├── .gitignore ├── LICENSE ├── README.md ├── VuforiaSampleSwift.xcodeproj └── project.pbxproj ├── VuforiaSampleSwift ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Background.fragsh ├── Background.vertsh ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── Localizable.strings ├── ViewController.swift ├── VuforiaManager │ ├── VuforiaEAGLView.h │ ├── VuforiaEAGLView.mm │ ├── VuforiaManager.h │ ├── VuforiaManager.mm │ ├── VuforiaObjects.h │ ├── VuforiaObjects.mm │ ├── VuforiaShaderUtils.h │ └── VuforiaShaderUtils.m └── VuforiaSampleSwift-Bridging-Header.h └── screenshot.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | #####=== Xcode ===##### 3 | 4 | .DS_Store 5 | 6 | build/ 7 | *.pbxuser 8 | !default.pbxuser 9 | *.mode1v3 10 | !default.mode1v3 11 | *.mode2v3 12 | !default.mode2v3 13 | *.perspectivev3 14 | !default.perspectivev3 15 | xcuserdata 16 | *.xccheckout 17 | *.moved-aside 18 | DerivedData 19 | *.xcuserstate 20 | 21 | vuforia-sdk-ios-*/ 22 | VuforiaAssets/ 23 | ImageTargets/ 24 | *.xcworkspace/ 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | MIT License 3 | 4 | Copyright (c) 2017 Yoshihiro Kato 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VuforiaSampleSwift 2 | 3 | Vuforia sample code with SceneKit using Swift. 4 | 5 | ## Requirement 6 | 7 | * Xcode 9.2 8 | * iOS 11.2 9 | * Vuforia SDK for iOS v7.5.20 10 | 11 | ## Setup 12 | 13 | * Download Vuforia SDK for iOS. 14 | [Vuforia SDK](https://developer.vuforia.com/downloads/sdk) 15 | * Put the SDK on your path as like bellow: 16 | `VuforiaSampleSwift/VuforiaSampleSwift/vuforia-sdk-ios-7.5.20` 17 | * Download Vuforiat Sample Targets. 18 | [Vuforiat Sample](https://developer.vuforia.com/downloads/samples) 19 | * Put your targets on your path as like bellow: 20 | `VuforiaSampleSwift/VuforiaSampleSwift/VuforiaAssets/ImageTargets` 21 | * If you needs to fix to links to these files and settings in project, fix it. 22 | If you failed to build, check `Header Search Paths` and `Libarary Search Paths` in Build Settings. 23 | * Set your `lincenseKey` and `dataSetFile` in ViewController.swift. 24 | 25 | 26 | ## Usage 27 | 28 | See ViewController.swift. 29 | 30 | ``` swift 31 | 32 | vuforiaManager = VuforiaManager(licenseKey: "your license key", dataSetFile: "your target xml file") 33 | if let manager = vuforiaManager { 34 | manager.delegate = self 35 | manager.eaglView.sceneSource = self 36 | manager.eaglView.delegate = self 37 | manager.eaglView.setupRenderer() 38 | self.view = manager.eaglView 39 | } 40 | 41 | vuforiaManager?.prepareWithOrientation(.Portrait) 42 | 43 | ... 44 | 45 | do { 46 | try vuforiaManager?.start() 47 | }catch let error { 48 | print("\(error)") 49 | } 50 | 51 | ``` 52 | 53 | ## ScreenShot 54 | 55 | ![screenshot](https://github.com/yshrkt/VuforiaSampleSwift/blob/master/screenshot.jpg) 56 | 57 | ## License 58 | 59 | MIT license. [See LICENSE](https://github.com/yshrkt/VuforiaSampleSwift/blob/master/LICENSE) for details. 60 | 61 | ## Thanks 62 | 63 | I am referring to the following page. 64 | 65 | * [Making Augmented Reality app easily with Scenekit + Vuforia (in English)](http://qiita.com/akira108/items/a743138fca532ee193fe) 66 | -------------------------------------------------------------------------------- /VuforiaSampleSwift.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 3703D8F821B6F88900C13C84 /* Vuforia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3703D8F721B6F88900C13C84 /* Vuforia.framework */; }; 11 | 3703D8F921B6F89100C13C84 /* Vuforia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3703D8F721B6F88900C13C84 /* Vuforia.framework */; }; 12 | 3703D8FA21B6F89100C13C84 /* Vuforia.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3703D8F721B6F88900C13C84 /* Vuforia.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 13 | 926096D41D4163B600510C24 /* SpriteKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 926096D31D4163B600510C24 /* SpriteKit.framework */; }; 14 | 9275279C1FC2CE5200CE7DCE /* Background.fragsh in Resources */ = {isa = PBXBuildFile; fileRef = 9275279A1FC2CE5200CE7DCE /* Background.fragsh */; }; 15 | 9275279D1FC2CE5200CE7DCE /* Background.vertsh in Resources */ = {isa = PBXBuildFile; fileRef = 9275279B1FC2CE5200CE7DCE /* Background.vertsh */; }; 16 | 927B76D71D27FDC600C4F5CC /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 927B76D41D27FDC600C4F5CC /* AVFoundation.framework */; }; 17 | 927B76D81D27FDC600C4F5CC /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 927B76D51D27FDC600C4F5CC /* CoreMotion.framework */; }; 18 | 927B76DB1D27FDE500C4F5CC /* SceneKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 927B76D91D27FDE500C4F5CC /* SceneKit.framework */; }; 19 | 927B76DC1D27FDE500C4F5CC /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 927B76DA1D27FDE500C4F5CC /* SystemConfiguration.framework */; }; 20 | 927B76DE1D27FE0500C4F5CC /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 927B76DD1D27FE0500C4F5CC /* CoreMedia.framework */; }; 21 | 927B76EA1D2806EF00C4F5CC /* VuforiaEAGLView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 927B76E51D2806EF00C4F5CC /* VuforiaEAGLView.mm */; }; 22 | 927B76EB1D2806EF00C4F5CC /* VuforiaManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = 927B76E71D2806EF00C4F5CC /* VuforiaManager.mm */; }; 23 | 927B76EC1D2806EF00C4F5CC /* VuforiaObjects.mm in Sources */ = {isa = PBXBuildFile; fileRef = 927B76E91D2806EF00C4F5CC /* VuforiaObjects.mm */; }; 24 | 927B76FD1D2816DB00C4F5CC /* VuforiaShaderUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 927B76FC1D2816DB00C4F5CC /* VuforiaShaderUtils.m */; }; 25 | 927B77081D2824AB00C4F5CC /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 927B77071D2824AB00C4F5CC /* OpenGLES.framework */; }; 26 | 927B77091D282DF100C4F5CC /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 927B76D31D27FDC600C4F5CC /* AudioToolbox.framework */; }; 27 | 927B770B1D282E0A00C4F5CC /* MediaPlayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 927B770A1D282E0A00C4F5CC /* MediaPlayer.framework */; }; 28 | 928C34301EAF69EB00BC07DE /* card_info.png in Resources */ = {isa = PBXBuildFile; fileRef = 928C34271EAF69EB00BC07DE /* card_info.png */; }; 29 | 928C34311EAF69EB00BC07DE /* reticle.png in Resources */ = {isa = PBXBuildFile; fileRef = 928C34281EAF69EB00BC07DE /* reticle.png */; }; 30 | 928C34321EAF69EB00BC07DE /* reticle@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 928C34291EAF69EB00BC07DE /* reticle@2x.png */; }; 31 | 928C34331EAF69EB00BC07DE /* reticle@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 928C342A1EAF69EB00BC07DE /* reticle@3x.png */; }; 32 | 928C34341EAF69EB00BC07DE /* VM.png in Resources */ = {isa = PBXBuildFile; fileRef = 928C342B1EAF69EB00BC07DE /* VM.png */; }; 33 | 928C34351EAF69EB00BC07DE /* VM_about.html in Resources */ = {isa = PBXBuildFile; fileRef = 928C342C1EAF69EB00BC07DE /* VM_about.html */; }; 34 | 928C34361EAF69EB00BC07DE /* Vuforia.dat in Resources */ = {isa = PBXBuildFile; fileRef = 928C342D1EAF69EB00BC07DE /* Vuforia.dat */; }; 35 | 928C34371EAF69EB00BC07DE /* Vuforia.xml in Resources */ = {isa = PBXBuildFile; fileRef = 928C342E1EAF69EB00BC07DE /* Vuforia.xml */; }; 36 | 928C34381EAF69EB00BC07DE /* vumark_texture.png in Resources */ = {isa = PBXBuildFile; fileRef = 928C342F1EAF69EB00BC07DE /* vumark_texture.png */; }; 37 | 92AA11091D27A5EB00E56CBE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92AA11081D27A5EB00E56CBE /* AppDelegate.swift */; }; 38 | 92AA110B1D27A5EB00E56CBE /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 92AA110A1D27A5EB00E56CBE /* ViewController.swift */; }; 39 | 92AA110E1D27A5EB00E56CBE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 92AA110C1D27A5EB00E56CBE /* Main.storyboard */; }; 40 | 92AA11101D27A5EB00E56CBE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 92AA110F1D27A5EB00E56CBE /* Assets.xcassets */; }; 41 | 92AA11131D27A5EB00E56CBE /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 92AA11111D27A5EB00E56CBE /* LaunchScreen.storyboard */; }; 42 | 92AA11851D27B96300E56CBE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 92AA11841D27B96300E56CBE /* Localizable.strings */; }; 43 | 92DCE9BB1E37CEA400E0DE1C /* IT.png in Resources */ = {isa = PBXBuildFile; fileRef = 92DCE9B51E37CEA400E0DE1C /* IT.png */; }; 44 | 92DCE9BC1E37CEA400E0DE1C /* IT_about.html in Resources */ = {isa = PBXBuildFile; fileRef = 92DCE9B61E37CEA400E0DE1C /* IT_about.html */; }; 45 | 92DCE9BD1E37CEA400E0DE1C /* StonesAndChips.dat in Resources */ = {isa = PBXBuildFile; fileRef = 92DCE9B71E37CEA400E0DE1C /* StonesAndChips.dat */; }; 46 | 92DCE9BE1E37CEA400E0DE1C /* StonesAndChips.xml in Resources */ = {isa = PBXBuildFile; fileRef = 92DCE9B81E37CEA400E0DE1C /* StonesAndChips.xml */; }; 47 | 92DCE9BF1E37CEA400E0DE1C /* Tarmac.dat in Resources */ = {isa = PBXBuildFile; fileRef = 92DCE9B91E37CEA400E0DE1C /* Tarmac.dat */; }; 48 | 92DCE9C01E37CEA400E0DE1C /* Tarmac.xml in Resources */ = {isa = PBXBuildFile; fileRef = 92DCE9BA1E37CEA400E0DE1C /* Tarmac.xml */; }; 49 | /* End PBXBuildFile section */ 50 | 51 | /* Begin PBXCopyFilesBuildPhase section */ 52 | 3703D8FB21B6F89200C13C84 /* Embed Frameworks */ = { 53 | isa = PBXCopyFilesBuildPhase; 54 | buildActionMask = 2147483647; 55 | dstPath = ""; 56 | dstSubfolderSpec = 10; 57 | files = ( 58 | 3703D8FA21B6F89100C13C84 /* Vuforia.framework in Embed Frameworks */, 59 | ); 60 | name = "Embed Frameworks"; 61 | runOnlyForDeploymentPostprocessing = 0; 62 | }; 63 | /* End PBXCopyFilesBuildPhase section */ 64 | 65 | /* Begin PBXFileReference section */ 66 | 3703D8F721B6F88900C13C84 /* Vuforia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Vuforia.framework; path = "VuforiaSampleSwift/vuforia-sdk-ios-7-5-20/build/Vuforia.framework"; sourceTree = ""; }; 67 | 926096D31D4163B600510C24 /* SpriteKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SpriteKit.framework; path = System/Library/Frameworks/SpriteKit.framework; sourceTree = SDKROOT; }; 68 | 9275279A1FC2CE5200CE7DCE /* Background.fragsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Background.fragsh; sourceTree = ""; }; 69 | 9275279B1FC2CE5200CE7DCE /* Background.vertsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Background.vertsh; sourceTree = ""; }; 70 | 927B76D31D27FDC600C4F5CC /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; 71 | 927B76D41D27FDC600C4F5CC /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; 72 | 927B76D51D27FDC600C4F5CC /* CoreMotion.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMotion.framework; path = System/Library/Frameworks/CoreMotion.framework; sourceTree = SDKROOT; }; 73 | 927B76D91D27FDE500C4F5CC /* SceneKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SceneKit.framework; path = System/Library/Frameworks/SceneKit.framework; sourceTree = SDKROOT; }; 74 | 927B76DA1D27FDE500C4F5CC /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; 75 | 927B76DD1D27FE0500C4F5CC /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; }; 76 | 927B76E41D2806EF00C4F5CC /* VuforiaEAGLView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VuforiaEAGLView.h; path = VuforiaManager/VuforiaEAGLView.h; sourceTree = ""; }; 77 | 927B76E51D2806EF00C4F5CC /* VuforiaEAGLView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = VuforiaEAGLView.mm; path = VuforiaManager/VuforiaEAGLView.mm; sourceTree = ""; }; 78 | 927B76E61D2806EF00C4F5CC /* VuforiaManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VuforiaManager.h; path = VuforiaManager/VuforiaManager.h; sourceTree = ""; }; 79 | 927B76E71D2806EF00C4F5CC /* VuforiaManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = VuforiaManager.mm; path = VuforiaManager/VuforiaManager.mm; sourceTree = ""; }; 80 | 927B76E81D2806EF00C4F5CC /* VuforiaObjects.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VuforiaObjects.h; path = VuforiaManager/VuforiaObjects.h; sourceTree = ""; }; 81 | 927B76E91D2806EF00C4F5CC /* VuforiaObjects.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = VuforiaObjects.mm; path = VuforiaManager/VuforiaObjects.mm; sourceTree = ""; }; 82 | 927B76FB1D2816DB00C4F5CC /* VuforiaShaderUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VuforiaShaderUtils.h; path = VuforiaManager/VuforiaShaderUtils.h; sourceTree = ""; }; 83 | 927B76FC1D2816DB00C4F5CC /* VuforiaShaderUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VuforiaShaderUtils.m; path = VuforiaManager/VuforiaShaderUtils.m; sourceTree = ""; }; 84 | 927B77071D2824AB00C4F5CC /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; 85 | 927B770A1D282E0A00C4F5CC /* MediaPlayer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaPlayer.framework; path = System/Library/Frameworks/MediaPlayer.framework; sourceTree = SDKROOT; }; 86 | 928C34271EAF69EB00BC07DE /* card_info.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = card_info.png; sourceTree = ""; }; 87 | 928C34281EAF69EB00BC07DE /* reticle.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = reticle.png; sourceTree = ""; }; 88 | 928C34291EAF69EB00BC07DE /* reticle@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "reticle@2x.png"; sourceTree = ""; }; 89 | 928C342A1EAF69EB00BC07DE /* reticle@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "reticle@3x.png"; sourceTree = ""; }; 90 | 928C342B1EAF69EB00BC07DE /* VM.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = VM.png; sourceTree = ""; }; 91 | 928C342C1EAF69EB00BC07DE /* VM_about.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = VM_about.html; sourceTree = ""; }; 92 | 928C342D1EAF69EB00BC07DE /* Vuforia.dat */ = {isa = PBXFileReference; lastKnownFileType = file; path = Vuforia.dat; sourceTree = ""; }; 93 | 928C342E1EAF69EB00BC07DE /* Vuforia.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = Vuforia.xml; sourceTree = ""; }; 94 | 928C342F1EAF69EB00BC07DE /* vumark_texture.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = vumark_texture.png; sourceTree = ""; }; 95 | 92AA11051D27A5EB00E56CBE /* VuforiaSampleSwift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = VuforiaSampleSwift.app; sourceTree = BUILT_PRODUCTS_DIR; }; 96 | 92AA11081D27A5EB00E56CBE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 97 | 92AA110A1D27A5EB00E56CBE /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 98 | 92AA110D1D27A5EB00E56CBE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 99 | 92AA110F1D27A5EB00E56CBE /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 100 | 92AA11121D27A5EB00E56CBE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 101 | 92AA11141D27A5EB00E56CBE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 102 | 92AA11801D27A6CD00E56CBE /* VuforiaSampleSwift-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "VuforiaSampleSwift-Bridging-Header.h"; sourceTree = ""; }; 103 | 92AA11841D27B96300E56CBE /* Localizable.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = Localizable.strings; sourceTree = ""; }; 104 | 92DCE9B51E37CEA400E0DE1C /* IT.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = IT.png; sourceTree = ""; }; 105 | 92DCE9B61E37CEA400E0DE1C /* IT_about.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = IT_about.html; sourceTree = ""; }; 106 | 92DCE9B71E37CEA400E0DE1C /* StonesAndChips.dat */ = {isa = PBXFileReference; lastKnownFileType = file; path = StonesAndChips.dat; sourceTree = ""; }; 107 | 92DCE9B81E37CEA400E0DE1C /* StonesAndChips.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = StonesAndChips.xml; sourceTree = ""; }; 108 | 92DCE9B91E37CEA400E0DE1C /* Tarmac.dat */ = {isa = PBXFileReference; lastKnownFileType = file; path = Tarmac.dat; sourceTree = ""; }; 109 | 92DCE9BA1E37CEA400E0DE1C /* Tarmac.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = Tarmac.xml; sourceTree = ""; }; 110 | /* End PBXFileReference section */ 111 | 112 | /* Begin PBXFrameworksBuildPhase section */ 113 | 92AA11021D27A5EB00E56CBE /* Frameworks */ = { 114 | isa = PBXFrameworksBuildPhase; 115 | buildActionMask = 2147483647; 116 | files = ( 117 | 926096D41D4163B600510C24 /* SpriteKit.framework in Frameworks */, 118 | 3703D8F921B6F89100C13C84 /* Vuforia.framework in Frameworks */, 119 | 927B770B1D282E0A00C4F5CC /* MediaPlayer.framework in Frameworks */, 120 | 927B77091D282DF100C4F5CC /* AudioToolbox.framework in Frameworks */, 121 | 927B77081D2824AB00C4F5CC /* OpenGLES.framework in Frameworks */, 122 | 927B76DE1D27FE0500C4F5CC /* CoreMedia.framework in Frameworks */, 123 | 927B76DB1D27FDE500C4F5CC /* SceneKit.framework in Frameworks */, 124 | 927B76DC1D27FDE500C4F5CC /* SystemConfiguration.framework in Frameworks */, 125 | 927B76D71D27FDC600C4F5CC /* AVFoundation.framework in Frameworks */, 126 | 927B76D81D27FDC600C4F5CC /* CoreMotion.framework in Frameworks */, 127 | 3703D8F821B6F88900C13C84 /* Vuforia.framework in Frameworks */, 128 | ); 129 | runOnlyForDeploymentPostprocessing = 0; 130 | }; 131 | /* End PBXFrameworksBuildPhase section */ 132 | 133 | /* Begin PBXGroup section */ 134 | 927527971FC2BE0400CE7DCE /* Frameworks */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | ); 138 | name = Frameworks; 139 | sourceTree = ""; 140 | }; 141 | 927527991FC2CE4100CE7DCE /* shaders */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | 9275279A1FC2CE5200CE7DCE /* Background.fragsh */, 145 | 9275279B1FC2CE5200CE7DCE /* Background.vertsh */, 146 | ); 147 | name = shaders; 148 | sourceTree = ""; 149 | }; 150 | 927B76DF1D27FE5900C4F5CC /* Frameworks */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | 3703D8F721B6F88900C13C84 /* Vuforia.framework */, 154 | 926096D31D4163B600510C24 /* SpriteKit.framework */, 155 | 927B770A1D282E0A00C4F5CC /* MediaPlayer.framework */, 156 | 927B77071D2824AB00C4F5CC /* OpenGLES.framework */, 157 | 927B76DD1D27FE0500C4F5CC /* CoreMedia.framework */, 158 | 927B76D91D27FDE500C4F5CC /* SceneKit.framework */, 159 | 927B76DA1D27FDE500C4F5CC /* SystemConfiguration.framework */, 160 | 927B76D31D27FDC600C4F5CC /* AudioToolbox.framework */, 161 | 927B76D41D27FDC600C4F5CC /* AVFoundation.framework */, 162 | 927B76D51D27FDC600C4F5CC /* CoreMotion.framework */, 163 | ); 164 | name = Frameworks; 165 | path = ..; 166 | sourceTree = ""; 167 | }; 168 | 927B76E31D27FF2300C4F5CC /* VuforiaManager */ = { 169 | isa = PBXGroup; 170 | children = ( 171 | 927527991FC2CE4100CE7DCE /* shaders */, 172 | 927B76E41D2806EF00C4F5CC /* VuforiaEAGLView.h */, 173 | 927B76E51D2806EF00C4F5CC /* VuforiaEAGLView.mm */, 174 | 927B76FB1D2816DB00C4F5CC /* VuforiaShaderUtils.h */, 175 | 927B76FC1D2816DB00C4F5CC /* VuforiaShaderUtils.m */, 176 | 927B76E61D2806EF00C4F5CC /* VuforiaManager.h */, 177 | 927B76E71D2806EF00C4F5CC /* VuforiaManager.mm */, 178 | 927B76E81D2806EF00C4F5CC /* VuforiaObjects.h */, 179 | 927B76E91D2806EF00C4F5CC /* VuforiaObjects.mm */, 180 | ); 181 | name = VuforiaManager; 182 | sourceTree = ""; 183 | }; 184 | 927B76ED1D28070D00C4F5CC /* VuforiaAssets */ = { 185 | isa = PBXGroup; 186 | children = ( 187 | 928C34261EAF69EB00BC07DE /* VuMark */, 188 | 92DCE9B41E37CEA400E0DE1C /* ImageTargets */, 189 | ); 190 | path = VuforiaAssets; 191 | sourceTree = ""; 192 | }; 193 | 928C34261EAF69EB00BC07DE /* VuMark */ = { 194 | isa = PBXGroup; 195 | children = ( 196 | 928C34271EAF69EB00BC07DE /* card_info.png */, 197 | 928C34281EAF69EB00BC07DE /* reticle.png */, 198 | 928C34291EAF69EB00BC07DE /* reticle@2x.png */, 199 | 928C342A1EAF69EB00BC07DE /* reticle@3x.png */, 200 | 928C342B1EAF69EB00BC07DE /* VM.png */, 201 | 928C342C1EAF69EB00BC07DE /* VM_about.html */, 202 | 928C342D1EAF69EB00BC07DE /* Vuforia.dat */, 203 | 928C342E1EAF69EB00BC07DE /* Vuforia.xml */, 204 | 928C342F1EAF69EB00BC07DE /* vumark_texture.png */, 205 | ); 206 | path = VuMark; 207 | sourceTree = ""; 208 | }; 209 | 92AA10FC1D27A5EB00E56CBE = { 210 | isa = PBXGroup; 211 | children = ( 212 | 92AA11071D27A5EB00E56CBE /* VuforiaSampleSwift */, 213 | 92AA11061D27A5EB00E56CBE /* Products */, 214 | 927527971FC2BE0400CE7DCE /* Frameworks */, 215 | ); 216 | sourceTree = ""; 217 | }; 218 | 92AA11061D27A5EB00E56CBE /* Products */ = { 219 | isa = PBXGroup; 220 | children = ( 221 | 92AA11051D27A5EB00E56CBE /* VuforiaSampleSwift.app */, 222 | ); 223 | name = Products; 224 | sourceTree = ""; 225 | }; 226 | 92AA11071D27A5EB00E56CBE /* VuforiaSampleSwift */ = { 227 | isa = PBXGroup; 228 | children = ( 229 | 92AA11801D27A6CD00E56CBE /* VuforiaSampleSwift-Bridging-Header.h */, 230 | 927B76E31D27FF2300C4F5CC /* VuforiaManager */, 231 | 927B76ED1D28070D00C4F5CC /* VuforiaAssets */, 232 | 92AA11081D27A5EB00E56CBE /* AppDelegate.swift */, 233 | 92AA110A1D27A5EB00E56CBE /* ViewController.swift */, 234 | 92AA110C1D27A5EB00E56CBE /* Main.storyboard */, 235 | 92AA110F1D27A5EB00E56CBE /* Assets.xcassets */, 236 | 92AA11111D27A5EB00E56CBE /* LaunchScreen.storyboard */, 237 | 92AA11141D27A5EB00E56CBE /* Info.plist */, 238 | 92AA11841D27B96300E56CBE /* Localizable.strings */, 239 | 927B76DF1D27FE5900C4F5CC /* Frameworks */, 240 | ); 241 | path = VuforiaSampleSwift; 242 | sourceTree = ""; 243 | }; 244 | 92DCE9B41E37CEA400E0DE1C /* ImageTargets */ = { 245 | isa = PBXGroup; 246 | children = ( 247 | 92DCE9B51E37CEA400E0DE1C /* IT.png */, 248 | 92DCE9B61E37CEA400E0DE1C /* IT_about.html */, 249 | 92DCE9B71E37CEA400E0DE1C /* StonesAndChips.dat */, 250 | 92DCE9B81E37CEA400E0DE1C /* StonesAndChips.xml */, 251 | 92DCE9B91E37CEA400E0DE1C /* Tarmac.dat */, 252 | 92DCE9BA1E37CEA400E0DE1C /* Tarmac.xml */, 253 | ); 254 | path = ImageTargets; 255 | sourceTree = ""; 256 | }; 257 | /* End PBXGroup section */ 258 | 259 | /* Begin PBXNativeTarget section */ 260 | 92AA11041D27A5EB00E56CBE /* VuforiaSampleSwift */ = { 261 | isa = PBXNativeTarget; 262 | buildConfigurationList = 92AA11171D27A5EB00E56CBE /* Build configuration list for PBXNativeTarget "VuforiaSampleSwift" */; 263 | buildPhases = ( 264 | 92AA11011D27A5EB00E56CBE /* Sources */, 265 | 92AA11021D27A5EB00E56CBE /* Frameworks */, 266 | 92AA11031D27A5EB00E56CBE /* Resources */, 267 | 3703D8FB21B6F89200C13C84 /* Embed Frameworks */, 268 | ); 269 | buildRules = ( 270 | ); 271 | dependencies = ( 272 | ); 273 | name = VuforiaSampleSwift; 274 | productName = VuforiaSampleSwift; 275 | productReference = 92AA11051D27A5EB00E56CBE /* VuforiaSampleSwift.app */; 276 | productType = "com.apple.product-type.application"; 277 | }; 278 | /* End PBXNativeTarget section */ 279 | 280 | /* Begin PBXProject section */ 281 | 92AA10FD1D27A5EB00E56CBE /* Project object */ = { 282 | isa = PBXProject; 283 | attributes = { 284 | LastSwiftUpdateCheck = 0730; 285 | LastUpgradeCheck = 1010; 286 | ORGANIZATIONNAME = "Yoshihiro Kato"; 287 | TargetAttributes = { 288 | 92AA11041D27A5EB00E56CBE = { 289 | CreatedOnToolsVersion = 7.3.1; 290 | LastSwiftMigration = 0800; 291 | ProvisioningStyle = Automatic; 292 | }; 293 | }; 294 | }; 295 | buildConfigurationList = 92AA11001D27A5EB00E56CBE /* Build configuration list for PBXProject "VuforiaSampleSwift" */; 296 | compatibilityVersion = "Xcode 3.2"; 297 | developmentRegion = English; 298 | hasScannedForEncodings = 0; 299 | knownRegions = ( 300 | en, 301 | Base, 302 | ); 303 | mainGroup = 92AA10FC1D27A5EB00E56CBE; 304 | productRefGroup = 92AA11061D27A5EB00E56CBE /* Products */; 305 | projectDirPath = ""; 306 | projectRoot = ""; 307 | targets = ( 308 | 92AA11041D27A5EB00E56CBE /* VuforiaSampleSwift */, 309 | ); 310 | }; 311 | /* End PBXProject section */ 312 | 313 | /* Begin PBXResourcesBuildPhase section */ 314 | 92AA11031D27A5EB00E56CBE /* Resources */ = { 315 | isa = PBXResourcesBuildPhase; 316 | buildActionMask = 2147483647; 317 | files = ( 318 | 92DCE9BF1E37CEA400E0DE1C /* Tarmac.dat in Resources */, 319 | 928C34361EAF69EB00BC07DE /* Vuforia.dat in Resources */, 320 | 9275279C1FC2CE5200CE7DCE /* Background.fragsh in Resources */, 321 | 9275279D1FC2CE5200CE7DCE /* Background.vertsh in Resources */, 322 | 92AA11131D27A5EB00E56CBE /* LaunchScreen.storyboard in Resources */, 323 | 928C34321EAF69EB00BC07DE /* reticle@2x.png in Resources */, 324 | 92AA11101D27A5EB00E56CBE /* Assets.xcassets in Resources */, 325 | 92DCE9BD1E37CEA400E0DE1C /* StonesAndChips.dat in Resources */, 326 | 92AA11851D27B96300E56CBE /* Localizable.strings in Resources */, 327 | 928C34331EAF69EB00BC07DE /* reticle@3x.png in Resources */, 328 | 928C34381EAF69EB00BC07DE /* vumark_texture.png in Resources */, 329 | 92DCE9C01E37CEA400E0DE1C /* Tarmac.xml in Resources */, 330 | 928C34351EAF69EB00BC07DE /* VM_about.html in Resources */, 331 | 928C34371EAF69EB00BC07DE /* Vuforia.xml in Resources */, 332 | 928C34301EAF69EB00BC07DE /* card_info.png in Resources */, 333 | 92DCE9BE1E37CEA400E0DE1C /* StonesAndChips.xml in Resources */, 334 | 92DCE9BB1E37CEA400E0DE1C /* IT.png in Resources */, 335 | 928C34311EAF69EB00BC07DE /* reticle.png in Resources */, 336 | 92AA110E1D27A5EB00E56CBE /* Main.storyboard in Resources */, 337 | 928C34341EAF69EB00BC07DE /* VM.png in Resources */, 338 | 92DCE9BC1E37CEA400E0DE1C /* IT_about.html in Resources */, 339 | ); 340 | runOnlyForDeploymentPostprocessing = 0; 341 | }; 342 | /* End PBXResourcesBuildPhase section */ 343 | 344 | /* Begin PBXSourcesBuildPhase section */ 345 | 92AA11011D27A5EB00E56CBE /* Sources */ = { 346 | isa = PBXSourcesBuildPhase; 347 | buildActionMask = 2147483647; 348 | files = ( 349 | 927B76EA1D2806EF00C4F5CC /* VuforiaEAGLView.mm in Sources */, 350 | 927B76FD1D2816DB00C4F5CC /* VuforiaShaderUtils.m in Sources */, 351 | 92AA110B1D27A5EB00E56CBE /* ViewController.swift in Sources */, 352 | 92AA11091D27A5EB00E56CBE /* AppDelegate.swift in Sources */, 353 | 927B76EB1D2806EF00C4F5CC /* VuforiaManager.mm in Sources */, 354 | 927B76EC1D2806EF00C4F5CC /* VuforiaObjects.mm in Sources */, 355 | ); 356 | runOnlyForDeploymentPostprocessing = 0; 357 | }; 358 | /* End PBXSourcesBuildPhase section */ 359 | 360 | /* Begin PBXVariantGroup section */ 361 | 92AA110C1D27A5EB00E56CBE /* Main.storyboard */ = { 362 | isa = PBXVariantGroup; 363 | children = ( 364 | 92AA110D1D27A5EB00E56CBE /* Base */, 365 | ); 366 | name = Main.storyboard; 367 | sourceTree = ""; 368 | }; 369 | 92AA11111D27A5EB00E56CBE /* LaunchScreen.storyboard */ = { 370 | isa = PBXVariantGroup; 371 | children = ( 372 | 92AA11121D27A5EB00E56CBE /* Base */, 373 | ); 374 | name = LaunchScreen.storyboard; 375 | sourceTree = ""; 376 | }; 377 | /* End PBXVariantGroup section */ 378 | 379 | /* Begin XCBuildConfiguration section */ 380 | 92AA11151D27A5EB00E56CBE /* Debug */ = { 381 | isa = XCBuildConfiguration; 382 | buildSettings = { 383 | ALWAYS_SEARCH_USER_PATHS = NO; 384 | CLANG_ANALYZER_NONNULL = YES; 385 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 386 | CLANG_CXX_LIBRARY = "libc++"; 387 | CLANG_ENABLE_MODULES = YES; 388 | CLANG_ENABLE_OBJC_ARC = YES; 389 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 390 | CLANG_WARN_BOOL_CONVERSION = YES; 391 | CLANG_WARN_COMMA = YES; 392 | CLANG_WARN_CONSTANT_CONVERSION = YES; 393 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 394 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 395 | CLANG_WARN_EMPTY_BODY = YES; 396 | CLANG_WARN_ENUM_CONVERSION = YES; 397 | CLANG_WARN_INFINITE_RECURSION = YES; 398 | CLANG_WARN_INT_CONVERSION = YES; 399 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 400 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 401 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 402 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 403 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 404 | CLANG_WARN_STRICT_PROTOTYPES = YES; 405 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 406 | CLANG_WARN_UNREACHABLE_CODE = YES; 407 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 408 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 409 | COPY_PHASE_STRIP = NO; 410 | DEBUG_INFORMATION_FORMAT = dwarf; 411 | ENABLE_BITCODE = NO; 412 | ENABLE_STRICT_OBJC_MSGSEND = YES; 413 | ENABLE_TESTABILITY = YES; 414 | GCC_C_LANGUAGE_STANDARD = gnu99; 415 | GCC_DYNAMIC_NO_PIC = NO; 416 | GCC_NO_COMMON_BLOCKS = YES; 417 | GCC_OPTIMIZATION_LEVEL = 0; 418 | GCC_PREPROCESSOR_DEFINITIONS = ( 419 | "DEBUG=1", 420 | "$(inherited)", 421 | ); 422 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 423 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 424 | GCC_WARN_UNDECLARED_SELECTOR = YES; 425 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 426 | GCC_WARN_UNUSED_FUNCTION = YES; 427 | GCC_WARN_UNUSED_VARIABLE = YES; 428 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 429 | MTL_ENABLE_DEBUG_INFO = YES; 430 | ONLY_ACTIVE_ARCH = YES; 431 | SDKROOT = iphoneos; 432 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 433 | }; 434 | name = Debug; 435 | }; 436 | 92AA11161D27A5EB00E56CBE /* Release */ = { 437 | isa = XCBuildConfiguration; 438 | buildSettings = { 439 | ALWAYS_SEARCH_USER_PATHS = NO; 440 | CLANG_ANALYZER_NONNULL = YES; 441 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 442 | CLANG_CXX_LIBRARY = "libc++"; 443 | CLANG_ENABLE_MODULES = YES; 444 | CLANG_ENABLE_OBJC_ARC = YES; 445 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 446 | CLANG_WARN_BOOL_CONVERSION = YES; 447 | CLANG_WARN_COMMA = YES; 448 | CLANG_WARN_CONSTANT_CONVERSION = YES; 449 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 450 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 451 | CLANG_WARN_EMPTY_BODY = YES; 452 | CLANG_WARN_ENUM_CONVERSION = YES; 453 | CLANG_WARN_INFINITE_RECURSION = YES; 454 | CLANG_WARN_INT_CONVERSION = YES; 455 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 456 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 457 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 458 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 459 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 460 | CLANG_WARN_STRICT_PROTOTYPES = YES; 461 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 462 | CLANG_WARN_UNREACHABLE_CODE = YES; 463 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 464 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 465 | COPY_PHASE_STRIP = NO; 466 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 467 | ENABLE_BITCODE = NO; 468 | ENABLE_NS_ASSERTIONS = NO; 469 | ENABLE_STRICT_OBJC_MSGSEND = YES; 470 | GCC_C_LANGUAGE_STANDARD = gnu99; 471 | GCC_NO_COMMON_BLOCKS = YES; 472 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 473 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 474 | GCC_WARN_UNDECLARED_SELECTOR = YES; 475 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 476 | GCC_WARN_UNUSED_FUNCTION = YES; 477 | GCC_WARN_UNUSED_VARIABLE = YES; 478 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 479 | MTL_ENABLE_DEBUG_INFO = NO; 480 | SDKROOT = iphoneos; 481 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 482 | VALIDATE_PRODUCT = YES; 483 | }; 484 | name = Release; 485 | }; 486 | 92AA11181D27A5EB00E56CBE /* Debug */ = { 487 | isa = XCBuildConfiguration; 488 | buildSettings = { 489 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 490 | CLANG_ENABLE_MODULES = YES; 491 | CODE_SIGN_IDENTITY = "iPhone Developer"; 492 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 493 | CODE_SIGN_STYLE = Automatic; 494 | DEVELOPMENT_TEAM = ""; 495 | ENABLE_BITCODE = NO; 496 | FRAMEWORK_SEARCH_PATHS = ( 497 | "$(inherited)", 498 | "$(PROJECT_DIR)/VuforiaSampleSwift/vuforia-sdk-ios-7-5-20/build", 499 | ); 500 | HEADER_SEARCH_PATHS = "\"$(SRCROOT)/VuforiaSampleSwift/vuforia-sdk-ios-7-0-50/build/include\""; 501 | INFOPLIST_FILE = VuforiaSampleSwift/Info.plist; 502 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 503 | LIBRARY_SEARCH_PATHS = ( 504 | "$(inherited)", 505 | "$(PROJECT_DIR)/VuforiaSampleSwift/vuforia-sdk-ios-7-0-50/build/lib/arm", 506 | ); 507 | PRODUCT_BUNDLE_IDENTIFIER = "com.sputnik-apps.VuforiaSampleSwift"; 508 | PRODUCT_NAME = VuforiaSampleSwift; 509 | PROVISIONING_PROFILE_SPECIFIER = ""; 510 | SWIFT_OBJC_BRIDGING_HEADER = "VuforiaSampleSwift/VuforiaSampleSwift-Bridging-Header.h"; 511 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 512 | SWIFT_VERSION = 3.0; 513 | TARGETED_DEVICE_FAMILY = "1,2"; 514 | USER_HEADER_SEARCH_PATHS = ""; 515 | }; 516 | name = Debug; 517 | }; 518 | 92AA11191D27A5EB00E56CBE /* Release */ = { 519 | isa = XCBuildConfiguration; 520 | buildSettings = { 521 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 522 | CLANG_ENABLE_MODULES = YES; 523 | CODE_SIGN_IDENTITY = "iPhone Developer"; 524 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 525 | CODE_SIGN_STYLE = Automatic; 526 | DEVELOPMENT_TEAM = ""; 527 | ENABLE_BITCODE = NO; 528 | FRAMEWORK_SEARCH_PATHS = ( 529 | "$(inherited)", 530 | "$(PROJECT_DIR)/VuforiaSampleSwift/vuforia-sdk-ios-7-5-20/build", 531 | ); 532 | HEADER_SEARCH_PATHS = "\"$(SRCROOT)/VuforiaSampleSwift/vuforia-sdk-ios-7-0-50/build/include\""; 533 | INFOPLIST_FILE = VuforiaSampleSwift/Info.plist; 534 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 535 | LIBRARY_SEARCH_PATHS = ( 536 | "$(inherited)", 537 | "$(PROJECT_DIR)/VuforiaSampleSwift/vuforia-sdk-ios-7-0-50/build/lib/arm", 538 | ); 539 | PRODUCT_BUNDLE_IDENTIFIER = "com.sputnik-apps.VuforiaSampleSwift"; 540 | PRODUCT_NAME = VuforiaSampleSwift; 541 | PROVISIONING_PROFILE_SPECIFIER = ""; 542 | SWIFT_OBJC_BRIDGING_HEADER = "VuforiaSampleSwift/VuforiaSampleSwift-Bridging-Header.h"; 543 | SWIFT_VERSION = 3.0; 544 | TARGETED_DEVICE_FAMILY = "1,2"; 545 | USER_HEADER_SEARCH_PATHS = ""; 546 | }; 547 | name = Release; 548 | }; 549 | /* End XCBuildConfiguration section */ 550 | 551 | /* Begin XCConfigurationList section */ 552 | 92AA11001D27A5EB00E56CBE /* Build configuration list for PBXProject "VuforiaSampleSwift" */ = { 553 | isa = XCConfigurationList; 554 | buildConfigurations = ( 555 | 92AA11151D27A5EB00E56CBE /* Debug */, 556 | 92AA11161D27A5EB00E56CBE /* Release */, 557 | ); 558 | defaultConfigurationIsVisible = 0; 559 | defaultConfigurationName = Release; 560 | }; 561 | 92AA11171D27A5EB00E56CBE /* Build configuration list for PBXNativeTarget "VuforiaSampleSwift" */ = { 562 | isa = XCConfigurationList; 563 | buildConfigurations = ( 564 | 92AA11181D27A5EB00E56CBE /* Debug */, 565 | 92AA11191D27A5EB00E56CBE /* Release */, 566 | ); 567 | defaultConfigurationIsVisible = 0; 568 | defaultConfigurationName = Release; 569 | }; 570 | /* End XCConfigurationList section */ 571 | }; 572 | rootObject = 92AA10FD1D27A5EB00E56CBE /* Project object */; 573 | } 574 | -------------------------------------------------------------------------------- /VuforiaSampleSwift/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // VuforiaSample 4 | // 5 | // Created by Yoshihiro Kato on 2016/07/02. 6 | // Copyright © 2016年 Yoshihiro Kato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /VuforiaSampleSwift/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | } 43 | ], 44 | "info" : { 45 | "version" : 1, 46 | "author" : "xcode" 47 | } 48 | } -------------------------------------------------------------------------------- /VuforiaSampleSwift/Background.fragsh: -------------------------------------------------------------------------------- 1 | /*=============================================================================== 2 | Copyright (c) 2016 PTC Inc. All Rights Reserved. 3 | 4 | Copyright (c) 2012-2015 Qualcomm Connected Experiences, Inc. All Rights Reserved. 5 | 6 | Vuforia is a trademark of PTC Inc., registered in the United States and other 7 | countries. 8 | ===============================================================================*/ 9 | 10 | precision mediump float; 11 | varying vec2 texCoord; 12 | uniform sampler2D texSampler2D; 13 | 14 | void main () 15 | { 16 | gl_FragColor = texture2D(texSampler2D, texCoord); 17 | } 18 | -------------------------------------------------------------------------------- /VuforiaSampleSwift/Background.vertsh: -------------------------------------------------------------------------------- 1 | /*=============================================================================== 2 | Copyright (c) 2016 PTC Inc. All Rights Reserved. 3 | 4 | Copyright (c) 2012-2015 Qualcomm Connected Experiences, Inc. All Rights Reserved. 5 | 6 | Vuforia is a trademark of PTC Inc., registered in the United States and other 7 | countries. 8 | ===============================================================================*/ 9 | 10 | attribute vec4 vertexPosition; 11 | attribute vec2 vertexTexCoord; 12 | uniform mat4 projectionMatrix; 13 | varying vec2 texCoord; 14 | 15 | void main() 16 | { 17 | gl_Position = projectionMatrix * vertexPosition; 18 | texCoord = vertexTexCoord; 19 | } -------------------------------------------------------------------------------- /VuforiaSampleSwift/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /VuforiaSampleSwift/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /VuforiaSampleSwift/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | NSCameraUsageDescription 26 | 27 | PrefersOpenGL 28 | 29 | UILaunchStoryboardName 30 | LaunchScreen 31 | UIMainStoryboardFile 32 | Main 33 | UIRequiredDeviceCapabilities 34 | 35 | armv7 36 | opengles-2 37 | auto-focus-camera 38 | 39 | UISupportedInterfaceOrientations 40 | 41 | UIInterfaceOrientationPortrait 42 | 43 | UISupportedInterfaceOrientations~ipad 44 | 45 | UIInterfaceOrientationPortrait 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /VuforiaSampleSwift/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | VuforiaSampleSwift 4 | 5 | Created by Yoshihiro Kato on 2016/07/02. 6 | Copyright © 2016年 Yoshihiro Kato. All rights reserved. 7 | */ 8 | 9 | "VUFORIA_ERROR_NO_NETWORK_TRANSIENT" = "Unable to contact server. Please try again later."; 10 | "VUFORIA_ERROR_NO_NETWORK_PERMANENT" = "No network available. Please make sure you are connected to the Internet."; 11 | "VUFORIA_ERROR_INVALID_KEY" = "Invalid Key used. Please make sure you are using a valid Vuforia App Key."; 12 | "VUFORIA_ERROR_CANCELED_KEY" = "This app license key has been canceled and may no longer be used. Please get a new license key."; 13 | "VUFORIA_ERROR_MISSING_KEY" = "Vuforia App key is missing. Please get a valid key, by logging into your account at developer.vuforia.com and creating a new project."; 14 | "VUFORIA_ERROR_PRODUCT_TYPE_MISMATCH" = "Vuforia App key is not valid for this product. Please get a valid key, by logging into your account at developer.vuforia.com and choosing the right product type during project creation."; 15 | "VUFORIA_ERROR_UNKNOWN" = "Initialization error"; 16 | -------------------------------------------------------------------------------- /VuforiaSampleSwift/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // VuforiaSample 4 | // 5 | // Created by Yoshihiro Kato on 2016/07/02. 6 | // Copyright © 2016年 Yoshihiro Kato. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | let vuforiaLicenseKey = "Your License Key" 14 | let vuforiaDataSetFile = "Target XML File" 15 | 16 | var vuforiaManager: VuforiaManager? = nil 17 | 18 | let boxMaterial = SCNMaterial() 19 | fileprivate var lastSceneName: String? = nil 20 | 21 | deinit { 22 | NotificationCenter.default.removeObserver(self) 23 | } 24 | 25 | override func viewDidLoad() { 26 | super.viewDidLoad() 27 | 28 | prepare() 29 | } 30 | 31 | override func didReceiveMemoryWarning() { 32 | super.didReceiveMemoryWarning() 33 | // Dispose of any resources that can be recreated. 34 | } 35 | 36 | override func viewWillAppear(_ animated: Bool) { 37 | super.viewWillAppear(animated) 38 | } 39 | 40 | override func viewWillDisappear(_ animated: Bool) { 41 | super.viewWillDisappear(animated) 42 | 43 | do { 44 | try vuforiaManager?.stop() 45 | }catch let error { 46 | print("\(error)") 47 | } 48 | } 49 | } 50 | 51 | private extension ViewController { 52 | func prepare() { 53 | vuforiaManager = VuforiaManager(licenseKey: vuforiaLicenseKey, dataSetFile: vuforiaDataSetFile) 54 | if let manager = vuforiaManager { 55 | manager.delegate = self 56 | manager.eaglView.sceneSource = self 57 | manager.eaglView.delegate = self 58 | manager.eaglView.setupRenderer() 59 | self.view = manager.eaglView 60 | } 61 | 62 | let notificationCenter = NotificationCenter.default 63 | notificationCenter.addObserver(self, selector: #selector(didRecieveWillResignActiveNotification), 64 | name: NSNotification.Name.UIApplicationWillResignActive, object: nil) 65 | 66 | notificationCenter.addObserver(self, selector: #selector(didRecieveDidBecomeActiveNotification), 67 | name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil) 68 | 69 | vuforiaManager?.prepare(with: .portrait) 70 | } 71 | 72 | func pause() { 73 | do { 74 | try vuforiaManager?.pause() 75 | }catch let error { 76 | print("\(error)") 77 | } 78 | } 79 | 80 | func resume() { 81 | do { 82 | try vuforiaManager?.resume() 83 | }catch let error { 84 | print("\(error)") 85 | } 86 | } 87 | } 88 | 89 | extension ViewController { 90 | func didRecieveWillResignActiveNotification(_ notification: Notification) { 91 | pause() 92 | } 93 | 94 | func didRecieveDidBecomeActiveNotification(_ notification: Notification) { 95 | resume() 96 | } 97 | } 98 | 99 | extension ViewController: VuforiaManagerDelegate { 100 | func vuforiaManagerDidFinishPreparing(_ manager: VuforiaManager!) { 101 | print("did finish preparing\n") 102 | 103 | do { 104 | try vuforiaManager?.start() 105 | vuforiaManager?.setContinuousAutofocusEnabled(true) 106 | }catch let error { 107 | print("\(error)") 108 | } 109 | } 110 | 111 | func vuforiaManager(_ manager: VuforiaManager!, didFailToPreparingWithError error: Error!) { 112 | print("did faid to preparing \(error)\n") 113 | } 114 | 115 | func vuforiaManager(_ manager: VuforiaManager!, didUpdateWith state: VuforiaState!) { 116 | for index in 0 ..< state.numberOfTrackableResults { 117 | let result = state.trackableResult(at: index) 118 | let trackerableName = result?.trackable.name 119 | //print("\(trackerableName)") 120 | if trackerableName == "stones" { 121 | boxMaterial.diffuse.contents = UIColor.red 122 | 123 | if lastSceneName != "stones" { 124 | manager.eaglView.setNeedsChangeSceneWithUserInfo(["scene" : "stones"]) 125 | lastSceneName = "stones" 126 | } 127 | }else { 128 | boxMaterial.diffuse.contents = UIColor.blue 129 | 130 | if lastSceneName != "chips" { 131 | manager.eaglView.setNeedsChangeSceneWithUserInfo(["scene" : "chips"]) 132 | lastSceneName = "chips" 133 | } 134 | } 135 | 136 | } 137 | } 138 | } 139 | 140 | extension ViewController: VuforiaEAGLViewSceneSource, VuforiaEAGLViewDelegate { 141 | 142 | func scene(for view: VuforiaEAGLView!, userInfo: [String : Any]?) -> SCNScene! { 143 | guard let userInfo = userInfo else { 144 | print("default scene") 145 | return createStonesScene(with: view) 146 | } 147 | 148 | if let sceneName = userInfo["scene"] as? String , sceneName == "stones" { 149 | print("stones scene") 150 | return createStonesScene(with: view) 151 | }else { 152 | print("chips scene") 153 | return createChipsScene(with: view) 154 | } 155 | 156 | } 157 | 158 | fileprivate func createStonesScene(with view: VuforiaEAGLView) -> SCNScene { 159 | let scene = SCNScene() 160 | 161 | boxMaterial.diffuse.contents = UIColor.lightGray 162 | 163 | let lightNode = SCNNode() 164 | lightNode.light = SCNLight() 165 | lightNode.light?.type = .omni 166 | lightNode.light?.color = UIColor.lightGray 167 | lightNode.position = SCNVector3(x:0, y:10, z:10) 168 | scene.rootNode.addChildNode(lightNode) 169 | 170 | let ambientLightNode = SCNNode() 171 | ambientLightNode.light = SCNLight() 172 | ambientLightNode.light?.type = .ambient 173 | ambientLightNode.light?.color = UIColor.darkGray 174 | scene.rootNode.addChildNode(ambientLightNode) 175 | 176 | let planeNode = SCNNode() 177 | planeNode.name = "plane" 178 | planeNode.geometry = SCNPlane(width: 247.0*view.objectScale, height: 173.0*view.objectScale) 179 | planeNode.position = SCNVector3Make(0, 0, -1) 180 | let planeMaterial = SCNMaterial() 181 | planeMaterial.diffuse.contents = UIColor.green 182 | planeMaterial.transparency = 0.6 183 | planeNode.geometry?.firstMaterial = planeMaterial 184 | scene.rootNode.addChildNode(planeNode) 185 | 186 | let boxNode = SCNNode() 187 | boxNode.name = "box" 188 | boxNode.geometry = SCNBox(width:1, height:1, length:1, chamferRadius:0.0) 189 | boxNode.geometry?.firstMaterial = boxMaterial 190 | scene.rootNode.addChildNode(boxNode) 191 | 192 | return scene 193 | } 194 | 195 | fileprivate func createChipsScene(with view: VuforiaEAGLView) -> SCNScene { 196 | let scene = SCNScene() 197 | 198 | boxMaterial.diffuse.contents = UIColor.lightGray 199 | 200 | let lightNode = SCNNode() 201 | lightNode.light = SCNLight() 202 | lightNode.light?.type = .omni 203 | lightNode.light?.color = UIColor.lightGray 204 | lightNode.position = SCNVector3(x:0, y:10, z:10) 205 | scene.rootNode.addChildNode(lightNode) 206 | 207 | let ambientLightNode = SCNNode() 208 | ambientLightNode.light = SCNLight() 209 | ambientLightNode.light?.type = .ambient 210 | ambientLightNode.light?.color = UIColor.darkGray 211 | scene.rootNode.addChildNode(ambientLightNode) 212 | 213 | let planeNode = SCNNode() 214 | planeNode.name = "plane" 215 | planeNode.geometry = SCNPlane(width: 247.0*view.objectScale, height: 173.0*view.objectScale) 216 | planeNode.position = SCNVector3Make(0, 0, -1) 217 | let planeMaterial = SCNMaterial() 218 | planeMaterial.diffuse.contents = UIColor.red 219 | planeMaterial.transparency = 0.6 220 | planeNode.geometry?.firstMaterial = planeMaterial 221 | scene.rootNode.addChildNode(planeNode) 222 | 223 | let boxNode = SCNNode() 224 | boxNode.name = "box" 225 | boxNode.geometry = SCNBox(width:1, height:1, length:1, chamferRadius:0.0) 226 | boxNode.geometry?.firstMaterial = boxMaterial 227 | scene.rootNode.addChildNode(boxNode) 228 | 229 | return scene 230 | } 231 | 232 | func vuforiaEAGLView(_ view: VuforiaEAGLView!, didTouchDownNode node: SCNNode!) { 233 | print("touch down \(node.name ?? "")\n") 234 | boxMaterial.transparency = 0.6 235 | } 236 | 237 | func vuforiaEAGLView(_ view: VuforiaEAGLView!, didTouchUp node: SCNNode!) { 238 | print("touch up \(node.name ?? "")\n") 239 | boxMaterial.transparency = 1.0 240 | } 241 | 242 | func vuforiaEAGLView(_ view: VuforiaEAGLView!, didTouchCancel node: SCNNode!) { 243 | print("touch cancel \(node.name ?? "")\n") 244 | boxMaterial.transparency = 1.0 245 | } 246 | } 247 | 248 | -------------------------------------------------------------------------------- /VuforiaSampleSwift/VuforiaManager/VuforiaEAGLView.h: -------------------------------------------------------------------------------- 1 | // 2 | // VuforiaEAGLView.h 3 | // VuforiaSampleSwift 4 | // 5 | // Created by Yoshihiro Kato on 2016/07/02. 6 | // Copyright © 2016年 Yoshihiro Kato. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | #import "VuforiaManager.h" 14 | 15 | @class VuforiaManager; 16 | @class VuforiaEAGLView; 17 | 18 | @protocol VuforiaEAGLViewSceneSource 19 | 20 | - (SCNScene *)sceneForEAGLView:(VuforiaEAGLView *)view userInfo:(NSDictionary*)userInfo; 21 | 22 | @end 23 | 24 | @protocol VuforiaEAGLViewDelegate 25 | 26 | - (void)vuforiaEAGLView:(VuforiaEAGLView*)view didTouchDownNode:(SCNNode *)node; 27 | - (void)vuforiaEAGLView:(VuforiaEAGLView*)view didTouchUpNode:(SCNNode *)node; 28 | - (void)vuforiaEAGLView:(VuforiaEAGLView*)view didTouchCancelNode:(SCNNode *)node; 29 | 30 | @end 31 | 32 | 33 | // EAGLView is a subclass of UIView and conforms to the informal protocol 34 | // UIGLViewProtocol 35 | @interface VuforiaEAGLView : UIView 36 | 37 | @property (weak, nonatomic)id sceneSource; 38 | @property (weak, nonatomic)id delegate; 39 | @property (nonatomic, assign)CGFloat objectScale; 40 | 41 | - (id)initWithFrame:(CGRect)frame manager:(VuforiaManager *) manager; 42 | 43 | - (void)setNearPlane:(CGFloat) near farPlane:(CGFloat) far; 44 | 45 | - (void)setupRenderer; 46 | - (void)setNeedsChangeSceneWithUserInfo: (NSDictionary*)userInfo; 47 | 48 | - (void)finishOpenGLESCommands; 49 | - (void)freeOpenGLESResources; 50 | @end 51 | -------------------------------------------------------------------------------- /VuforiaSampleSwift/VuforiaManager/VuforiaEAGLView.mm: -------------------------------------------------------------------------------- 1 | // 2 | // VuforiaEAGLView.m 3 | // VuforiaSampleSwift 4 | // 5 | // Created by Yoshihiro Kato on 2016/07/02. 6 | // Copyright © 2016年 Yoshihiro Kato. All rights reserved. 7 | // 8 | 9 | #import "VuforiaEAGLView.h" 10 | 11 | #import 12 | #import 13 | #import 14 | #import 15 | #import 16 | #import 17 | 18 | #import 19 | #import 20 | #import 21 | #import 22 | #import 23 | #import 24 | #import 25 | #import 26 | #import 27 | #import 28 | #import 29 | #import 30 | #import 31 | #import 32 | #import 33 | #import 34 | #import 35 | #import 36 | #import 37 | 38 | #import "VuforiaShaderUtils.h" 39 | 40 | 41 | namespace VuforiaEAGLViewUtils 42 | { 43 | // Print a 4x4 matrix 44 | void printMatrix(const float* matrix); 45 | 46 | // Print GL error information 47 | void checkGlError(const char* operation); 48 | 49 | // Set the rotation components of a 4x4 matrix 50 | void setRotationMatrix(float angle, float x, float y, float z, 51 | float *nMatrix); 52 | 53 | // Set the translation components of a 4x4 matrix 54 | void translatePoseMatrix(float x, float y, float z, 55 | float* nMatrix = NULL); 56 | 57 | // Apply a rotation 58 | void rotatePoseMatrix(float angle, float x, float y, float z, 59 | float* nMatrix = NULL); 60 | 61 | // Apply a scaling transformation 62 | void scalePoseMatrix(float x, float y, float z, 63 | float* nMatrix = NULL); 64 | 65 | // Multiply the two matrices A and B and write the result to C 66 | void multiplyMatrix(float *matrixA, float *matrixB, 67 | float *matrixC); 68 | 69 | void setOrthoMatrix(float nLeft, float nRight, float nBottom, float nTop, 70 | float nNear, float nFar, float *nProjMatrix); 71 | 72 | // void screenCoordToCameraCoord(int screenX, int screenY, int screenDX, int screenDY, 73 | // int screenWidth, int screenHeight, int cameraWidth, int cameraHeight, 74 | // int * cameraX, int* cameraY, int * cameraDX, int * cameraDY); 75 | 76 | Vuforia::Matrix44F identityMatrix(); 77 | Vuforia::Matrix44F transposeMatrix(const Vuforia::Matrix44F& m); 78 | Vuforia::Matrix44F inverseMatrix(const Vuforia::Matrix44F& m); 79 | } 80 | 81 | 82 | //****************************************************************************** 83 | // *** OpenGL ES thread safety *** 84 | // 85 | // OpenGL ES on iOS is not thread safe. We ensure thread safety by following 86 | // this procedure: 87 | // 1) Create the OpenGL ES context on the main thread. 88 | // 2) Start the Vuforia camera, which causes Vuforia to locate our EAGLView and start 89 | // the render thread. 90 | // 3) Vuforia calls our renderFrameVuforia method periodically on the render thread. 91 | // The first time this happens, the defaultFramebuffer does not exist, so it 92 | // is created with a call to createFramebuffer. createFramebuffer is called 93 | // on the main thread in order to safely allocate the OpenGL ES storage, 94 | // which is shared with the drawable layer. The render (background) thread 95 | // is blocked during the call to createFramebuffer, thus ensuring no 96 | // concurrent use of the OpenGL ES context. 97 | // 98 | //****************************************************************************** 99 | 100 | @interface VuforiaEAGLView (PrivateMethods) 101 | 102 | - (void)initShaders; 103 | - (void)createFramebuffer; 104 | - (void)deleteFramebuffer; 105 | - (void)setFramebuffer; 106 | - (BOOL)presentFramebuffer; 107 | 108 | @end 109 | 110 | 111 | @implementation VuforiaEAGLView { 112 | __weak VuforiaManager* _manager; 113 | 114 | // OpenGL ES context 115 | EAGLContext* _context; 116 | 117 | // The OpenGL ES names for the framebuffer and renderbuffers used to render 118 | // to this view 119 | GLuint _defaultFramebuffer; 120 | GLuint _colorRenderbuffer; 121 | GLuint _depthRenderbuffer; 122 | 123 | SCNRenderer* _renderer; // Renderer 124 | SCNNode* _cameraNode; // Camera Node 125 | CFAbsoluteTime _startTime; // Start Time 126 | 127 | SCNNode* _currentTouchNode; 128 | 129 | SCNMatrix4 _projectionTransform; 130 | 131 | CGFloat _nearPlane; 132 | CGFloat _farPlane; 133 | 134 | GLuint _vbShaderProgramID; 135 | GLint _vbVertexHandle; 136 | GLint _vbTexCoordHandle; 137 | GLint _vbTexSampler2DHandle; 138 | GLint _vbProjectionMatrixHandle; 139 | Vuforia::VIEW _currentView; 140 | Vuforia::RenderingPrimitives* _currentRenderingPrimitives; 141 | } 142 | 143 | // You must implement this method, which ensures the view's underlying layer is 144 | // of type CAEAGLLayer 145 | + (Class)layerClass 146 | { 147 | return [CAEAGLLayer class]; 148 | } 149 | 150 | 151 | //------------------------------------------------------------------------------ 152 | #pragma mark - Lifecycle 153 | 154 | - (id)initWithFrame:(CGRect)frame manager:(VuforiaManager *)manager 155 | { 156 | self = [super initWithFrame:frame]; 157 | 158 | if (self) { 159 | _manager = manager; 160 | // Enable retina mode if available on this device 161 | if (YES == [_manager isRetinaDisplay]) { 162 | [self setContentScaleFactor:[UIScreen mainScreen].nativeScale]; 163 | } 164 | 165 | // Create the OpenGL ES context 166 | _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; 167 | 168 | // The EAGLContext must be set for each thread that wishes to use it. 169 | // Set it the first time this method is called (on the main thread) 170 | if (_context != [EAGLContext currentContext]) { 171 | [EAGLContext setCurrentContext:_context]; 172 | } 173 | 174 | _objectScale = 0.03175f; 175 | 176 | _nearPlane = 0.01; 177 | _farPlane = 5; 178 | 179 | [self initRendering]; 180 | } 181 | 182 | return self; 183 | } 184 | 185 | - (void) initRendering { 186 | // Video background rendering 187 | _vbShaderProgramID = [VuforiaShaderUtils createProgramWithVertexShaderFileName:@"Background.vertsh" 188 | fragmentShaderFileName:@"Background.fragsh"]; 189 | 190 | if (0 < _vbShaderProgramID) { 191 | _vbVertexHandle = glGetAttribLocation(_vbShaderProgramID, "vertexPosition"); 192 | _vbTexCoordHandle = glGetAttribLocation(_vbShaderProgramID, "vertexTexCoord"); 193 | _vbProjectionMatrixHandle = glGetUniformLocation(_vbShaderProgramID, "projectionMatrix"); 194 | _vbTexSampler2DHandle = glGetUniformLocation(_vbShaderProgramID, "texSampler2D"); 195 | } 196 | else { 197 | NSLog(@"Could not initialise video background shader"); 198 | } 199 | 200 | } 201 | 202 | 203 | - (void)dealloc 204 | { 205 | [self deleteFramebuffer]; 206 | 207 | // Tear down context 208 | if ([EAGLContext currentContext] == _context) { 209 | [EAGLContext setCurrentContext:nil]; 210 | } 211 | } 212 | 213 | - (void) setNearPlane:(CGFloat) near farPlane:(CGFloat) far { 214 | _nearPlane = near; 215 | _farPlane = far; 216 | } 217 | 218 | - (void)setupRenderer { 219 | _startTime = CFAbsoluteTimeGetCurrent(); 220 | _renderer = [SCNRenderer rendererWithContext:_context options:nil]; 221 | //_renderer.autoenablesDefaultLighting = YES; 222 | _renderer.playing = YES; 223 | 224 | if (_sceneSource != nil) { 225 | [self setNeedsChangeSceneWithUserInfo:nil]; 226 | } 227 | 228 | } 229 | 230 | - (void)setNeedsChangeSceneWithUserInfo: (NSDictionary*)userInfo { 231 | SCNScene* scene = [self.sceneSource sceneForEAGLView:self userInfo:userInfo]; 232 | if (scene == nil) { 233 | return; 234 | } 235 | 236 | SCNCamera* camera = [SCNCamera camera]; 237 | _cameraNode = [SCNNode node]; 238 | _cameraNode.camera = camera; 239 | _cameraNode.camera.projectionTransform = _projectionTransform; 240 | [scene.rootNode addChildNode:_cameraNode]; 241 | 242 | _renderer.scene = scene; 243 | _renderer.pointOfView = _cameraNode; 244 | } 245 | 246 | 247 | - (void)finishOpenGLESCommands 248 | { 249 | // Called in response to applicationWillResignActive. The render loop has 250 | // been stopped, so we now make sure all OpenGL ES commands complete before 251 | // we (potentially) go into the background 252 | if (_context) { 253 | [EAGLContext setCurrentContext:_context]; 254 | glFinish(); 255 | } 256 | } 257 | 258 | 259 | - (void)freeOpenGLESResources 260 | { 261 | // Called in response to applicationDidEnterBackground. Free easily 262 | // recreated OpenGL ES resources 263 | [self deleteFramebuffer]; 264 | glFinish(); 265 | } 266 | 267 | // Convert Vuforia's matrix to SceneKit's matrix 268 | - (SCNMatrix4)SCNMatrix4FromVuforiaMatrix44:(Vuforia::Matrix44F)matrix { 269 | GLKMatrix4 glkMatrix; 270 | 271 | for(int i=0; i<16; i++) { 272 | glkMatrix.m[i] = matrix.data[i]; 273 | } 274 | 275 | return SCNMatrix4FromGLKMatrix4(glkMatrix); 276 | 277 | } 278 | 279 | // Set camera node matrix 280 | - (void)setCameraMatrix:(Vuforia::Matrix44F)matrix { 281 | SCNMatrix4 extrinsic = [self SCNMatrix4FromVuforiaMatrix44:matrix]; 282 | SCNMatrix4 inverted = SCNMatrix4Invert(extrinsic); 283 | _cameraNode.transform = inverted; 284 | 285 | //NSLog(@"position = %lf, %lf, %lf", _cameraNode.position.x, _cameraNode.position.y, _cameraNode.position.z); // for Debug 286 | } 287 | 288 | - (void)setProjectionMatrix:(Vuforia::Matrix44F)matrix { 289 | _projectionTransform = [self SCNMatrix4FromVuforiaMatrix44:matrix]; 290 | _cameraNode.camera.projectionTransform = _projectionTransform; 291 | } 292 | 293 | //------------------------------------------------------------------------------ 294 | #pragma mark - UIGLViewProtocol methods 295 | 296 | // Draw the current frame using OpenGL 297 | // 298 | // This method is called by Vuforia when it wishes to render the current frame to 299 | // the screen. 300 | // 301 | // *** Vuforia will call this method periodically on a background thread *** 302 | - (void)renderFrameVuforia 303 | { 304 | if(!_manager.isCameraStarted) { 305 | return; 306 | } 307 | 308 | // Render video background and retrieve tracking state 309 | const Vuforia::State state = Vuforia::TrackerManager::getInstance().getStateUpdater().updateState(); 310 | Vuforia::Renderer::getInstance().begin(state); 311 | 312 | 313 | if(Vuforia::Renderer::getInstance().getVideoBackgroundConfig().mReflection == Vuforia::VIDEO_BACKGROUND_REFLECTION_ON) 314 | glFrontFace(GL_CW); //Front camera 315 | else 316 | glFrontFace(GL_CCW); //Back camera 317 | 318 | if(_currentRenderingPrimitives == nullptr) 319 | [self updateRenderingPrimitives]; 320 | 321 | Vuforia::ViewList& viewList = _currentRenderingPrimitives->getRenderingViews(); 322 | 323 | // Clear colour and depth buffers 324 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 325 | 326 | glEnable(GL_DEPTH_TEST); 327 | glEnable(GL_CULL_FACE); 328 | glCullFace(GL_BACK); 329 | 330 | // Iterate over the ViewList 331 | for (int viewIdx = 0; viewIdx < viewList.getNumViews(); viewIdx++) { 332 | Vuforia::VIEW vw = viewList.getView(viewIdx); 333 | _currentView = vw; 334 | 335 | // Set up the viewport 336 | Vuforia::Vec4I viewport; 337 | // We're writing directly to the screen, so the viewport is relative to the screen 338 | viewport = _currentRenderingPrimitives->getViewport(vw); 339 | 340 | // Set viewport for current view 341 | glViewport(viewport.data[0], viewport.data[1], viewport.data[2], viewport.data[3]); 342 | 343 | //set scissor 344 | glScissor(viewport.data[0], viewport.data[1], viewport.data[2], viewport.data[3]); 345 | 346 | Vuforia::Matrix34F projMatrix = _currentRenderingPrimitives->getProjectionMatrix(vw, state.getCameraCalibration()); 347 | 348 | Vuforia::Matrix44F rawProjectionMatrixGL = Vuforia::Tool::convertPerspectiveProjection2GLMatrix( 349 | projMatrix, 350 | _nearPlane, 351 | _farPlane); 352 | 353 | // Apply the appropriate eye adjustment to the raw projection matrix, and assign to the global variable 354 | Vuforia::Matrix44F eyeAdjustmentGL = Vuforia::Tool::convert2GLMatrix(_currentRenderingPrimitives->getEyeDisplayAdjustmentMatrix(vw)); 355 | 356 | Vuforia::Matrix44F projectionMatrix; 357 | VuforiaEAGLViewUtils::multiplyMatrix(&rawProjectionMatrixGL.data[0], &eyeAdjustmentGL.data[0], &projectionMatrix.data[0]); 358 | 359 | if (_currentView != Vuforia::VIEW_POSTPROCESS) { 360 | [self renderFrameWithState:state projectMatrix:projectionMatrix]; 361 | } 362 | 363 | glDisable(GL_SCISSOR_TEST); 364 | 365 | } 366 | 367 | Vuforia::Renderer::getInstance().end(); 368 | } 369 | 370 | - (void)updateRenderingPrimitives 371 | { 372 | delete _currentRenderingPrimitives; 373 | _currentRenderingPrimitives = new Vuforia::RenderingPrimitives(Vuforia::Device::getInstance().getRenderingPrimitives()); 374 | } 375 | 376 | - (void) renderFrameWithState:(const Vuforia::State&) state projectMatrix:(Vuforia::Matrix44F&) projectionMatrix { 377 | [self setFramebuffer]; 378 | 379 | // Clear colour and depth buffers 380 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 381 | 382 | // Render video background and retrieve tracking state 383 | [self renderVideoBackgroundWithState:state]; 384 | 385 | glEnable(GL_DEPTH_TEST); 386 | // We must detect if background reflection is active and adjust the culling direction. 387 | // If the reflection is active, this means the pose matrix has been reflected as well, 388 | // therefore standard counter clockwise face culling will result in "inside out" models. 389 | glEnable(GL_CULL_FACE); 390 | 391 | glCullFace(GL_BACK); 392 | if(Vuforia::Renderer::getInstance().getVideoBackgroundConfig().mReflection == Vuforia::VIDEO_BACKGROUND_REFLECTION_ON) 393 | glFrontFace(GL_CW); //Front camera 394 | else 395 | glFrontFace(GL_CCW); //Back camera 396 | 397 | Vuforia::Matrix44F devicePoseMatrix = VuforiaEAGLViewUtils::identityMatrix(); 398 | 399 | if (state.getDeviceTrackableResult() != nullptr && state.getDeviceTrackableResult()->getStatus() != Vuforia::TrackableResult::NO_POSE) { 400 | Vuforia::Matrix44F deviceMatrix = Vuforia::Tool::convertPose2GLMatrix(state.getDeviceTrackableResult()->getPose()); 401 | devicePoseMatrix = VuforiaEAGLViewUtils::transposeMatrix(VuforiaEAGLViewUtils::inverseMatrix(deviceMatrix)); 402 | } 403 | 404 | for (int i = 0; i < state.getNumTrackableResults(); ++i) { 405 | // Get the trackable 406 | const Vuforia::TrackableResult* result = state.getTrackableResult(i); 407 | 408 | Vuforia::Matrix44F modelViewMatrix = Vuforia::Tool::convertPose2GLMatrix(result->getPose()); // get model view matrix 409 | 410 | VuforiaEAGLViewUtils::translatePoseMatrix(0.0f, 0.0f, _objectScale, &modelViewMatrix.data[0]); 411 | VuforiaEAGLViewUtils::scalePoseMatrix(_objectScale, _objectScale, _objectScale, &modelViewMatrix.data[0]); 412 | VuforiaEAGLViewUtils::multiplyMatrix(&devicePoseMatrix.data[0],&modelViewMatrix.data[0],&modelViewMatrix.data[0]); 413 | 414 | [self setProjectionMatrix:projectionMatrix]; 415 | [self setCameraMatrix:modelViewMatrix]; // set camera matrix to SCNCamera 416 | 417 | [SCNTransaction flush]; 418 | 419 | CFAbsoluteTime currentTime = CFAbsoluteTimeGetCurrent() - _startTime; 420 | [_renderer renderAtTime: currentTime]; // render using SCNRenderer 421 | 422 | VuforiaEAGLViewUtils::checkGlError("EAGLView renderFrameVuforia"); 423 | } 424 | 425 | glDisable(GL_DEPTH_TEST); 426 | glDisable(GL_CULL_FACE); 427 | 428 | [self presentFramebuffer]; 429 | } 430 | 431 | - (void) renderVideoBackgroundWithState:(const Vuforia::State&)state { 432 | if (_currentView == Vuforia::VIEW_POSTPROCESS) { 433 | return; 434 | } 435 | 436 | // Use texture unit 0 for the video background - this will hold the camera frame and we want to reuse for all views 437 | // So need to use a different texture unit for the augmentation 438 | int vbVideoTextureUnit = 0; 439 | 440 | // Bind the video bg texture and get the Texture ID from Vuforia 441 | Vuforia::GLTextureUnit tex; 442 | tex.mTextureUnit = vbVideoTextureUnit; 443 | 444 | if (! Vuforia::Renderer::getInstance().updateVideoBackgroundTexture(&tex)) 445 | { 446 | NSLog(@"Unable to bind video background texture!!"); 447 | return; 448 | } 449 | 450 | Vuforia::Matrix44F vbProjectionMatrix = Vuforia::Tool::convert2GLMatrix(_currentRenderingPrimitives->getVideoBackgroundProjectionMatrix(_currentView)); 451 | 452 | // Apply the scene scale on video see-through eyewear, to scale the video background and augmentation 453 | // so that the display lines up with the real world 454 | // This should not be applied on optical see-through devices, as there is no video background, 455 | // and the calibration ensures that the augmentation matches the real world 456 | if (Vuforia::Device::getInstance().isViewerActive()) 457 | { 458 | float sceneScaleFactor = [self getSceneScaleFactorWithViewId:_currentView cameraCalibration:state.getCameraCalibration()]; 459 | VuforiaEAGLViewUtils::scalePoseMatrix(sceneScaleFactor, sceneScaleFactor, 1.0f, vbProjectionMatrix.data); 460 | } 461 | 462 | glDisable(GL_DEPTH_TEST); 463 | glDisable(GL_CULL_FACE); 464 | glDisable(GL_SCISSOR_TEST); 465 | 466 | const Vuforia::Mesh& vbMesh = _currentRenderingPrimitives->getVideoBackgroundMesh(_currentView); 467 | // Load the shader and upload the vertex/texcoord/index data 468 | glUseProgram(_vbShaderProgramID); 469 | glVertexAttribPointer(_vbVertexHandle, 3, GL_FLOAT, false, 0, vbMesh.getPositionCoordinates()); 470 | glVertexAttribPointer(_vbTexCoordHandle, 2, GL_FLOAT, false, 0, vbMesh.getUVCoordinates()); 471 | 472 | glUniform1i(_vbTexSampler2DHandle, vbVideoTextureUnit); 473 | 474 | // Render the video background with the custom shader 475 | // First, we enable the vertex arrays 476 | glEnableVertexAttribArray(_vbVertexHandle); 477 | glEnableVertexAttribArray(_vbTexCoordHandle); 478 | 479 | // Pass the projection matrix to OpenGL 480 | glUniformMatrix4fv(_vbProjectionMatrixHandle, 1, GL_FALSE, vbProjectionMatrix.data); 481 | 482 | // Then, we issue the render call 483 | glDrawElements(GL_TRIANGLES, vbMesh.getNumTriangles() * 3, GL_UNSIGNED_SHORT, 484 | vbMesh.getTriangles()); 485 | 486 | // Finally, we disable the vertex arrays 487 | glDisableVertexAttribArray(_vbVertexHandle); 488 | glDisableVertexAttribArray(_vbTexCoordHandle); 489 | 490 | VuforiaEAGLViewUtils::checkGlError("Rendering of the video background failed"); 491 | } 492 | 493 | -(float)getSceneScaleFactorWithViewId:(Vuforia::VIEW)viewId cameraCalibration:(const Vuforia::CameraCalibration*)cameraCalib 494 | { 495 | if (cameraCalib == nullptr) { 496 | NSLog(@"Cannot compute scene scale factor, camera calibration is invalid"); 497 | return 0.0f; 498 | } 499 | 500 | // Get the y-dimension of the physical camera field of view 501 | Vuforia::Vec2F fovVector = cameraCalib->getFieldOfViewRads(); 502 | float cameraFovYRads = fovVector.data[1]; 503 | 504 | // Get the y-dimension of the virtual camera field of view 505 | Vuforia::Vec4F virtualFovVector = _currentRenderingPrimitives->getEffectiveFov(viewId); // {left, right, bottom, top} 506 | float virtualFovYRads = virtualFovVector.data[2] + virtualFovVector.data[3]; 507 | 508 | // The scene-scale factor represents the proportion of the viewport that is filled by 509 | // the video background when projected onto the same plane. 510 | // In order to calculate this, let 'd' be the distance between the cameras and the plane. 511 | // The height of the projected image 'h' on this plane can then be calculated: 512 | // tan(fov/2) = h/2d 513 | // which rearranges to: 514 | // 2d = h/tan(fov/2) 515 | // Since 'd' is the same for both cameras, we can combine the equations for the two cameras: 516 | // hPhysical/tan(fovPhysical/2) = hVirtual/tan(fovVirtual/2) 517 | // Which rearranges to: 518 | // hPhysical/hVirtual = tan(fovPhysical/2)/tan(fovVirtual/2) 519 | // ... which is the scene-scale factor 520 | return tan(cameraFovYRads / 2) / tan(virtualFovYRads / 2); 521 | } 522 | 523 | #pragma mark Touch Evnets 524 | - (SCNNode*)touchedNodeWithLocationInView:(CGPoint)location { 525 | CGPoint pos = location; 526 | pos.x *= [[UIScreen mainScreen] nativeScale]; 527 | pos.y *= [[UIScreen mainScreen] nativeScale]; 528 | NSArray* results = [_renderer hitTest:pos options:nil]; 529 | return [[results firstObject] node]; 530 | } 531 | 532 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 533 | CGPoint pos = [touches.anyObject locationInView:self]; 534 | SCNNode* result = [self touchedNodeWithLocationInView:pos]; 535 | if(result){ 536 | _currentTouchNode = result; 537 | [self.delegate vuforiaEAGLView:self didTouchDownNode:result]; 538 | } 539 | 540 | } 541 | 542 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { 543 | 544 | } 545 | 546 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 547 | if(!_currentTouchNode) { 548 | return; 549 | } 550 | 551 | CGPoint pos = [touches.anyObject locationInView:self]; 552 | SCNNode* result = [self touchedNodeWithLocationInView:pos]; 553 | if(_currentTouchNode == result){ 554 | [self.delegate vuforiaEAGLView:self didTouchUpNode:result]; 555 | }else { 556 | [self.delegate vuforiaEAGLView:self didTouchCancelNode:_currentTouchNode]; 557 | } 558 | _currentTouchNode = nil; 559 | } 560 | 561 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { 562 | if(_currentTouchNode) { 563 | [self.delegate vuforiaEAGLView:self didTouchCancelNode:_currentTouchNode]; 564 | } 565 | _currentTouchNode = nil; 566 | } 567 | 568 | //------------------------------------------------------------------------------ 569 | #pragma mark - OpenGL ES management 570 | 571 | - (void)createFramebuffer 572 | { 573 | if (_context) { 574 | // Create default framebuffer object 575 | glGenFramebuffers(1, &_defaultFramebuffer); 576 | glBindFramebuffer(GL_FRAMEBUFFER, _defaultFramebuffer); 577 | 578 | // Create colour renderbuffer and allocate backing store 579 | glGenRenderbuffers(1, &_colorRenderbuffer); 580 | glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderbuffer); 581 | 582 | // Allocate the renderbuffer's storage (shared with the drawable object) 583 | [_context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer*)self.layer]; 584 | GLint framebufferWidth; 585 | GLint framebufferHeight; 586 | glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &framebufferWidth); 587 | glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &framebufferHeight); 588 | 589 | // Create the depth render buffer and allocate storage 590 | glGenRenderbuffers(1, &_depthRenderbuffer); 591 | glBindRenderbuffer(GL_RENDERBUFFER, _depthRenderbuffer); 592 | glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, framebufferWidth, framebufferHeight); 593 | 594 | // Attach colour and depth render buffers to the frame buffer 595 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorRenderbuffer); 596 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthRenderbuffer); 597 | 598 | // Leave the colour render buffer bound so future rendering operations will act on it 599 | glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderbuffer); 600 | } 601 | } 602 | 603 | 604 | - (void)deleteFramebuffer 605 | { 606 | if (_context) { 607 | [EAGLContext setCurrentContext:_context]; 608 | 609 | if (_defaultFramebuffer) { 610 | glDeleteFramebuffers(1, &_defaultFramebuffer); 611 | _defaultFramebuffer = 0; 612 | } 613 | 614 | if (_colorRenderbuffer) { 615 | glDeleteRenderbuffers(1, &_colorRenderbuffer); 616 | _colorRenderbuffer = 0; 617 | } 618 | 619 | if (_depthRenderbuffer) { 620 | glDeleteRenderbuffers(1, &_depthRenderbuffer); 621 | _depthRenderbuffer = 0; 622 | } 623 | } 624 | } 625 | 626 | 627 | - (void)setFramebuffer 628 | { 629 | // The EAGLContext must be set for each thread that wishes to use it. Set 630 | // it the first time this method is called (on the render thread) 631 | if (_context != [EAGLContext currentContext]) { 632 | [EAGLContext setCurrentContext:_context]; 633 | } 634 | 635 | if (!_defaultFramebuffer) { 636 | // Perform on the main thread to ensure safe memory allocation for the 637 | // shared buffer. Block until the operation is complete to prevent 638 | // simultaneous access to the OpenGL context 639 | [self performSelectorOnMainThread:@selector(createFramebuffer) withObject:self waitUntilDone:YES]; 640 | } 641 | 642 | glBindFramebuffer(GL_FRAMEBUFFER, _defaultFramebuffer); 643 | } 644 | 645 | 646 | - (BOOL)presentFramebuffer 647 | { 648 | // setFramebuffer must have been called before presentFramebuffer, therefore 649 | // we know the context is valid and has been set for this (render) thread 650 | 651 | // Bind the colour render buffer and present it 652 | glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderbuffer); 653 | 654 | return [_context presentRenderbuffer:GL_RENDERBUFFER]; 655 | } 656 | 657 | 658 | @end 659 | 660 | namespace VuforiaEAGLViewUtils 661 | { 662 | // Print a 4x4 matrix 663 | void 664 | printMatrix(const float* mat) 665 | { 666 | for (int r = 0; r < 4; r++, mat += 4) { 667 | printf("%7.3f %7.3f %7.3f %7.3f", mat[0], mat[1], mat[2], mat[3]); 668 | } 669 | } 670 | 671 | 672 | // Print GL error information 673 | void 674 | checkGlError(const char* operation) 675 | { 676 | for (GLint error = glGetError(); error; error = glGetError()) { 677 | printf("after %s() glError (0x%x)\n", operation, error); 678 | } 679 | } 680 | 681 | 682 | // Set the rotation components of a 4x4 matrix 683 | void 684 | setRotationMatrix(float angle, float x, float y, float z, 685 | float *matrix) 686 | { 687 | double radians, c, s, c1, u[3], length; 688 | int i, j; 689 | 690 | radians = (angle * M_PI) / 180.0; 691 | 692 | c = cos(radians); 693 | s = sin(radians); 694 | 695 | c1 = 1.0 - cos(radians); 696 | 697 | length = sqrt(x * x + y * y + z * z); 698 | 699 | u[0] = x / length; 700 | u[1] = y / length; 701 | u[2] = z / length; 702 | 703 | for (i = 0; i < 16; i++) { 704 | matrix[i] = 0.0; 705 | } 706 | 707 | matrix[15] = 1.0; 708 | 709 | for (i = 0; i < 3; i++) { 710 | matrix[i * 4 + (i + 1) % 3] = u[(i + 2) % 3] * s; 711 | matrix[i * 4 + (i + 2) % 3] = -u[(i + 1) % 3] * s; 712 | } 713 | 714 | for (i = 0; i < 3; i++) { 715 | for (j = 0; j < 3; j++) { 716 | matrix[i * 4 + j] += c1 * u[i] * u[j] + (i == j ? c : 0.0); 717 | } 718 | } 719 | } 720 | 721 | 722 | // Set the translation components of a 4x4 matrix 723 | void 724 | translatePoseMatrix(float x, float y, float z, float* matrix) 725 | { 726 | if (matrix) { 727 | // matrix * translate_matrix 728 | matrix[12] += (matrix[0] * x + matrix[4] * y + matrix[8] * z); 729 | matrix[13] += (matrix[1] * x + matrix[5] * y + matrix[9] * z); 730 | matrix[14] += (matrix[2] * x + matrix[6] * y + matrix[10] * z); 731 | matrix[15] += (matrix[3] * x + matrix[7] * y + matrix[11] * z); 732 | } 733 | } 734 | 735 | 736 | // Apply a rotation 737 | void 738 | rotatePoseMatrix(float angle, float x, float y, float z, 739 | float* matrix) 740 | { 741 | if (matrix) { 742 | float rotate_matrix[16]; 743 | setRotationMatrix(angle, x, y, z, rotate_matrix); 744 | 745 | // matrix * scale_matrix 746 | multiplyMatrix(matrix, rotate_matrix, matrix); 747 | } 748 | } 749 | 750 | 751 | // Apply a scaling transformation 752 | void 753 | scalePoseMatrix(float x, float y, float z, float* matrix) 754 | { 755 | if (matrix) { 756 | // matrix * scale_matrix 757 | matrix[0] *= x; 758 | matrix[1] *= x; 759 | matrix[2] *= x; 760 | matrix[3] *= x; 761 | 762 | matrix[4] *= y; 763 | matrix[5] *= y; 764 | matrix[6] *= y; 765 | matrix[7] *= y; 766 | 767 | matrix[8] *= z; 768 | matrix[9] *= z; 769 | matrix[10] *= z; 770 | matrix[11] *= z; 771 | } 772 | } 773 | 774 | 775 | // Multiply the two matrices A and B and write the result to C 776 | void 777 | multiplyMatrix(float *matrixA, float *matrixB, float *matrixC) 778 | { 779 | int i, j, k; 780 | float aTmp[16]; 781 | 782 | for (i = 0; i < 4; i++) { 783 | for (j = 0; j < 4; j++) { 784 | aTmp[j * 4 + i] = 0.0; 785 | 786 | for (k = 0; k < 4; k++) { 787 | aTmp[j * 4 + i] += matrixA[k * 4 + i] * matrixB[j * 4 + k]; 788 | } 789 | } 790 | } 791 | 792 | for (i = 0; i < 16; i++) { 793 | matrixC[i] = aTmp[i]; 794 | } 795 | } 796 | 797 | void 798 | setOrthoMatrix(float nLeft, float nRight, float nBottom, float nTop, 799 | float nNear, float nFar, float *nProjMatrix) 800 | { 801 | if (!nProjMatrix) 802 | { 803 | // arLogMessage(AR_LOG_LEVEL_ERROR, "PLShadersExample", "Orthographic projection matrix pointer is NULL"); 804 | return; 805 | } 806 | 807 | int i; 808 | for (i = 0; i < 16; i++) 809 | nProjMatrix[i] = 0.0f; 810 | 811 | nProjMatrix[0] = 2.0f / (nRight - nLeft); 812 | nProjMatrix[5] = 2.0f / (nTop - nBottom); 813 | nProjMatrix[10] = 2.0f / (nNear - nFar); 814 | nProjMatrix[12] = -(nRight + nLeft) / (nRight - nLeft); 815 | nProjMatrix[13] = -(nTop + nBottom) / (nTop - nBottom); 816 | nProjMatrix[14] = (nFar + nNear) / (nFar - nNear); 817 | nProjMatrix[15] = 1.0f; 818 | } 819 | 820 | Vuforia::Matrix44F 821 | identityMatrix() 822 | { 823 | Vuforia::Matrix44F r; 824 | 825 | for (int i = 0; i < 16; i++) 826 | r.data[i] = 0.0f; 827 | 828 | r.data[0] = 1.0f; 829 | r.data[5] = 1.0f; 830 | r.data[10] = 1.0f; 831 | r.data[15] = 1.0f; 832 | 833 | return r; 834 | } 835 | 836 | Vuforia::Matrix44F 837 | transposeMatrix(const Vuforia::Matrix44F& m) 838 | { 839 | Vuforia::Matrix44F r; 840 | for (int i = 0; i < 4; i++) 841 | for (int j = 0; j < 4; j++) 842 | r.data[i*4+j] = m.data[i+4*j]; 843 | return r; 844 | } 845 | 846 | float 847 | determinateMatrix(const Vuforia::Matrix44F& m) 848 | { 849 | return m.data[12] * m.data[9] * m.data[6] * m.data[3] - m.data[8] * m.data[13] * m.data[6] * m.data[3] - 850 | m.data[12] * m.data[5] * m.data[10] * m.data[3] + m.data[4] * m.data[13] * m.data[10] * m.data[3] + 851 | m.data[8] * m.data[5] * m.data[14] * m.data[3] - m.data[4] * m.data[9] * m.data[14] * m.data[3] - 852 | m.data[12] * m.data[9] * m.data[2] * m.data[7] + m.data[8] * m.data[13] * m.data[2] * m.data[7] + 853 | m.data[12] * m.data[1] * m.data[10] * m.data[7] - m.data[0] * m.data[13] * m.data[10] * m.data[7] - 854 | m.data[8] * m.data[1] * m.data[14] * m.data[7] + m.data[0] * m.data[9] * m.data[14] * m.data[7] + 855 | m.data[12] * m.data[5] * m.data[2] * m.data[11] - m.data[4] * m.data[13] * m.data[2] * m.data[11] - 856 | m.data[12] * m.data[1] * m.data[6] * m.data[11] + m.data[0] * m.data[13] * m.data[6] * m.data[11] + 857 | m.data[4] * m.data[1] * m.data[14] * m.data[11] - m.data[0] * m.data[5] * m.data[14] * m.data[11] - 858 | m.data[8] * m.data[5] * m.data[2] * m.data[15] + m.data[4] * m.data[9] * m.data[2] * m.data[15] + 859 | m.data[8] * m.data[1] * m.data[6] * m.data[15] - m.data[0] * m.data[9] * m.data[6] * m.data[15] - 860 | m.data[4] * m.data[1] * m.data[10] * m.data[15] + m.data[0] * m.data[5] * m.data[10] * m.data[15] ; 861 | } 862 | 863 | Vuforia::Matrix44F 864 | inverseMatrix(const Vuforia::Matrix44F& m) 865 | { 866 | Vuforia::Matrix44F r; 867 | 868 | float det = 1.0f / determinateMatrix(m); 869 | 870 | r.data[0] = m.data[6]*m.data[11]*m.data[13] - m.data[7]*m.data[10]*m.data[13] 871 | + m.data[7]*m.data[9]*m.data[14] - m.data[5]*m.data[11]*m.data[14] 872 | - m.data[6]*m.data[9]*m.data[15] + m.data[5]*m.data[10]*m.data[15]; 873 | 874 | r.data[4] = m.data[3]*m.data[10]*m.data[13] - m.data[2]*m.data[11]*m.data[13] 875 | - m.data[3]*m.data[9]*m.data[14] + m.data[1]*m.data[11]*m.data[14] 876 | + m.data[2]*m.data[9]*m.data[15] - m.data[1]*m.data[10]*m.data[15]; 877 | 878 | r.data[8] = m.data[2]*m.data[7]*m.data[13] - m.data[3]*m.data[6]*m.data[13] 879 | + m.data[3]*m.data[5]*m.data[14] - m.data[1]*m.data[7]*m.data[14] 880 | - m.data[2]*m.data[5]*m.data[15] + m.data[1]*m.data[6]*m.data[15]; 881 | 882 | r.data[12] = m.data[3]*m.data[6]*m.data[9] - m.data[2]*m.data[7]*m.data[9] 883 | - m.data[3]*m.data[5]*m.data[10] + m.data[1]*m.data[7]*m.data[10] 884 | + m.data[2]*m.data[5]*m.data[11] - m.data[1]*m.data[6]*m.data[11]; 885 | 886 | r.data[1] = m.data[7]*m.data[10]*m.data[12] - m.data[6]*m.data[11]*m.data[12] 887 | - m.data[7]*m.data[8]*m.data[14] + m.data[4]*m.data[11]*m.data[14] 888 | + m.data[6]*m.data[8]*m.data[15] - m.data[4]*m.data[10]*m.data[15]; 889 | 890 | r.data[5] = m.data[2]*m.data[11]*m.data[12] - m.data[3]*m.data[10]*m.data[12] 891 | + m.data[3]*m.data[8]*m.data[14] - m.data[0]*m.data[11]*m.data[14] 892 | - m.data[2]*m.data[8]*m.data[15] + m.data[0]*m.data[10]*m.data[15]; 893 | 894 | r.data[9] = m.data[3]*m.data[6]*m.data[12] - m.data[2]*m.data[7]*m.data[12] 895 | - m.data[3]*m.data[4]*m.data[14] + m.data[0]*m.data[7]*m.data[14] 896 | + m.data[2]*m.data[4]*m.data[15] - m.data[0]*m.data[6]*m.data[15]; 897 | 898 | r.data[13] = m.data[2]*m.data[7]*m.data[8] - m.data[3]*m.data[6]*m.data[8] 899 | + m.data[3]*m.data[4]*m.data[10] - m.data[0]*m.data[7]*m.data[10] 900 | - m.data[2]*m.data[4]*m.data[11] + m.data[0]*m.data[6]*m.data[11]; 901 | 902 | r.data[2] = m.data[5]*m.data[11]*m.data[12] - m.data[7]*m.data[9]*m.data[12] 903 | + m.data[7]*m.data[8]*m.data[13] - m.data[4]*m.data[11]*m.data[13] 904 | - m.data[5]*m.data[8]*m.data[15] + m.data[4]*m.data[9]*m.data[15]; 905 | 906 | r.data[6] = m.data[3]*m.data[9]*m.data[12] - m.data[1]*m.data[11]*m.data[12] 907 | - m.data[3]*m.data[8]*m.data[13] + m.data[0]*m.data[11]*m.data[13] 908 | + m.data[1]*m.data[8]*m.data[15] - m.data[0]*m.data[9]*m.data[15]; 909 | 910 | r.data[10] = m.data[1]*m.data[7]*m.data[12] - m.data[3]*m.data[5]*m.data[12] 911 | + m.data[3]*m.data[4]*m.data[13] - m.data[0]*m.data[7]*m.data[13] 912 | - m.data[1]*m.data[4]*m.data[15] + m.data[0]*m.data[5]*m.data[15]; 913 | 914 | r.data[14] = m.data[3]*m.data[5]*m.data[8] - m.data[1]*m.data[7]*m.data[8] 915 | - m.data[3]*m.data[4]*m.data[9] + m.data[0]*m.data[7]*m.data[9] 916 | + m.data[1]*m.data[4]*m.data[11] - m.data[0]*m.data[5]*m.data[11]; 917 | 918 | r.data[3] = m.data[6]*m.data[9]*m.data[12] - m.data[5]*m.data[10]*m.data[12] 919 | - m.data[6]*m.data[8]*m.data[13] + m.data[4]*m.data[10]*m.data[13] 920 | + m.data[5]*m.data[8]*m.data[14] - m.data[4]*m.data[9]*m.data[14]; 921 | 922 | r.data[7] = m.data[1]*m.data[10]*m.data[12] - m.data[2]*m.data[9]*m.data[12] 923 | + m.data[2]*m.data[8]*m.data[13] - m.data[0]*m.data[10]*m.data[13] 924 | - m.data[1]*m.data[8]*m.data[14] + m.data[0]*m.data[9]*m.data[14]; 925 | 926 | r.data[11] = m.data[2]*m.data[5]*m.data[12] - m.data[1]*m.data[6]*m.data[12] 927 | - m.data[2]*m.data[4]*m.data[13] + m.data[0]*m.data[6]*m.data[13] 928 | + m.data[1]*m.data[4]*m.data[14] - m.data[0]*m.data[5]*m.data[14]; 929 | 930 | r.data[15] = m.data[1]*m.data[6]*m.data[8] - m.data[2]*m.data[5]*m.data[8] 931 | + m.data[2]*m.data[4]*m.data[9] - m.data[0]*m.data[6]*m.data[9] 932 | - m.data[1]*m.data[4]*m.data[10] + m.data[0]*m.data[5]*m.data[10]; 933 | 934 | for (int i = 0; i < 16; i++) 935 | r.data[i] *= det; 936 | 937 | return r; 938 | } 939 | } 940 | -------------------------------------------------------------------------------- /VuforiaSampleSwift/VuforiaManager/VuforiaManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // VuforiaManager.h 3 | // VuforiaSample 4 | // 5 | // Created by Yoshihiro Kato on 2016/07/02. 6 | // Copyright © 2016年 Yoshihiro Kato. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "VuforiaObjects.h" 12 | #import "VuforiaEAGLView.h" 13 | 14 | typedef NS_ENUM(NSInteger, VuforiaError) { 15 | VuforiaError_InitializeError = -1, ///< Error during initialization 16 | VuforiaError_DeviceNotSupported = -2, ///< The device is not supported 17 | VuforiaError_NoCameraAccess = -3, ///< Cannot access the camera 18 | VuforiaError_MissingKey = -4, ///< License key is missing 19 | VuforiaError_InvalidKey = -5, ///< Invalid license key passed to SDK 20 | VuforiaError_NoNetworkPermanent = -6, ///< Unable to verify license key due to network (Permanent error) 21 | VuforiaError_NoNetworkTransient = -7, ///< Unable to verify license key due to network (Transient error) 22 | VuforiaError_CanceledKey = -8, ///< Provided key is no longer valid 23 | VuforiaError_ProductTypeMismatch = -9, ///< Provided key is not valid for this product 24 | VuforiaError_DeviceNotDetected = -10, 25 | 26 | VuforiaError_InitializingVuforia = 100, 27 | 28 | VuforiaError_InitializingCamera = 110, 29 | VuforiaError_StartingCamera = 111, 30 | VuforiaError_StoppingCamera = 112, 31 | VuforiaError_DeinitCamara = 113, 32 | 33 | VuforiaError_InitTrackers = 120, 34 | VuforiaError_LoadingTrackersData = 121, 35 | VuforiaError_StartingTrackers = 122, 36 | VuforiaError_StoppingTrackers = 123, 37 | VuforiaError_UnloadingTrackersData = 124, 38 | VuforiaError_DeinitTrackers = 125, 39 | 40 | VuforiaError_CameraNotStarted = 150, 41 | }; 42 | 43 | @class VuforiaManager; 44 | @class VuforiaEAGLView; 45 | 46 | @protocol VuforiaManagerDelegate 47 | 48 | - (void)vuforiaManagerDidFinishPreparing:(VuforiaManager*) manager; 49 | - (void)vuforiaManager:(VuforiaManager*)manager didFailToPreparingWithError:(NSError*)error; 50 | - (void)vuforiaManager:(VuforiaManager *)manager didUpdateWithState:(VuforiaState*)state; 51 | 52 | @end 53 | 54 | @interface VuforiaManager : NSObject 55 | 56 | @property (nonatomic, weak) id delegate; 57 | @property (nonatomic, readonly)BOOL isRetinaDisplay; 58 | @property (nonatomic, readonly)BOOL continuousAutofocusEnabled; 59 | @property (nonatomic, readonly)BOOL flashEnabled; 60 | @property (nonatomic, readonly)BOOL frontCameraEnabled; 61 | @property (nonatomic, readonly)VuforiaEAGLView* eaglView; 62 | @property (nonatomic, readonly)BOOL isCameraStarted; 63 | 64 | - (instancetype)init __attribute__((unavailable("init is not available"))); 65 | - (instancetype)initWithLicenseKey:(NSString*)licenseKey dataSetFile:(NSString*)path; 66 | 67 | - (CGSize)preferredARFrameSize; 68 | 69 | 70 | - (void)prepareWithOrientation:(UIInterfaceOrientation)orientation; 71 | 72 | - (BOOL)setContinuousAutofocusEnabled:(BOOL)enabled; 73 | - (BOOL)setFlashEnabled:(BOOL)enabled; 74 | - (BOOL)setFrontCameraEnabled:(BOOL)enabled; 75 | 76 | - (BOOL)resume:(NSError **)error; 77 | - (BOOL)pause:(NSError **)error; 78 | 79 | - (BOOL)start:(NSError **)error; 80 | - (BOOL)stop:(NSError **)error; 81 | 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /VuforiaSampleSwift/VuforiaManager/VuforiaManager.mm: -------------------------------------------------------------------------------- 1 | // 2 | // VuforiaManager.m 3 | // VuforiaSample 4 | // 5 | // Created by Yoshihiro Kato on 2016/07/02. 6 | // Copyright © 2016年 Yoshihiro Kato. All rights reserved. 7 | // 8 | 9 | #import "VuforiaManager.h" 10 | #import 11 | #import 12 | #import 13 | #import 14 | #import 15 | #import 16 | #import 17 | #import 18 | #import 19 | #import 20 | #import 21 | 22 | #define DEBUG_SAMPLE_APP 1 23 | 24 | @interface VuforiaFrame () 25 | - (instancetype)initWithFrame:(Vuforia::Frame)frame; 26 | @end 27 | 28 | @interface VuforiaTrackable () 29 | - (instancetype)initWithTrackable:(const Vuforia::Trackable*)trackable; 30 | @end 31 | 32 | @interface VuforiaTrackableResult () 33 | - (instancetype)initWithTrackableResult:(const Vuforia::TrackableResult*)result; 34 | @end 35 | 36 | @interface VuforiaState () 37 | - (instancetype)initWithState:(Vuforia::State*)state; 38 | @end 39 | 40 | namespace { 41 | // --- Data private to this unit --- 42 | 43 | // instance of the seesion 44 | // used to support the Vuforia callback 45 | // there should be only one instance of a session 46 | // at any given point of time 47 | VuforiaManager* instance = nil; 48 | 49 | // Vuforia initialisation flags (passed to Vuforia before initialising) 50 | int mVuforiaInitFlags = Vuforia::GL_20; 51 | 52 | // camera to use for the session 53 | Vuforia::CameraDevice::CAMERA_DIRECTION mCamera = Vuforia::CameraDevice::CAMERA_DIRECTION_DEFAULT; 54 | 55 | // class used to support the Vuforia callback mechanism 56 | class VuforiaApplication_UpdateCallback : public Vuforia::UpdateCallback { 57 | virtual void Vuforia_onUpdate(Vuforia::State& state); 58 | } vuforiaUpdate; 59 | 60 | // NSerror domain for errors coming from the Sample application template classes 61 | NSString* VUFORIA_MANAGER_ERROR_DOMAIN = @"vuforia_manager"; 62 | } 63 | 64 | #pragma mark - VuforiaManager 65 | @implementation VuforiaManager { 66 | NSString* _licenseKey; 67 | NSString* _dataSetFile; 68 | 69 | Vuforia::DataSet* _dataSet; 70 | 71 | BOOL _isCameraActive; 72 | BOOL _isCameraStarted; 73 | BOOL _isRetinaDisplay; 74 | UIInterfaceOrientation _arViewOrientation; 75 | BOOL _isActivityInPortraitMode; 76 | 77 | BOOL _extendedTrackingEnabled; 78 | BOOL _continuousAutofocusEnabled; 79 | BOOL _flashEnabled; 80 | BOOL _frontCameraEnabled; 81 | 82 | VuforiaEAGLView* _eaglView; 83 | } 84 | 85 | - (instancetype)init { 86 | [NSException raise:NSGenericException 87 | format:@"Disabled. Use +[[%@ alloc] %@] instead", 88 | NSStringFromClass([self class]), 89 | NSStringFromSelector(@selector(initWithLicenseKey:dataSetFile:))]; 90 | return nil; 91 | } 92 | 93 | - (instancetype)initWithLicenseKey:(NSString *)licenseKey dataSetFile:(NSString *)path { 94 | if(self = [super init]) { 95 | _licenseKey = licenseKey; 96 | _dataSetFile = path; 97 | instance = self; 98 | 99 | [[NSNotificationCenter defaultCenter] addObserver:self 100 | selector:@selector(didReceiveDidEnterBackgroundNotification:) 101 | name:UIApplicationDidEnterBackgroundNotification object:nil]; 102 | } 103 | return self; 104 | } 105 | 106 | - (void)dealloc { 107 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 108 | } 109 | 110 | - (VuforiaEAGLView*)eaglView { 111 | if(!_eaglView) { 112 | CGSize size = [self preferredARFrameSize]; 113 | _eaglView = [[VuforiaEAGLView alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height) manager:self]; 114 | } 115 | return _eaglView; 116 | } 117 | 118 | - (CGSize)preferredARFrameSize 119 | { 120 | CGRect screenBounds = [[UIScreen mainScreen] bounds]; 121 | CGRect viewFrame = screenBounds; 122 | 123 | // If this device has a retina display, scale the view bounds 124 | // for the AR (OpenGL) view 125 | if ([self isRetinaDisplay]) { 126 | viewFrame.size.width *= [UIScreen mainScreen].nativeScale; 127 | viewFrame.size.height *= [UIScreen mainScreen].nativeScale; 128 | } 129 | return viewFrame.size; 130 | } 131 | 132 | - (BOOL)continuousAutofocusEnabled { 133 | return _continuousAutofocusEnabled; 134 | } 135 | 136 | - (BOOL)setContinuousAutofocusEnabled:(BOOL)enabled { 137 | int focusMode = enabled ? Vuforia::CameraDevice::FOCUS_MODE_CONTINUOUSAUTO : Vuforia::CameraDevice::FOCUS_MODE_NORMAL; 138 | BOOL result = Vuforia::CameraDevice::getInstance().setFocusMode(focusMode); 139 | _continuousAutofocusEnabled = enabled && result; 140 | return result; 141 | } 142 | 143 | - (BOOL)flashEnabled { 144 | return _flashEnabled; 145 | } 146 | 147 | - (BOOL)setFlashEnabled:(BOOL)enabled { 148 | BOOL result = Vuforia::CameraDevice::getInstance().setFlashTorchMode(enabled); 149 | _flashEnabled = enabled && result; 150 | return result; 151 | } 152 | 153 | - (BOOL)frontCameraEnabled { 154 | return _frontCameraEnabled; 155 | } 156 | 157 | - (BOOL)setFrontCameraEnabled:(BOOL)enabled { 158 | NSError* error = nil; 159 | if ([self stopCamera:&error]) { 160 | Vuforia::CameraDevice::CAMERA_DIRECTION camera = enabled ? Vuforia::CameraDevice::CAMERA_DIRECTION_FRONT : Vuforia::CameraDevice::CAMERA_DIRECTION_BACK; 161 | BOOL result = [self startWithCamera:camera error:&error]; 162 | _frontCameraEnabled = result; 163 | if (_frontCameraEnabled) { 164 | // Switch Flash toggle OFF, in case it was previously ON, 165 | // as the front camera does not support flash 166 | _flashEnabled = NO; 167 | } 168 | return result; 169 | } else { 170 | return NO; 171 | } 172 | } 173 | 174 | - (BOOL)isCameraStarted { 175 | return _isCameraStarted; 176 | } 177 | 178 | 179 | #pragma mark - build a NSError 180 | - (NSError*) buildErrorWithCode:(int) code { 181 | return [NSError errorWithDomain:VUFORIA_MANAGER_ERROR_DOMAIN code:code userInfo:nil]; 182 | } 183 | 184 | - (NSError*) buildErrorWithCode:(NSString *) description code:(NSInteger)code { 185 | NSDictionary *userInfo = @{ 186 | NSLocalizedDescriptionKey: description 187 | }; 188 | return [NSError errorWithDomain:VUFORIA_MANAGER_ERROR_DOMAIN 189 | code:code 190 | userInfo:userInfo]; 191 | } 192 | 193 | - (NSError*) buildErrorWithCode:(int) code error:(NSError **) error{ 194 | if (error != NULL) { 195 | *error = [self buildErrorWithCode:code]; 196 | return *error; 197 | } 198 | return nil; 199 | } 200 | 201 | // Determine whether the device has a retina display 202 | - (BOOL)isRetinaDisplay 203 | { 204 | // If UIScreen mainScreen responds to selector 205 | // displayLinkWithTarget:selector: and the scale property is larger than 1.0, then this 206 | // is a retina display 207 | return ([[UIScreen mainScreen] respondsToSelector:@selector(displayLinkWithTarget:selector:)] && 1.0 < [UIScreen mainScreen].scale); 208 | } 209 | 210 | #pragma mark - Prepare 211 | - (void) prepareWithOrientation:(UIInterfaceOrientation)orientation { 212 | _isCameraActive = NO; 213 | _isCameraStarted = NO; 214 | _isRetinaDisplay = [self isRetinaDisplay]; 215 | _arViewOrientation = orientation; 216 | 217 | // Initialising Vuforia is a potentially lengthy operation, so perform it on a 218 | // background thread 219 | [self performSelectorInBackground:@selector(prepareInBackground) withObject:nil]; 220 | } 221 | 222 | // Setup Vuforia 223 | // (Performed on a background thread) 224 | - (void)prepareInBackground 225 | { 226 | // Background thread must have its own autorelease pool 227 | @autoreleasepool { 228 | Vuforia::setInitParameters(mVuforiaInitFlags, [_licenseKey cStringUsingEncoding:NSUTF8StringEncoding]); 229 | 230 | // Vuforia::init() will return positive numbers up to 100 as it progresses 231 | // towards success. Negative numbers indicate error conditions 232 | NSInteger initSuccess = 0; 233 | do { 234 | initSuccess = Vuforia::init(); 235 | } while (0 <= initSuccess && 100 > initSuccess); 236 | 237 | if (100 == initSuccess) { 238 | // We can now continue the initialization of Vuforia 239 | // (on the main thread) 240 | [self performSelectorOnMainThread:@selector(prepareAR) withObject:nil waitUntilDone:NO]; 241 | } 242 | else { 243 | NSError* error = nil; 244 | switch(initSuccess) { 245 | case Vuforia::INIT_LICENSE_ERROR_NO_NETWORK_TRANSIENT: 246 | error = [self buildErrorWithCode:NSLocalizedString(@"VUFORIA_ERROR_NO_NETWORK_TRANSIENT", nil) code:initSuccess]; 247 | break; 248 | 249 | case Vuforia::INIT_LICENSE_ERROR_NO_NETWORK_PERMANENT: 250 | error = [self buildErrorWithCode:NSLocalizedString(@"VUFORIA_ERROR_NO_NETWORK_PERMANENT", nil) code:initSuccess]; 251 | break; 252 | 253 | case Vuforia::INIT_LICENSE_ERROR_INVALID_KEY: 254 | error = [self buildErrorWithCode:NSLocalizedString(@"VUFORIA_ERROR_INVALID_KEY", nil) code:initSuccess]; 255 | break; 256 | 257 | case Vuforia::INIT_LICENSE_ERROR_CANCELED_KEY: 258 | error = [self buildErrorWithCode:NSLocalizedString(@"VUFORIA_ERROR_CANCELED_KEY", nil) code:initSuccess]; 259 | break; 260 | 261 | case Vuforia::INIT_LICENSE_ERROR_MISSING_KEY: 262 | error = [self buildErrorWithCode:NSLocalizedString(@"VUFORIA_ERROR_MISSING_KEY", nil) code:initSuccess]; 263 | break; 264 | 265 | case Vuforia::INIT_LICENSE_ERROR_PRODUCT_TYPE_MISMATCH: 266 | error = [self buildErrorWithCode:NSLocalizedString(@"VUFORIA_ERROR_PRODUCT_TYPE_MISMATCH", nil) code:initSuccess]; 267 | break; 268 | 269 | default: 270 | error = [self buildErrorWithCode:NSLocalizedString(@"VUFORIA_ERROR_UNKNOWN", nil) code:initSuccess]; 271 | break; 272 | 273 | } 274 | // Vuforia initialization error 275 | dispatch_async(dispatch_get_main_queue(), ^{ 276 | [self.delegate vuforiaManager:self didFailToPreparingWithError:error]; 277 | }); 278 | } 279 | } 280 | } 281 | 282 | - (void)prepareAR { 283 | // we register for the Vuforia callback 284 | Vuforia::registerCallback(&vuforiaUpdate); 285 | 286 | // Tell Vuforia we've created a drawing surface 287 | Vuforia::onSurfaceCreated(); 288 | 289 | CGSize viewBoundsSize = self.preferredARFrameSize; 290 | int smallerSize = MIN(viewBoundsSize.width, viewBoundsSize.height); 291 | int largerSize = MAX(viewBoundsSize.width, viewBoundsSize.height); 292 | 293 | // Frames from the camera are always landscape, no matter what the 294 | // orientation of the device. Tell Vuforia to rotate the video background (and 295 | // the projection matrix it provides to us for rendering our augmentation) 296 | // by the proper angle in order to match the EAGLView orientation 297 | if (_arViewOrientation == UIInterfaceOrientationPortrait) 298 | { 299 | Vuforia::onSurfaceChanged(smallerSize, largerSize); 300 | Vuforia::setRotation(Vuforia::ROTATE_IOS_90); 301 | 302 | _isActivityInPortraitMode = YES; 303 | } 304 | else if (_arViewOrientation == UIInterfaceOrientationPortraitUpsideDown) 305 | { 306 | Vuforia::onSurfaceChanged(smallerSize, largerSize); 307 | Vuforia::setRotation(Vuforia::ROTATE_IOS_270); 308 | 309 | _isActivityInPortraitMode = YES; 310 | } 311 | else if (_arViewOrientation == UIInterfaceOrientationLandscapeLeft) 312 | { 313 | Vuforia::onSurfaceChanged(largerSize, smallerSize); 314 | Vuforia::setRotation(Vuforia::ROTATE_IOS_180); 315 | 316 | _isActivityInPortraitMode = NO; 317 | } 318 | else if (_arViewOrientation == UIInterfaceOrientationLandscapeRight) 319 | { 320 | Vuforia::onSurfaceChanged(largerSize, smallerSize); 321 | Vuforia::setRotation(Vuforia::ROTATE_IOS_0); 322 | 323 | _isActivityInPortraitMode = NO; 324 | } 325 | 326 | [self initTracker]; 327 | } 328 | 329 | - (void)initTracker { 330 | Vuforia::TrackerManager& trackerManager = Vuforia::TrackerManager::getInstance(); 331 | Vuforia::Tracker* trackerBase = trackerManager.initTracker(Vuforia::ObjectTracker::getClassType()); 332 | if (trackerBase == NULL) 333 | { 334 | [self.delegate vuforiaManager: self didFailToPreparingWithError:[self buildErrorWithCode:VuforiaError_InitTrackers]]; 335 | return; 336 | } 337 | [self loadTrackerData]; 338 | } 339 | 340 | 341 | - (void)loadTrackerData { 342 | // Loading tracker data is a potentially lengthy operation, so perform it on 343 | // a background thread 344 | [self performSelectorInBackground:@selector(loadTrackerDataInBackground) withObject:nil]; 345 | } 346 | 347 | // *** Performed on a background thread *** 348 | - (void)loadTrackerDataInBackground 349 | { 350 | // Background thread must have its own autorelease pool 351 | @autoreleasepool { 352 | Vuforia::DataSet* dataSet = [self loadObjectTrackerDataSet:_dataSetFile]; 353 | if(dataSet == NULL) { 354 | [self.delegate vuforiaManager:self didFailToPreparingWithError:[self buildErrorWithCode:VuforiaError_LoadingTrackersData]]; 355 | return; 356 | } 357 | 358 | if(![self activateDataSet:dataSet]) { 359 | [self.delegate vuforiaManager:self didFailToPreparingWithError:[self buildErrorWithCode:VuforiaError_LoadingTrackersData]]; 360 | return; 361 | } 362 | } 363 | 364 | [self.delegate vuforiaManagerDidFinishPreparing:self]; 365 | } 366 | 367 | // Load the image tracker data set 368 | - (Vuforia::DataSet *)loadObjectTrackerDataSet:(NSString*)dataFile 369 | { 370 | NSLog(@"loadObjectTrackerDataSet (%@)", dataFile); 371 | Vuforia::DataSet* dataSet = NULL; 372 | 373 | // Get the Vuforia tracker manager image tracker 374 | Vuforia::TrackerManager& trackerManager = Vuforia::TrackerManager::getInstance(); 375 | Vuforia::ObjectTracker* objectTracker = static_cast(trackerManager.getTracker(Vuforia::ObjectTracker::getClassType())); 376 | 377 | if (NULL == objectTracker) { 378 | NSLog(@"ERROR: failed to get the ObjectTracker from the tracker manager"); 379 | return NULL; 380 | } else { 381 | dataSet = objectTracker->createDataSet(); 382 | 383 | if (NULL != dataSet) { 384 | NSLog(@"INFO: successfully loaded data set"); 385 | 386 | // Load the data set from the app's resources location 387 | if (!dataSet->load([dataFile cStringUsingEncoding:NSASCIIStringEncoding], Vuforia::STORAGE_APPRESOURCE)) { 388 | NSLog(@"ERROR: failed to load data set"); 389 | objectTracker->destroyDataSet(dataSet); 390 | dataSet = NULL; 391 | } 392 | } 393 | else { 394 | NSLog(@"ERROR: failed to create data set"); 395 | } 396 | } 397 | 398 | return dataSet; 399 | } 400 | 401 | - (BOOL)activateDataSet:(Vuforia::DataSet *)theDataSet 402 | { 403 | // if we've previously recorded an activation, deactivate it 404 | if (_dataSet != nil) 405 | { 406 | [self deactivateDataSet:_dataSet]; 407 | } 408 | BOOL success = NO; 409 | 410 | // Get the image tracker: 411 | Vuforia::TrackerManager& trackerManager = Vuforia::TrackerManager::getInstance(); 412 | Vuforia::ObjectTracker* objectTracker = static_cast(trackerManager.getTracker(Vuforia::ObjectTracker::getClassType())); 413 | 414 | if (objectTracker == NULL) { 415 | NSLog(@"Failed to load tracking data set because the ObjectTracker has not been initialized."); 416 | } 417 | else 418 | { 419 | // Activate the data set: 420 | if (!objectTracker->activateDataSet(theDataSet)) 421 | { 422 | NSLog(@"Failed to activate data set."); 423 | } 424 | else 425 | { 426 | NSLog(@"Successfully activated data set."); 427 | _dataSet = theDataSet; 428 | success = YES; 429 | } 430 | } 431 | 432 | return success; 433 | } 434 | 435 | - (BOOL)deactivateDataSet:(Vuforia::DataSet *)theDataSet 436 | { 437 | if ((_dataSet == nil) || (theDataSet != _dataSet)) 438 | { 439 | NSLog(@"Invalid request to deactivate data set."); 440 | return NO; 441 | } 442 | 443 | BOOL success = NO; 444 | 445 | // Get the image tracker: 446 | Vuforia::TrackerManager& trackerManager = Vuforia::TrackerManager::getInstance(); 447 | Vuforia::ObjectTracker* objectTracker = static_cast(trackerManager.getTracker(Vuforia::ObjectTracker::getClassType())); 448 | 449 | if (objectTracker == NULL) 450 | { 451 | NSLog(@"Failed to unload tracking data set because the ObjectTracker has not been initialized."); 452 | } 453 | else 454 | { 455 | // Activate the data set: 456 | if (!objectTracker->deactivateDataSet(theDataSet)) 457 | { 458 | NSLog(@"Failed to deactivate data set."); 459 | } 460 | else 461 | { 462 | success = YES; 463 | } 464 | } 465 | 466 | return success; 467 | } 468 | 469 | // Configure Vuforia with the video background size 470 | - (void)configureVideoBackgroundWithViewWidth:(float)viewWidth andHeight:(float)viewHeight 471 | { 472 | // Get the default video mode 473 | Vuforia::CameraDevice& cameraDevice = Vuforia::CameraDevice::getInstance(); 474 | Vuforia::VideoMode videoMode = cameraDevice.getVideoMode(Vuforia::CameraDevice::MODE_DEFAULT); 475 | 476 | // Configure the video background 477 | Vuforia::VideoBackgroundConfig config; 478 | config.mPosition.data[0] = 0.0f; 479 | config.mPosition.data[1] = 0.0f; 480 | 481 | // Determine the orientation of the view. Note, this simple test assumes 482 | // that a view is portrait if its height is greater than its width. This is 483 | // not always true: it is perfectly reasonable for a view with portrait 484 | // orientation to be wider than it is high. The test is suitable for the 485 | // dimensions used in this sample 486 | if (_isActivityInPortraitMode) { 487 | // --- View is portrait --- 488 | 489 | // Compare aspect ratios of video and screen. If they are different we 490 | // use the full screen size while maintaining the video's aspect ratio, 491 | // which naturally entails some cropping of the video 492 | float aspectRatioVideo = (float)videoMode.mWidth / (float)videoMode.mHeight; 493 | float aspectRatioView = viewHeight / viewWidth; 494 | 495 | if (aspectRatioVideo < aspectRatioView) { 496 | // Video (when rotated) is wider than the view: crop left and right 497 | // (top and bottom of video) 498 | 499 | // --============-- 500 | // - = = _ 501 | // - = = _ 502 | // - = = _ 503 | // - = = _ 504 | // - = = _ 505 | // - = = _ 506 | // - = = _ 507 | // - = = _ 508 | // --============-- 509 | 510 | config.mSize.data[0] = (int)videoMode.mHeight * (viewHeight / (float)videoMode.mWidth); 511 | config.mSize.data[1] = (int)viewHeight; 512 | } 513 | else { 514 | // Video (when rotated) is narrower than the view: crop top and 515 | // bottom (left and right of video). Also used when aspect ratios 516 | // match (no cropping) 517 | 518 | // ------------ 519 | // - - 520 | // - - 521 | // ============ 522 | // = = 523 | // = = 524 | // = = 525 | // = = 526 | // = = 527 | // = = 528 | // = = 529 | // = = 530 | // ============ 531 | // - - 532 | // - - 533 | // ------------ 534 | 535 | config.mSize.data[0] = (int)viewWidth; 536 | config.mSize.data[1] = (int)videoMode.mWidth * (viewWidth / (float)videoMode.mHeight); 537 | } 538 | 539 | } 540 | else { 541 | // --- View is landscape --- 542 | if (viewWidth < viewHeight) { 543 | // Swap width/height: this is neded on iOS7 and below 544 | // as the view width is always reported as if in portrait. 545 | // On IOS 8, the swap is not needed, because the size is 546 | // orientation-dependent; so, this swap code in practice 547 | // will only be executed on iOS 7 and below. 548 | float temp = viewWidth; 549 | viewWidth = viewHeight; 550 | viewHeight = temp; 551 | } 552 | 553 | // Compare aspect ratios of video and screen. If they are different we 554 | // use the full screen size while maintaining the video's aspect ratio, 555 | // which naturally entails some cropping of the video 556 | float aspectRatioVideo = (float)videoMode.mWidth / (float)videoMode.mHeight; 557 | float aspectRatioView = viewWidth / viewHeight; 558 | 559 | if (aspectRatioVideo < aspectRatioView) { 560 | // Video is taller than the view: crop top and bottom 561 | 562 | // -------------------- 563 | // ==================== 564 | // = = 565 | // = = 566 | // = = 567 | // = = 568 | // ==================== 569 | // -------------------- 570 | 571 | config.mSize.data[0] = (int)viewWidth; 572 | config.mSize.data[1] = (int)videoMode.mHeight * (viewWidth / (float)videoMode.mWidth); 573 | } 574 | else { 575 | // Video is wider than the view: crop left and right. Also used 576 | // when aspect ratios match (no cropping) 577 | 578 | // ---====================--- 579 | // - = = - 580 | // - = = - 581 | // - = = - 582 | // - = = - 583 | // ---====================--- 584 | 585 | config.mSize.data[0] = (int)videoMode.mWidth * (viewHeight / (float)videoMode.mHeight); 586 | config.mSize.data[1] = (int)viewHeight; 587 | } 588 | 589 | } 590 | 591 | #ifdef DEBUG_SAMPLE_APP 592 | NSLog(@"VideoBackgroundConfig: size: %d,%d", config.mSize.data[0], config.mSize.data[1]); 593 | NSLog(@"VideoMode:w=%d h=%d", videoMode.mWidth, videoMode.mHeight); 594 | NSLog(@"width=%7.3f height=%7.3f", viewWidth, viewHeight); 595 | #endif 596 | 597 | // Set the config 598 | Vuforia::Renderer::getInstance().setVideoBackgroundConfig(config); 599 | } 600 | 601 | #pragma mark - Start 602 | - (BOOL)start:(NSError **)error { 603 | Vuforia::CameraDevice::CAMERA_DIRECTION camera = _frontCameraEnabled ? Vuforia::CameraDevice::CAMERA_DIRECTION_FRONT : Vuforia::CameraDevice::CAMERA_DIRECTION_BACK; 604 | 605 | return [self startWithCamera:camera error:error]; 606 | } 607 | 608 | - (BOOL)startWithCamera:(Vuforia::CameraDevice::CAMERA_DIRECTION)camera error:(NSError**)error { 609 | CGSize ARViewBoundsSize = self.preferredARFrameSize; 610 | 611 | // Start the camera. This causes Vuforia to locate our EAGLView in the view 612 | // hierarchy, start a render thread, and then call renderFrameVuforia on the 613 | // view periodically 614 | if (! [self startCamera:camera viewWidth:ARViewBoundsSize.width andHeight:ARViewBoundsSize.height error:error]) { 615 | return NO; 616 | } 617 | _isCameraActive = YES; 618 | _isCameraStarted = YES; 619 | 620 | return YES; 621 | } 622 | 623 | // Start Vuforia camera with the specified view size 624 | - (BOOL)startCamera:(Vuforia::CameraDevice::CAMERA_DIRECTION)camera viewWidth:(float)viewWidth andHeight:(float)viewHeight error:(NSError **)error 625 | { 626 | // initialize the camera 627 | if (! Vuforia::CameraDevice::getInstance().init(camera)) { 628 | [self buildErrorWithCode:VuforiaError_InitializingCamera error:error]; 629 | return NO; 630 | } 631 | 632 | // select the default video mode 633 | if(! Vuforia::CameraDevice::getInstance().selectVideoMode(Vuforia::CameraDevice::MODE_DEFAULT)) { 634 | [self buildErrorWithCode:VuforiaError_InitializingCamera error:error]; 635 | return NO; 636 | } 637 | 638 | // configure Vuforia video background 639 | [self configureVideoBackgroundWithViewWidth:viewWidth andHeight:viewHeight]; 640 | 641 | // start the camera 642 | if (!Vuforia::CameraDevice::getInstance().start()) { 643 | [self buildErrorWithCode:VuforiaError_StartingCamera error:error]; 644 | return NO; 645 | } 646 | 647 | // we keep track of the current camera to restart this 648 | // camera when the application comes back to the foreground 649 | mCamera = camera; 650 | 651 | // ask the application to start the tracker(s) 652 | Vuforia::TrackerManager& trackerManager = Vuforia::TrackerManager::getInstance(); 653 | Vuforia::Tracker* tracker = trackerManager.getTracker(Vuforia::ObjectTracker::getClassType()); 654 | if(tracker == 0) { 655 | [self buildErrorWithCode:VuforiaError_StartingTrackers error:error]; 656 | return NO; 657 | } 658 | tracker->start(); 659 | 660 | return YES; 661 | } 662 | 663 | #pragma mark - Stop 664 | // Stop Vuforia camera 665 | - (BOOL)stop:(NSError **)error { 666 | // Stop the camera 667 | if (_isCameraActive) { 668 | // Stop and deinit the camera 669 | Vuforia::CameraDevice::getInstance().stop(); 670 | Vuforia::CameraDevice::getInstance().deinit(); 671 | _isCameraActive = NO; 672 | } 673 | _isCameraStarted = NO; 674 | 675 | // Stop the tracker 676 | if(! [self stopTrackers]) { 677 | [self buildErrorWithCode:VuforiaError_StoppingTrackers error:error]; 678 | return NO; 679 | } 680 | 681 | // Unload TrackersData 682 | [self deactivateDataSet: _dataSet]; 683 | 684 | // Get the image tracker: 685 | Vuforia::TrackerManager& trackerManager = Vuforia::TrackerManager::getInstance(); 686 | Vuforia::ObjectTracker* objectTracker = static_cast(trackerManager.getTracker(Vuforia::ObjectTracker::getClassType())); 687 | 688 | // Destroy the data sets: 689 | if (!objectTracker->destroyDataSet(_dataSet)) 690 | { 691 | NSLog(@"Failed to destroy data set"); 692 | [self buildErrorWithCode:VuforiaError_UnloadingTrackersData error:error]; 693 | }else { 694 | NSLog(@"datasets destroyed"); 695 | } 696 | 697 | _dataSet = nil; 698 | 699 | // Deinit Trackers 700 | trackerManager.deinitTracker(Vuforia::ObjectTracker::getClassType()); 701 | 702 | // Pause and deinitialise Vuforia 703 | Vuforia::onPause(); 704 | Vuforia::deinit(); 705 | 706 | [_eaglView finishOpenGLESCommands]; 707 | 708 | return YES; 709 | } 710 | 711 | // stop the tracker 712 | - (BOOL) stopTrackers { 713 | // Stop the tracker 714 | Vuforia::TrackerManager& trackerManager = Vuforia::TrackerManager::getInstance(); 715 | Vuforia::Tracker* tracker = trackerManager.getTracker(Vuforia::ObjectTracker::getClassType()); 716 | 717 | if (NULL != tracker) { 718 | tracker->stop(); 719 | NSLog(@"INFO: successfully stopped tracker"); 720 | return YES; 721 | } 722 | else { 723 | NSLog(@"ERROR: failed to get the tracker from the tracker manager"); 724 | return NO; 725 | } 726 | } 727 | 728 | // stop the camera 729 | - (BOOL) stopCamera:(NSError **)error { 730 | if (_isCameraActive) { 731 | // Stop and deinit the camera 732 | Vuforia::CameraDevice::getInstance().stop(); 733 | Vuforia::CameraDevice::getInstance().deinit(); 734 | _isCameraActive = NO; 735 | } else { 736 | [self buildErrorWithCode:VuforiaError_CameraNotStarted error:error]; 737 | return NO; 738 | } 739 | _isCameraStarted = NO; 740 | 741 | // Stop the trackers 742 | if(! [self stopTrackers]) { 743 | [self buildErrorWithCode:VuforiaError_StoppingTrackers error:error]; 744 | return NO; 745 | } 746 | 747 | return YES; 748 | } 749 | 750 | #pragma mark - Resume 751 | - (BOOL)resume:(NSError **)error { 752 | Vuforia::onResume(); 753 | 754 | // if the camera was previously started, but not currently active, then 755 | // we restart it 756 | if ((_isCameraStarted) && (! _isCameraActive)) { 757 | 758 | // initialize the camera 759 | if (! Vuforia::CameraDevice::getInstance().init(mCamera)) { 760 | [self buildErrorWithCode:VuforiaError_InitializingCamera error:error]; 761 | return NO; 762 | } 763 | 764 | // start the camera 765 | if (!Vuforia::CameraDevice::getInstance().start()) { 766 | [self buildErrorWithCode:VuforiaError_StartingCamera error:error]; 767 | return NO; 768 | } 769 | 770 | _isCameraActive = YES; 771 | } 772 | return YES; 773 | } 774 | 775 | 776 | #pragma mark - Pause 777 | - (BOOL)pause:(NSError **)error { 778 | if (_isCameraActive) { 779 | // Stop and deinit the camera 780 | if(! Vuforia::CameraDevice::getInstance().stop()) { 781 | [self buildErrorWithCode:VuforiaError_StoppingCamera error:error]; 782 | return NO; 783 | } 784 | if(! Vuforia::CameraDevice::getInstance().deinit()) { 785 | [self buildErrorWithCode:VuforiaError_DeinitCamara error:error]; 786 | return NO; 787 | } 788 | _isCameraActive = NO; 789 | } 790 | Vuforia::onPause(); 791 | return YES; 792 | } 793 | 794 | #pragma mark - 795 | - (void)didReceiveDidEnterBackgroundNotification:(NSNotification*)notification { 796 | [_eaglView freeOpenGLESResources]; 797 | [_eaglView finishOpenGLESCommands]; 798 | } 799 | 800 | #pragma mark - Vuforia Callback 801 | - (void) Vuforia_onUpdate:(Vuforia::State *) state { 802 | if ((self.delegate != nil) && [self.delegate respondsToSelector:@selector(vuforiaManager:didUpdateWithState:)]) { 803 | [self.delegate vuforiaManager:self didUpdateWithState:[[VuforiaState alloc] initWithState:state]]; 804 | } 805 | } 806 | 807 | //////////////////////////////////////////////////////////////////////////////// 808 | // Callback function called by the tracker when each tracking cycle has finished 809 | void VuforiaApplication_UpdateCallback::Vuforia_onUpdate(Vuforia::State& state) 810 | { 811 | if (instance != nil) { 812 | [instance Vuforia_onUpdate:&state]; 813 | } 814 | } 815 | 816 | 817 | @end 818 | -------------------------------------------------------------------------------- /VuforiaSampleSwift/VuforiaManager/VuforiaObjects.h: -------------------------------------------------------------------------------- 1 | // 2 | // VuforiaObjects.h 3 | // VuforiaSampleSwift 4 | // 5 | // Created by Yoshihiro Kato on 2016/07/02. 6 | // Copyright © 2016年 Yoshihiro Kato. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef NS_ENUM(NSUInteger, VuforiaTrackableResultStatus) { 12 | VuforiaTrackableResultStatus_Unknown, ///< The state of the TrackableResult is unknown 13 | VuforiaTrackableResultStatus_No_Pose, ///< 14 | VuforiaTrackableResultStatus_Limited, ///< 15 | VuforiaTrackableResultStatus_Detected, ///< The TrackableResult was detected 16 | VuforiaTrackableResultStatus_Tracked, ///< The TrackableResult was tracked 17 | VuforiaTrackableResultStatus_Extended_tracked ///< The Trackable Result was extended tracked 18 | }; 19 | 20 | @interface VuforiaFrame : NSObject 21 | @end 22 | 23 | @interface VuforiaTrackable : NSObject 24 | 25 | @property (nonatomic, readonly)NSInteger identifier; 26 | @property (nonatomic, readonly)NSString* name; 27 | 28 | @end 29 | 30 | @interface VuforiaTrackableResult : NSObject 31 | 32 | @property (nonatomic, readonly)NSTimeInterval timeStamp; 33 | @property (nonatomic, readonly)VuforiaTrackableResultStatus status; 34 | @property (nonatomic, readonly)VuforiaTrackable* trackable; 35 | 36 | @end 37 | 38 | @interface VuforiaState : NSObject 39 | 40 | @property (nonatomic, readonly)VuforiaFrame* frame; 41 | @property (nonatomic, readonly)int numberOfTrackables; 42 | @property (nonatomic, readonly)int numberOfTrackableResults; 43 | 44 | 45 | - (VuforiaTrackable*)trackableAtIndex:(int)index; 46 | - (VuforiaTrackableResult*)trackableResultAtIndex:(int)index; 47 | 48 | @end 49 | 50 | -------------------------------------------------------------------------------- /VuforiaSampleSwift/VuforiaManager/VuforiaObjects.mm: -------------------------------------------------------------------------------- 1 | // 2 | // VuforiaObjects.m 3 | // VuforiaSampleSwift 4 | // 5 | // Created by Yoshihiro Kato on 2016/07/02. 6 | // Copyright © 2016年 Yoshihiro Kato. All rights reserved. 7 | // 8 | 9 | #import "VuforiaObjects.h" 10 | #import 11 | #import 12 | #import 13 | 14 | @implementation VuforiaFrame { 15 | Vuforia::Frame _frame; 16 | } 17 | 18 | - (instancetype)initWithFrame:(Vuforia::Frame)frame { 19 | if(self = [super init]) { 20 | _frame = frame; 21 | } 22 | return self; 23 | } 24 | 25 | @end 26 | 27 | @implementation VuforiaTrackable { 28 | const Vuforia::Trackable* _trackable; 29 | } 30 | 31 | - (instancetype)initWithTrackable:(const Vuforia::Trackable*)trackable { 32 | if(self = [super init]) { 33 | _trackable = trackable; 34 | } 35 | return self; 36 | } 37 | 38 | - (NSInteger)identifier { 39 | return _trackable->getId(); 40 | } 41 | 42 | - (NSString*)name { 43 | return [NSString stringWithCString:_trackable->getName() encoding:NSUTF8StringEncoding]; 44 | } 45 | 46 | @end 47 | 48 | @implementation VuforiaTrackableResult { 49 | const Vuforia::TrackableResult* _result; 50 | } 51 | 52 | - (instancetype)initWithTrackableResult:(const Vuforia::TrackableResult*)result { 53 | if(self = [super init]) { 54 | _result = result; 55 | } 56 | return self; 57 | } 58 | 59 | - (NSTimeInterval)timeStamp { 60 | return _result->getTimeStamp(); 61 | } 62 | 63 | - (VuforiaTrackableResultStatus)status { 64 | switch (_result->getStatus()) { 65 | case Vuforia::TrackableResult::STATUS::NO_POSE: 66 | return VuforiaTrackableResultStatus_No_Pose; 67 | case Vuforia::TrackableResult::STATUS::LIMITED: 68 | return VuforiaTrackableResultStatus_Limited; 69 | case Vuforia::TrackableResult::STATUS::DETECTED: 70 | return VuforiaTrackableResultStatus_Detected; 71 | case Vuforia::TrackableResult::STATUS::TRACKED: 72 | return VuforiaTrackableResultStatus_Tracked; 73 | case Vuforia::TrackableResult::STATUS::EXTENDED_TRACKED: 74 | return VuforiaTrackableResultStatus_Extended_tracked; 75 | default: 76 | return VuforiaTrackableResultStatus_Unknown; 77 | } 78 | } 79 | 80 | - (VuforiaTrackable*)trackable { 81 | return [[VuforiaTrackable alloc] initWithTrackable:&_result->getTrackable()]; 82 | } 83 | 84 | @end 85 | 86 | @implementation VuforiaState { 87 | Vuforia::State* _state; 88 | 89 | VuforiaFrame* _frame; 90 | } 91 | 92 | - (instancetype)initWithState:(Vuforia::State*)state { 93 | if(self = [super init]) { 94 | _state = state; 95 | _frame = [[VuforiaFrame alloc] initWithFrame:_state->getFrame()]; 96 | } 97 | return self; 98 | } 99 | 100 | - (VuforiaFrame *)frame { 101 | return _frame; 102 | } 103 | 104 | - (int)numberOfTrackables { 105 | return _state->getNumTrackables(); 106 | } 107 | 108 | - (int)numberOfTrackableResults { 109 | return _state->getNumTrackableResults(); 110 | } 111 | 112 | - (VuforiaTrackable*)trackableAtIndex:(int)index { 113 | return [[VuforiaTrackable alloc] initWithTrackable:_state->getTrackable(index)]; 114 | } 115 | 116 | - (VuforiaTrackableResult*)trackableResultAtIndex:(int)index { 117 | return [[VuforiaTrackableResult alloc] initWithTrackableResult:_state->getTrackableResult(index)]; 118 | } 119 | 120 | @end 121 | -------------------------------------------------------------------------------- /VuforiaSampleSwift/VuforiaManager/VuforiaShaderUtils.h: -------------------------------------------------------------------------------- 1 | // 2 | // VuforiaShaderUtils.h 3 | // VuforiaSampleSwift 4 | // 5 | // Created by Yoshihiro Kato on 2016/07/03. 6 | // Copyright © 2016年 Yoshihiro Kato. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface VuforiaShaderUtils : NSObject 12 | 13 | + (int)createProgramWithVertexShaderFileName:(NSString*) vertexShaderFileName 14 | fragmentShaderFileName:(NSString*) fragmentShaderFileName; 15 | 16 | + (int)createProgramWithVertexShaderFileName:(NSString*) vertexShaderFileName 17 | withVertexShaderDefs:(NSString *) vertexShaderDefs 18 | fragmentShaderFileName:(NSString *) fragmentShaderFileName 19 | withFragmentShaderDefs:(NSString *) fragmentShaderDefs; 20 | 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /VuforiaSampleSwift/VuforiaManager/VuforiaShaderUtils.m: -------------------------------------------------------------------------------- 1 | // 2 | // VuforiaShaderUtils.m 3 | // VuforiaSampleSwift 4 | // 5 | // Created by Yoshihiro Kato on 2016/07/03. 6 | // Copyright © 2016年 Yoshihiro Kato. All rights reserved. 7 | // 8 | 9 | #import "VuforiaShaderUtils.h" 10 | #import 11 | 12 | @implementation VuforiaShaderUtils 13 | 14 | + (GLuint)compileShader:(NSString*)shaderFileName withDefs:(NSString *) defs withType:(GLenum)shaderType { 15 | NSString* shaderName = [[shaderFileName lastPathComponent] stringByDeletingPathExtension]; 16 | NSString* shaderFileType = [shaderFileName pathExtension]; 17 | 18 | NSLog(@"debug: shaderName=(%@), shaderFileTYpe=(%@)", shaderName, shaderFileType); 19 | 20 | // 1 21 | NSString* shaderPath = [[NSBundle mainBundle] pathForResource:shaderName ofType:shaderFileType]; 22 | NSLog(@"debug: shaderPath=(%@)", shaderPath); 23 | NSError* error; 24 | NSString* shaderString = [NSString stringWithContentsOfFile:shaderPath encoding:NSUTF8StringEncoding error:&error]; 25 | if (!shaderString) { 26 | NSLog(@"Error loading shader (%@): %@", shaderFileName, error.localizedDescription); 27 | return 0; 28 | } 29 | 30 | // 2 31 | GLuint shaderHandle = glCreateShader(shaderType); 32 | 33 | // 3 34 | const char * shaderStringUTF8 = [shaderString UTF8String]; 35 | GLint shaderStringLength = (GLint)[shaderString length]; 36 | 37 | if (defs == nil) { 38 | glShaderSource(shaderHandle, 1, &shaderStringUTF8, &shaderStringLength); 39 | } else { 40 | const char* finalShader[2] = {[defs UTF8String],shaderStringUTF8}; 41 | GLint finalShaderSizes[2] = {(GLint)[defs length], shaderStringLength}; 42 | glShaderSource(shaderHandle, 2, finalShader, finalShaderSizes); 43 | } 44 | 45 | // 4 46 | glCompileShader(shaderHandle); 47 | 48 | // 5 49 | GLint compileSuccess; 50 | glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compileSuccess); 51 | if (compileSuccess == GL_FALSE) { 52 | GLchar messages[256]; 53 | glGetShaderInfoLog(shaderHandle, sizeof(messages), 0, &messages[0]); 54 | NSString *messageString = [NSString stringWithUTF8String:messages]; 55 | NSLog(@"Error compiling shader (%@): %@", shaderFileName, messageString); 56 | return 0; 57 | } 58 | 59 | return shaderHandle; 60 | 61 | } 62 | 63 | + (int)createProgramWithVertexShaderFileName:(NSString*) vertexShaderFileName 64 | fragmentShaderFileName:(NSString *) fragmentShaderFileName { 65 | return [self createProgramWithVertexShaderFileName:vertexShaderFileName 66 | withVertexShaderDefs:nil 67 | fragmentShaderFileName:fragmentShaderFileName 68 | withFragmentShaderDefs:nil]; 69 | } 70 | 71 | + (int)createProgramWithVertexShaderFileName:(NSString*) vertexShaderFileName 72 | withVertexShaderDefs:(NSString *) vertexShaderDefs 73 | fragmentShaderFileName:(NSString *) fragmentShaderFileName 74 | withFragmentShaderDefs:(NSString *) fragmentShaderDefs { 75 | GLuint vertexShader = [self compileShader:vertexShaderFileName withDefs:vertexShaderDefs withType:GL_VERTEX_SHADER]; 76 | GLuint fragmentShader = [self compileShader:fragmentShaderFileName withDefs:fragmentShaderDefs withType:GL_FRAGMENT_SHADER]; 77 | 78 | if ((vertexShader == 0) || (fragmentShader == 0)) { 79 | NSLog(@"Error: error compiling shaders"); 80 | return 0; 81 | } 82 | 83 | GLuint programHandle = glCreateProgram(); 84 | 85 | if (programHandle == 0) { 86 | NSLog(@"Error: can't create programe"); 87 | return 0; 88 | } 89 | glAttachShader(programHandle, vertexShader); 90 | glAttachShader(programHandle, fragmentShader); 91 | glLinkProgram(programHandle); 92 | 93 | GLint linkSuccess; 94 | glGetProgramiv(programHandle, GL_LINK_STATUS, &linkSuccess); 95 | if (linkSuccess == GL_FALSE) { 96 | GLchar messages[256]; 97 | glGetProgramInfoLog(programHandle, sizeof(messages), 0, &messages[0]); 98 | NSString *messageString = [NSString stringWithUTF8String:messages]; 99 | NSLog(@"Error linkink shaders (%@) and (%@): %@", vertexShaderFileName, fragmentShaderFileName, messageString); 100 | return 0; 101 | } 102 | return programHandle; 103 | } 104 | 105 | 106 | @end 107 | -------------------------------------------------------------------------------- /VuforiaSampleSwift/VuforiaSampleSwift-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #import "VuforiaManager.h" -------------------------------------------------------------------------------- /screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yshrkt/VuforiaSampleSwift/f7d3cba45a683e7ec03854d80f7afad185328f2b/screenshot.jpg --------------------------------------------------------------------------------