├── .gitignore ├── ArtzyCamera.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── xcshareddata │ └── xcschemes │ │ └── ArtzyCamera.xcscheme └── xcuserdata │ └── oscardelaheragomez.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── ArtzyCamera ├── AppDelegate.swift ├── Assets.xcassets │ ├── AR Resources.arresourcegroup │ │ ├── Contents.json │ │ ├── artzy loader by delasign.arreferenceimage │ │ │ ├── 1024.png │ │ │ └── Contents.json │ │ ├── hand by delasign.arreferenceimage │ │ │ ├── Contents.json │ │ │ └── Hand-02.png │ │ ├── local by adamfu x delasign.arreferenceimage │ │ │ ├── Contents.json │ │ │ └── adamLocal-01.png │ │ └── mondriaan by delasign.arreferenceimage │ │ │ ├── Contents.json │ │ │ └── Painting@3x.png │ ├── AppIcon.appiconset │ │ ├── 1024.png │ │ ├── 20.png │ │ ├── 20@2x-1.png │ │ ├── 20@2x.png │ │ ├── 20@3x.png │ │ ├── 29.png │ │ ├── 29@2x-1.png │ │ ├── 29@2x.png │ │ ├── 29@3x.png │ │ ├── 40.png │ │ ├── 40@2x-1.png │ │ ├── 40@2x.png │ │ ├── 40@3x.png │ │ ├── 60@2x.png │ │ ├── 60@3x.png │ │ ├── 76.png │ │ ├── 76@2x.png │ │ ├── 83.5.png │ │ └── Contents.json │ ├── Contents.json │ ├── LaunchImage.launchimage │ │ ├── Contents.json │ │ ├── Ipad Portrait.png │ │ ├── Ipad Portrait@2x.png │ │ ├── Retina HD 5.5.png │ │ ├── Retine HD 4.7".png │ │ ├── XR.png │ │ ├── XS Max.png │ │ └── xs.png │ └── saveIcon.imageset │ │ ├── ArtzyLogo-01@2x.png │ │ ├── ArtzyLogo-01@3x.png │ │ ├── ArtzyLogo-1.png │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── HUD │ ├── BaseView │ │ └── BaseView.swift │ ├── Buttons │ │ ├── Camera │ │ │ └── ArtzyCameraButton.swift │ │ ├── Cancel │ │ │ └── CancelButton.swift │ │ ├── Reset │ │ │ └── ResetButton.swift │ │ └── Save │ │ │ └── SaveButton.swift │ ├── CameraHUDViewControllerViewController.swift │ ├── Functionality │ │ ├── HUDAudioFunc.swift │ │ ├── HUDPhotoFunc.swift │ │ ├── HUDRecordingFunc.swift │ │ └── HUDVideoFunc.swift │ ├── NotificationView │ │ ├── NotificationBlimp.swift │ │ └── NotificationView.swift │ └── Preview │ │ └── PreviewView.swift ├── Info.plist ├── PieceOfArtzy │ ├── Functionality │ │ └── ShaderFunctionality.swift │ ├── PieceOfArtzy.swift │ ├── Shaders │ │ ├── Fade │ │ │ ├── FadeIn.metal │ │ │ └── FadeInTexture.metal │ │ ├── Standard │ │ │ ├── Color.metal │ │ │ └── Texture.metal │ │ └── Stroke │ │ │ ├── BackwardStroke.metal │ │ │ ├── BackwardsTimedStroke.metal │ │ │ ├── BackwardsTimedStrokeTexture.metal │ │ │ ├── Stroke.metal │ │ │ ├── TimedStroke.metal │ │ │ └── TimedStrokeTexture.metal │ ├── SpecialEffects │ │ ├── Glow │ │ │ ├── Glow.metal │ │ │ └── Glow.plist │ │ └── GlowInTwoColors │ │ │ ├── GlowBlue.metal │ │ │ ├── GlowInTwoColors.plist │ │ │ └── GlowRed.metal │ └── Variables │ │ └── PieceOfArtzyVariables.swift ├── Variables │ └── AppVariables.swift ├── ViewController.swift └── art.scnassets │ ├── hand.dae │ └── localxAdamfu.scn ├── ArtzyCameraTests ├── ArtzyCameraTests.swift └── Info.plist ├── ArtzyCameraUITests ├── ArtzyCameraUITests.swift └── Info.plist ├── GettingStarted ├── Hand-02.png ├── a4Logo-01.png └── adamLocal-01.png ├── HowItWasMade ├── Hand │ ├── Files │ │ ├── Hand8.ai │ │ └── hand.mb │ └── Image │ │ └── Hand-02.png ├── Loader │ ├── Files │ │ ├── Loading.mb │ │ ├── loading8.ai │ │ └── logo.scn │ └── Image │ │ └── 1024.png └── Local │ ├── Files │ ├── adamLocal8.ai │ ├── adamLocal8Halo.ai │ └── adamLocalFinal.mb │ └── Image │ └── adamLocal-01.png ├── README.md └── license.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | 20 | ## Other 21 | *.xccheckout 22 | *.moved-aside 23 | *.xcuserstate 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | 30 | # Swift Package Manager 31 | # 32 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 33 | # Packages/ 34 | .build/ 35 | 36 | # CocoaPods 37 | # 38 | # We recommend against adding the Pods directory to your .gitignore. However 39 | # you should judge for yourself, the pros and cons are mentioned at: 40 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 41 | # 42 | # Pods/ 43 | 44 | .DS_Store 45 | ArtzyCamera.xcworkspace/xcuserdata/oscardelaheragomez.xcuserdatad/UserInterfaceState.xcuserstate 46 | 47 | -------------------------------------------------------------------------------- /ArtzyCamera.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ArtzyCamera.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ArtzyCamera.xcodeproj/xcshareddata/xcschemes/ArtzyCamera.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /ArtzyCamera.xcodeproj/xcuserdata/oscardelaheragomez.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ArtzyCamera.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | BA82E20121B5C85D002CEFE4 16 | 17 | primary 18 | 19 | 20 | BA82E21721B5C860002CEFE4 21 | 22 | primary 23 | 24 | 25 | BA82E22221B5C860002CEFE4 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /ArtzyCamera/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // ArtzyCamera 4 | // 5 | // Created by Oscar De la Hera Gomez on 12/3/18. 6 | // Copyright © 2018 Delasign. 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: [UIApplication.LaunchOptionsKey: 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 invalidate graphics rendering callbacks. 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 active 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 | -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AR Resources.arresourcegroup/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "resources" : [ 7 | { 8 | "filename" : "artzy loader by delasign.arreferenceimage" 9 | }, 10 | { 11 | "filename" : "hand by delasign.arreferenceimage" 12 | }, 13 | { 14 | "filename" : "local by adamfu x delasign.arreferenceimage" 15 | }, 16 | { 17 | "filename" : "mondriaan by delasign.arreferenceimage" 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AR Resources.arresourcegroup/artzy loader by delasign.arreferenceimage/1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/AR Resources.arresourcegroup/artzy loader by delasign.arreferenceimage/1024.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AR Resources.arresourcegroup/artzy loader by delasign.arreferenceimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "1024.png" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "width" : 0.20000000000000001 14 | } 15 | } -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AR Resources.arresourcegroup/hand by delasign.arreferenceimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Hand-02.png" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "width" : 0.17000000000000001 14 | } 15 | } -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AR Resources.arresourcegroup/hand by delasign.arreferenceimage/Hand-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/AR Resources.arresourcegroup/hand by delasign.arreferenceimage/Hand-02.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AR Resources.arresourcegroup/local by adamfu x delasign.arreferenceimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "adamLocal-01.png" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "width" : 0.20999999999999999 14 | } 15 | } -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AR Resources.arresourcegroup/local by adamfu x delasign.arreferenceimage/adamLocal-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/AR Resources.arresourcegroup/local by adamfu x delasign.arreferenceimage/adamLocal-01.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AR Resources.arresourcegroup/mondriaan by delasign.arreferenceimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Painting@3x.png" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | }, 12 | "properties" : { 13 | "width" : 0.20000000000000001 14 | } 15 | } -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AR Resources.arresourcegroup/mondriaan by delasign.arreferenceimage/Painting@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/AR Resources.arresourcegroup/mondriaan by delasign.arreferenceimage/Painting@3x.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AppIcon.appiconset/1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/AppIcon.appiconset/1024.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AppIcon.appiconset/20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/AppIcon.appiconset/20.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AppIcon.appiconset/20@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/AppIcon.appiconset/20@2x-1.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AppIcon.appiconset/20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/AppIcon.appiconset/20@2x.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AppIcon.appiconset/20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/AppIcon.appiconset/20@3x.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AppIcon.appiconset/29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/AppIcon.appiconset/29.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AppIcon.appiconset/29@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/AppIcon.appiconset/29@2x-1.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AppIcon.appiconset/29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/AppIcon.appiconset/29@2x.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AppIcon.appiconset/29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/AppIcon.appiconset/29@3x.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AppIcon.appiconset/40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/AppIcon.appiconset/40.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AppIcon.appiconset/40@2x-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/AppIcon.appiconset/40@2x-1.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AppIcon.appiconset/40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/AppIcon.appiconset/40@2x.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AppIcon.appiconset/40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/AppIcon.appiconset/40@3x.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AppIcon.appiconset/60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/AppIcon.appiconset/60@2x.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AppIcon.appiconset/60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/AppIcon.appiconset/60@3x.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AppIcon.appiconset/76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/AppIcon.appiconset/76.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AppIcon.appiconset/76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/AppIcon.appiconset/76@2x.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AppIcon.appiconset/83.5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/AppIcon.appiconset/83.5.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "29@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "29@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "40@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "40@3x.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "60@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "60@3x.png", 49 | "scale" : "3x" 50 | }, 51 | { 52 | "size" : "20x20", 53 | "idiom" : "ipad", 54 | "filename" : "20.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "20@2x-1.png", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "size" : "29x29", 65 | "idiom" : "ipad", 66 | "filename" : "29.png", 67 | "scale" : "1x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "29@2x-1.png", 73 | "scale" : "2x" 74 | }, 75 | { 76 | "size" : "40x40", 77 | "idiom" : "ipad", 78 | "filename" : "40.png", 79 | "scale" : "1x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "40@2x-1.png", 85 | "scale" : "2x" 86 | }, 87 | { 88 | "size" : "76x76", 89 | "idiom" : "ipad", 90 | "filename" : "76.png", 91 | "scale" : "1x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "76@2x.png", 97 | "scale" : "2x" 98 | }, 99 | { 100 | "size" : "83.5x83.5", 101 | "idiom" : "ipad", 102 | "filename" : "83.5.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "1024x1024", 107 | "idiom" : "ios-marketing", 108 | "filename" : "1024.png", 109 | "scale" : "1x" 110 | } 111 | ], 112 | "info" : { 113 | "version" : 1, 114 | "author" : "xcode" 115 | } 116 | } -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "extent" : "full-screen", 5 | "idiom" : "iphone", 6 | "subtype" : "2688h", 7 | "filename" : "XS Max.png", 8 | "minimum-system-version" : "12.0", 9 | "orientation" : "portrait", 10 | "scale" : "3x" 11 | }, 12 | { 13 | "extent" : "full-screen", 14 | "idiom" : "iphone", 15 | "subtype" : "1792h", 16 | "filename" : "XR.png", 17 | "minimum-system-version" : "12.0", 18 | "orientation" : "portrait", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "extent" : "full-screen", 23 | "idiom" : "iphone", 24 | "subtype" : "2436h", 25 | "filename" : "xs.png", 26 | "minimum-system-version" : "11.0", 27 | "orientation" : "portrait", 28 | "scale" : "3x" 29 | }, 30 | { 31 | "extent" : "full-screen", 32 | "idiom" : "iphone", 33 | "subtype" : "736h", 34 | "filename" : "Retina HD 5.5.png", 35 | "minimum-system-version" : "8.0", 36 | "orientation" : "portrait", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "extent" : "full-screen", 41 | "idiom" : "iphone", 42 | "subtype" : "667h", 43 | "filename" : "Retine HD 4.7\".png", 44 | "minimum-system-version" : "8.0", 45 | "orientation" : "portrait", 46 | "scale" : "2x" 47 | }, 48 | { 49 | "orientation" : "portrait", 50 | "idiom" : "ipad", 51 | "filename" : "Ipad Portrait.png", 52 | "extent" : "full-screen", 53 | "minimum-system-version" : "7.0", 54 | "scale" : "1x" 55 | }, 56 | { 57 | "orientation" : "portrait", 58 | "idiom" : "ipad", 59 | "filename" : "Ipad Portrait@2x.png", 60 | "extent" : "full-screen", 61 | "minimum-system-version" : "7.0", 62 | "scale" : "2x" 63 | } 64 | ], 65 | "info" : { 66 | "version" : 1, 67 | "author" : "xcode" 68 | } 69 | } -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/LaunchImage.launchimage/Ipad Portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/LaunchImage.launchimage/Ipad Portrait.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/LaunchImage.launchimage/Ipad Portrait@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/LaunchImage.launchimage/Ipad Portrait@2x.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/LaunchImage.launchimage/Retina HD 5.5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/LaunchImage.launchimage/Retina HD 5.5.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/LaunchImage.launchimage/Retine HD 4.7".png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/LaunchImage.launchimage/Retine HD 4.7".png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/LaunchImage.launchimage/XR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/LaunchImage.launchimage/XR.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/LaunchImage.launchimage/XS Max.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/LaunchImage.launchimage/XS Max.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/LaunchImage.launchimage/xs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/LaunchImage.launchimage/xs.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/saveIcon.imageset/ArtzyLogo-01@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/saveIcon.imageset/ArtzyLogo-01@2x.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/saveIcon.imageset/ArtzyLogo-01@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/saveIcon.imageset/ArtzyLogo-01@3x.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/saveIcon.imageset/ArtzyLogo-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/Assets.xcassets/saveIcon.imageset/ArtzyLogo-1.png -------------------------------------------------------------------------------- /ArtzyCamera/Assets.xcassets/saveIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "ArtzyLogo-1.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "ArtzyLogo-01@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "ArtzyLogo-01@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /ArtzyCamera/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 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /ArtzyCamera/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 | -------------------------------------------------------------------------------- /ArtzyCamera/HUD/BaseView/BaseView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BaseView.swift 3 | // ArtzyCamera 4 | // 5 | // Created by Oscar De la Hera Gomez on 12/4/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import AVFoundation 12 | import ARKit 13 | 14 | class BaseView: UIView { 15 | 16 | public var cameraHUDDelegate:CameraHUDDelegate? 17 | public var viewControllerDelegate:ViewControllerDelegate?; 18 | public var sceneView:ARSCNView = ARSCNView(); 19 | 20 | var cameraButton: ArtzyCameraButton = ArtzyCameraButton(); 21 | var resetButton:ResetButton = ResetButton(); 22 | 23 | override init(frame: CGRect) { 24 | super.init(frame: frame); 25 | self.alpha = 1; 26 | 27 | 28 | 29 | 30 | } 31 | 32 | public func start() { 33 | self.cameraButton = ArtzyCameraButton(); 34 | self.cameraButton.sceneView = self.sceneView; 35 | self.cameraButton.cameraHUDDelegate = self.cameraHUDDelegate; 36 | 37 | self.addSubview(self.cameraButton); 38 | 39 | self.resetButton = ResetButton(); 40 | self.resetButton.viewControllerDelegate = self.viewControllerDelegate; 41 | self.resetButton.cameraHUDDelegate = self.cameraHUDDelegate; 42 | self.addSubview(self.resetButton); 43 | } 44 | 45 | required init?(coder aDecoder: NSCoder) { 46 | super.init(coder: aDecoder); 47 | } 48 | 49 | func generateAttributedTitle(string:String, size:CGFloat) -> NSMutableAttributedString{ 50 | return NSMutableAttributedString(string: string, attributes: [NSAttributedString.Key.foregroundColor: UIColor.black, NSAttributedString.Key.font: UIFont(name: "Helvetica", size: size)]); 51 | } 52 | 53 | public func showBaseView(withURL:URL) { 54 | self.alpha = 1 55 | self.isUserInteractionEnabled = true; 56 | } 57 | 58 | private func hideBaseView() { 59 | self.alpha = 0 60 | self.isUserInteractionEnabled = false; 61 | } 62 | 63 | // MARK : BUTTON FUNCTIONALITY 64 | 65 | // @objc private func resetButtonPressed() { 66 | // self.cameraHUDDelegate?.exportVideo(); 67 | // self.removeVideoPreview(); 68 | // self.hideBaseView(); 69 | // } 70 | // 71 | // @objc private func cancelButtonPressed() { 72 | // self.removeVideoPreview(); 73 | // FileManager.default.clearTmpDirectory(); 74 | // self.hideBaseView(); 75 | // } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /ArtzyCamera/HUD/Buttons/Camera/ArtzyCameraButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ArtzyCameraButton.swift 3 | // Artzy 4 | // 5 | // Created by Oscar De la Hera Gomez on 8/2/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import ARKit 11 | import Photos 12 | import ReplayKit 13 | 14 | class ArtzyCameraButton: UIButton { 15 | 16 | public var sceneView:ARSCNView = ARSCNView(); 17 | // public var xArtAlertViewDelegate:xAlertViewDelegate?; 18 | public var cameraHUDDelegate:CameraHUDDelegate?; 19 | 20 | private let whiteCircle:UIView = UIView(); 21 | private var whiteCircleSize:CGFloat { 22 | return kArtzyCameraButtonDimension*3/4; 23 | } 24 | 25 | private let videoCameraProgressArc:CAShapeLayer = CAShapeLayer(); 26 | private var videoCameraProgressArcMargin:CGFloat { 27 | return kArtzyCameraButtonDimension/20; 28 | } 29 | 30 | private let circleGrowthTimeInterval:TimeInterval = 0.3; 31 | private var touchEnded:Bool = false; 32 | private var videoStarted:Bool = false; 33 | private var videoSaved:Bool = false; 34 | 35 | init() { 36 | // Initialize the view to fit the responsive design presented in the deck and sketch file 37 | // Instatiate Camera Circle 38 | 39 | super.init(frame: CGRect(x: (screenWidth - kArtzyCameraButtonDimension)/2, y: (screenHeight*0.9-kArtzyCameraButtonDimension), width: kArtzyCameraButtonDimension, height: kArtzyCameraButtonDimension)); 40 | 41 | self.backgroundColor = UIColor.white.withAlphaComponent(0.6); 42 | self.layer.cornerRadius = kArtzyCameraButtonDimension/2; 43 | 44 | // Instatiate Camera Circle 45 | 46 | self.whiteCircle.backgroundColor = UIColor.white; 47 | self.whiteCircle.layer.cornerRadius = whiteCircleSize/2; 48 | self.whiteCircle.frame = CGRect(x: (self.frame.width-whiteCircleSize)/2, y: (self.frame.width-whiteCircleSize)/2, width: whiteCircleSize, height: whiteCircleSize); 49 | self.addSubview(self.whiteCircle); 50 | 51 | 52 | // Create the video camera progress arc 53 | 54 | self.videoCameraProgressArc.opacity = 0; 55 | self.videoCameraProgressArc.path = UIBezierPath(ovalIn: CGRect(x: self.videoCameraProgressArcMargin, y: self.videoCameraProgressArcMargin, width: self.frame.width - self.videoCameraProgressArcMargin*2, height: self.frame.width - self.videoCameraProgressArcMargin*2)).cgPath; 56 | self.videoCameraProgressArc.lineWidth = 5.0; 57 | self.videoCameraProgressArc.strokeStart = 0; 58 | self.videoCameraProgressArc.strokeEnd = 0; 59 | self.videoCameraProgressArc.strokeColor = UIColor.black.cgColor; 60 | self.videoCameraProgressArc.fillColor = UIColor.clear.cgColor; 61 | 62 | // Rotate 90 degrees anti clockwise 63 | self.videoCameraProgressArc.transform = CATransform3DMakeRotation(CGFloat(-Double.pi/2), 0,0,1); 64 | self.videoCameraProgressArc.position = CGPoint(x: 0, y: self.frame.height); 65 | 66 | 67 | self.layer.addSublayer(self.videoCameraProgressArc); 68 | 69 | 70 | 71 | } 72 | 73 | override init(frame: CGRect) { 74 | super.init(frame: frame); 75 | 76 | } 77 | 78 | required init?(coder aDecoder: NSCoder) { 79 | super.init(coder: aDecoder); 80 | } 81 | 82 | // BUTTON FUNCTIONALITY 83 | 84 | override func touchesBegan(_ touches: Set, with event: UIEvent?) { 85 | 86 | self.touchEnded = false; 87 | self.videoSaved = false; 88 | 89 | UIView.animate(withDuration: circleGrowthTimeInterval, delay: 0, options: .curveEaseInOut, animations: { 90 | 91 | self.frame = CGRect(x: (screenWidth - kArtzyCameraButtonDimension*1.5)/2, y: (screenHeight*0.9-kArtzyCameraButtonDimension*1.25), width: kArtzyCameraButtonDimension*1.5, height: kArtzyCameraButtonDimension*1.5); 92 | self.layer.cornerRadius = kArtzyCameraButtonDimension*1.5/2; 93 | 94 | self.whiteCircle.frame = CGRect(x: (self.frame.width-self.whiteCircleSize)/2, y: (self.frame.width-self.whiteCircleSize)/2, width: self.whiteCircleSize, height: self.whiteCircleSize); 95 | 96 | self.videoCameraProgressArc.path = UIBezierPath(ovalIn: CGRect(x: self.videoCameraProgressArcMargin, y: self.videoCameraProgressArcMargin, width: self.frame.width - self.videoCameraProgressArcMargin*2, height: self.frame.width - self.videoCameraProgressArcMargin*2)).cgPath; 97 | 98 | self.videoCameraProgressArc.transform = CATransform3DMakeRotation(CGFloat(-Double.pi/2), 0,0,1); 99 | self.videoCameraProgressArc.position = CGPoint(x: 0, y: self.frame.height); 100 | 101 | }) { (finished) in 102 | print("FINISHED INWARD ANIMATION"); 103 | // Begin Video Capture 104 | 105 | if (self.touchEnded == false){ 106 | 107 | self.videoStarted = true; 108 | 109 | // Start the animation 110 | self.animateVideoRing(); 111 | 112 | // Start recording the video 113 | self.cameraHUDDelegate?.startRecording(); 114 | } 115 | } 116 | } 117 | 118 | override func touchesMoved(_ touches: Set, with event: UIEvent?) { 119 | 120 | } 121 | 122 | override func touchesEnded(_ touches: Set, with event: UIEvent?) { 123 | 124 | self.touchEnded = true; 125 | 126 | 127 | print("STATE ", RPScreenRecorder.shared().isRecording ) 128 | print("VIDEO STARTED ", self.videoStarted ) 129 | 130 | if( self.videoStarted == false ){ //self.recorder?.status != .recording 131 | // Check if you actually started recording? 132 | if self.videoSaved == false { 133 | print("IMAGE"); 134 | self.cameraHUDDelegate?.previewPhoto(image:self.sceneView.snapshot()); 135 | 136 | } 137 | else { 138 | print("Video Already saved"); 139 | } 140 | } 141 | else { 142 | self.videoStarted = false; 143 | 144 | // Screen Recorder isn't recording, theresfore stop recording. 145 | print("VIDEO"); 146 | self.videoCameraProgressArc.removeAllAnimations(); 147 | self.videoCameraProgressArc.opacity = 0; 148 | } 149 | 150 | UIView.animate(withDuration: circleGrowthTimeInterval, animations: { 151 | 152 | self.frame = CGRect(x: (screenWidth - kArtzyCameraButtonDimension)/2, y: (screenHeight*0.9-kArtzyCameraButtonDimension), width: kArtzyCameraButtonDimension, height: kArtzyCameraButtonDimension); 153 | self.layer.cornerRadius = kArtzyCameraButtonDimension/2; 154 | 155 | self.whiteCircle.frame = CGRect(x: (self.frame.width-self.whiteCircleSize)/2, y: (self.frame.width-self.whiteCircleSize)/2, width: self.whiteCircleSize, height: self.whiteCircleSize); 156 | 157 | }); 158 | 159 | } 160 | 161 | // MARK : ANIMATION FUNCTIONALITY 162 | 163 | func animateVideoRing(){ 164 | // Set the Initial Stroke State 165 | self.videoCameraProgressArc.strokeStart = 0 166 | self.videoCameraProgressArc.strokeEnd = 0 167 | self.videoCameraProgressArc.opacity = 1; 168 | 169 | CATransaction.begin(); 170 | CATransaction.setAnimationDuration(10); 171 | CATransaction.setDisableActions(true); 172 | CATransaction.setCompletionBlock { 173 | self.videoRingAnimationDidFinish(); 174 | } 175 | 176 | // Set animation end state 177 | let start = CABasicAnimation(keyPath: "strokeStart") 178 | start.toValue = 0 179 | let end = CABasicAnimation(keyPath: "strokeEnd") 180 | end.toValue = 1 181 | 182 | // Play Animation Repetitively 183 | let group = CAAnimationGroup() 184 | group.animations = [start, end]; 185 | group.duration = 10 186 | group.autoreverses = false; 187 | group.repeatCount = 0 // repeat 0 times 188 | group.isRemovedOnCompletion = true; 189 | 190 | self.videoCameraProgressArc.add(group, forKey: nil) 191 | 192 | CATransaction.commit(); 193 | 194 | } 195 | 196 | func videoRingAnimationDidFinish(){ 197 | print("STOP VIDEO, ANIMATION COMPLETE"); 198 | 199 | // Stop the button animation and hide the arc 200 | self.videoCameraProgressArc.removeAllAnimations(); 201 | self.videoCameraProgressArc.opacity = 0; 202 | self.videoSaved = true; 203 | self.cameraHUDDelegate?.stopRecording(); 204 | } 205 | 206 | } 207 | 208 | -------------------------------------------------------------------------------- /ArtzyCamera/HUD/Buttons/Cancel/CancelButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CancelButton.swift 3 | // ArtzyCamera 4 | // 5 | // Created by Oscar De la Hera Gomez on 12/5/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class CancelButton: UIButton { 12 | 13 | public var viewControllerDelegate:ViewControllerDelegate?; 14 | public var cameraHUDDelegate:CameraHUDDelegate?; 15 | 16 | private var label:UILabel = UILabel(); 17 | 18 | init() { 19 | // Initialize the view to fit the responsive design presented in the deck and sketch file 20 | // Instatiate Camera Circle 21 | 22 | super.init(frame: CGRect(x: kArtzyHUDButtonGap/2, y:kArtzyResetButtonMinY, width: kArtzyResetButtonDimension, height: kArtzyResetButtonDimension)); 23 | self.layer.cornerRadius = 6; 24 | 25 | self.label.attributedText = self.generateAttributedTitle(string: "cancel", size: 18); 26 | self.label.sizeToFit(); 27 | self.label.frame = CGRect(x: 0, y: kArtzMinYLabelLine-self.frame.minY, width: self.label.frame.width, height: self.label.frame.height); 28 | 29 | self.addSubview(self.label); 30 | } 31 | 32 | override init(frame: CGRect) { 33 | super.init(frame: frame); 34 | 35 | } 36 | 37 | required init?(coder aDecoder: NSCoder) { 38 | super.init(coder: aDecoder); 39 | } 40 | 41 | func generateAttributedTitle(string:String, size:CGFloat) -> NSMutableAttributedString{ 42 | return NSMutableAttributedString(string: string, attributes: [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont(name: "Helvetica", size: size)]); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ArtzyCamera/HUD/Buttons/Reset/ResetButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ResetButton.swift 3 | // Artzy 4 | // 5 | // Created by Oscar De la Hera Gomez on 9/15/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ResetButton: UIButton { 12 | 13 | public var viewControllerDelegate:ViewControllerDelegate?; 14 | public var cameraHUDDelegate:CameraHUDDelegate?; 15 | 16 | private var label:UILabel = UILabel(); 17 | 18 | init() { 19 | // Initialize the view to fit the responsive design presented in the deck and sketch file 20 | // Instatiate Camera Circle 21 | 22 | super.init(frame: CGRect(x: screenWidth - kArtzyResetButtonDimension - kArtzyHUDButtonGap/2, y:kArtzyResetButtonMinY, width: kArtzyResetButtonDimension, height: kArtzyResetButtonDimension)); 23 | // self.setAttributedTitle(self.generateAttributedTitle(string: "reset", size: 18), for: .normal); 24 | self.layer.cornerRadius = 6; 25 | 26 | self.label.attributedText = self.generateAttributedTitle(string: "reset", size: 18); 27 | self.label.sizeToFit(); 28 | self.label.frame = CGRect(x: 0, y: kArtzMinYLabelLine-self.frame.minY, width: self.frame.width, height: self.label.frame.height); 29 | self.addSubview(self.label); 30 | } 31 | 32 | override init(frame: CGRect) { 33 | super.init(frame: frame); 34 | 35 | } 36 | 37 | required init?(coder aDecoder: NSCoder) { 38 | super.init(coder: aDecoder); 39 | } 40 | 41 | func generateAttributedTitle(string:String, size:CGFloat) -> NSMutableAttributedString{ 42 | return NSMutableAttributedString(string: string, attributes: [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont(name: "Helvetica", size: size)]); 43 | } 44 | 45 | override func touchesBegan(_ touches: Set, with event: UIEvent?) { 46 | DispatchQueue.global().async { [weak self] in 47 | self?.cameraHUDDelegate?.resetCameraHUD(); 48 | } 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /ArtzyCamera/HUD/Buttons/Save/SaveButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SaveButton.swift 3 | // ArtzyCamera 4 | // 5 | // Created by Oscar De la Hera Gomez on 12/5/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SaveButton: UIButton { 12 | 13 | public var viewControllerDelegate:ViewControllerDelegate?; 14 | public var cameraHUDDelegate:CameraHUDDelegate?; 15 | 16 | private var label:UILabel = UILabel(); 17 | private var saveIcon:UIImageView = UIImageView(); //UIImage(named: "saveIcon"); 18 | 19 | init() { 20 | // Initialize the view to fit the responsive design presented in the deck and sketch file 21 | // Instatiate Camera Circle 22 | 23 | var kArtzySaveButtonDimension:CGFloat = CGFloat(); 24 | kArtzySaveButtonDimension = screenHeight/6 25 | 26 | super.init(frame: CGRect(x: (screenWidth-kArtzySaveButtonDimension)/2, y:screenHeight*0.7325, width: kArtzySaveButtonDimension, height: kArtzySaveButtonDimension)); 27 | self.layer.cornerRadius = 6; 28 | 29 | self.label.attributedText = self.generateAttributedTitle(string: "save", size: 18); 30 | self.label.sizeToFit(); 31 | self.label.textAlignment = .center; 32 | self.label.frame = CGRect(x: 0, y: self.frame.height*0.75, width: self.frame.width, height: self.label.frame.height); 33 | self.addSubview(self.label); 34 | 35 | self.saveIcon.frame = CGRect(x: self.frame.height*0.25, y: self.frame.height*0.125, width: self.frame.height*0.5, height: self.frame.height*0.5); 36 | self.saveIcon.image = UIImage(named: "saveIcon"); 37 | self.addSubview(self.saveIcon) 38 | } 39 | 40 | override init(frame: CGRect) { 41 | super.init(frame: frame); 42 | 43 | } 44 | 45 | required init?(coder aDecoder: NSCoder) { 46 | super.init(coder: aDecoder); 47 | } 48 | 49 | func generateAttributedTitle(string:String, size:CGFloat) -> NSMutableAttributedString{ 50 | return NSMutableAttributedString(string: string, attributes: [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont(name: "Helvetica", size: size)]); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /ArtzyCamera/HUD/CameraHUDViewControllerViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HiddenStatusBarViewController.swift 3 | // xArt 4 | // 5 | // Created by Oscar De la Hera Gomez on 8/2/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import ARKit 11 | import AVFoundation 12 | import Photos 13 | 14 | protocol CameraHUDDelegate { 15 | func startRecording(); 16 | func stopRecording(); 17 | func resetCameraHUD(); 18 | func exportVideo(); 19 | func endAudioSession(); 20 | func saveImage(image:UIImage); 21 | func previewPhoto(image:UIImage) 22 | } 23 | 24 | class CameraHUDViewController: UIViewController, CameraHUDDelegate, AVCaptureAudioDataOutputSampleBufferDelegate { 25 | 26 | // Views 27 | var baseView: BaseView = BaseView(); 28 | var previewView: PreviewView = PreviewView(); 29 | 30 | // Delegates 31 | public var viewControllerDelegate:ViewControllerDelegate?; 32 | // Sceneview 33 | public var sceneView:ARSCNView = ARSCNView(); 34 | private var sampleImage:UIImage? 35 | private var renderer:SCNRenderer? 36 | 37 | // Recording 38 | public var isRecording:Bool = false; 39 | var snapshotArray:[[String:Any]] = [[String:Any]]() 40 | var lastTime:TimeInterval = 0 41 | public var videoStartTime:CMTime?; 42 | 43 | // Asset Writer 44 | var pixelBufferAdaptor:AVAssetWriterInputPixelBufferAdaptor? 45 | var videoInput:AVAssetWriterInput?; 46 | var audioInput:AVAssetWriterInput?; 47 | var assetWriter:AVAssetWriter?; 48 | 49 | // Audio 50 | var captureSession: AVCaptureSession? 51 | var micInput:AVCaptureDeviceInput? 52 | var audioOutput:AVCaptureAudioDataOutput? 53 | var recordingSession:AVAudioSession! 54 | 55 | override func viewDidLoad() { 56 | super.viewDidLoad() 57 | self.intializeBasicCameraHUD(); 58 | } 59 | 60 | override func didReceiveMemoryWarning() { 61 | super.didReceiveMemoryWarning() 62 | // Dispose of any resources that can be recreated. 63 | } 64 | 65 | func prefersStatusBarHidden() -> Bool { 66 | return true 67 | } 68 | 69 | // MARK: STARTING / REFRESHING FUNCTIONALITY 70 | 71 | func intializeBasicCameraHUD() { 72 | DispatchQueue.main.async { 73 | // Do any additional setup after loading the view. 74 | 75 | self.sampleImage = self.sceneView.snapshot(); 76 | 77 | self.renderer = SCNRenderer(device: MTLCreateSystemDefaultDevice(), options: [:]) 78 | self.renderer!.scene = self.sceneView.scene 79 | self.renderer!.pointOfView = self.sceneView.pointOfView 80 | 81 | self.baseView = BaseView(frame: self.view.frame); 82 | self.baseView.cameraHUDDelegate = self; 83 | self.baseView.viewControllerDelegate = self.viewControllerDelegate; 84 | self.baseView.sceneView = self.sceneView; 85 | 86 | self.baseView.start(); 87 | self.view.addSubview(self.baseView); 88 | 89 | self.previewView = PreviewView(frame: self.view.frame); 90 | self.previewView.cameraHUDDelegate = self; 91 | 92 | artzyNotificationView = NotificationView(frame: CGRect(x: screenWidth*0.25, y: 0, width: screenWidth*0.5, height: screenHeight*0.2)); 93 | self.view.addSubview(artzyNotificationView) 94 | 95 | 96 | } 97 | } 98 | 99 | public func resetCameraHUD() { 100 | 101 | self.viewControllerDelegate?.resetTracking(); 102 | 103 | DispatchQueue.main.async { 104 | for view in self.view.subviews { 105 | view.removeFromSuperview(); 106 | } 107 | 108 | self.intializeBasicCameraHUD(); 109 | } 110 | } 111 | 112 | // MARK: DID UPDATE AT TIME 113 | 114 | let filmQueue:DispatchQueue = DispatchQueue(label: "filmQueue"); 115 | var snapshot:UIImage?; 116 | let scale = CMTimeScale(NSEC_PER_SEC) 117 | 118 | public func didUpdateAtTime(time: TimeInterval) { 119 | 120 | 121 | if self.isRecording { 122 | 123 | if self.lastTime == 0 || (self.lastTime + 1/25) < time { 124 | 125 | // filmQueue.sync { [weak self] () -> Void in 126 | 127 | var currentFrameTime:CMTime = CMTime(value: CMTimeValue((self.sceneView.session.currentFrame!.timestamp) * Double(scale)), timescale: scale); 128 | 129 | if self.lastTime == 0 { 130 | self.videoStartTime = currentFrameTime; 131 | } 132 | 133 | print("[artzyhud] UPDATE AT TIME : \(time)"); 134 | 135 | self.lastTime = time; 136 | 137 | // VIDEO 138 | 139 | let snapshot:UIImage = self.sceneView.snapshot() 140 | 141 | self.createPixelBufferFromUIImage(image:snapshot, completionHandler: { (error, pixelBuffer) in 142 | 143 | guard error == nil else { 144 | print("failed to get pixelBuffer"); 145 | return 146 | } 147 | 148 | currentFrameTime = currentFrameTime - self.videoStartTime!; 149 | 150 | 151 | if (self.videoInput?.isReadyForMoreMediaData)! { 152 | // Add pixel buffer to video input 153 | self.pixelBufferAdaptor!.append(pixelBuffer!, withPresentationTime: currentFrameTime); 154 | return 155 | } 156 | else { 157 | print("FAILED TO PASS DATA") 158 | } 159 | }); 160 | 161 | // } 162 | } 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /ArtzyCamera/HUD/Functionality/HUDAudioFunc.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HUDAudioFunc.swift 3 | // ArtzyCamera 4 | // 5 | // Created by Oscar De la Hera Gomez on 12/4/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import AVFoundation 11 | 12 | extension CameraHUDViewController { 13 | 14 | // MARK: AUDIO FUNCTIONALITY 15 | 16 | func startAudioRecording(completionHandler:@escaping(Bool) -> ()) { 17 | 18 | self.recordingSession = AVAudioSession.sharedInstance() 19 | 20 | do { 21 | try self.recordingSession.setCategory(AVAudioSession.Category.playAndRecord, mode: .videoRecording, options: [.defaultToSpeaker]) 22 | try self.recordingSession.setActive(true, options: .notifyOthersOnDeactivation) 23 | 24 | print("REQUESTED SESSION") 25 | 26 | self.recordingSession!.requestRecordPermission() { [unowned self] allowed in 27 | DispatchQueue.main.async { 28 | if allowed { 29 | // self.loadRecordingUI() 30 | print("SESSION ALLOWED") 31 | // let microphone = AVCaptureDevice.default(.builtInMicrophone, for: AVMediaType.audio, position: .unspecified) 32 | let microphone = AVCaptureDevice.default(.builtInMicrophone, for: AVMediaType.audio, position: .unspecified) 33 | 34 | do { 35 | try self.micInput = AVCaptureDeviceInput(device: microphone!); 36 | 37 | self.captureSession = AVCaptureSession(); 38 | 39 | if (self.captureSession?.canAddInput(self.micInput!))! { 40 | self.captureSession?.addInput(self.micInput!); 41 | 42 | self.audioOutput = AVCaptureAudioDataOutput(); 43 | 44 | if self.captureSession!.canAddOutput(self.audioOutput!){ 45 | self.captureSession!.addOutput(self.audioOutput!) 46 | self.audioOutput?.setSampleBufferDelegate(self, queue: DispatchQueue.global()); 47 | 48 | self.captureSession?.startRunning(); 49 | completionHandler(true); 50 | } 51 | 52 | } 53 | } 54 | catch { 55 | completionHandler(false); 56 | } 57 | } else { 58 | // self.loadFailUI() 59 | completionHandler(false); 60 | 61 | } 62 | } 63 | } 64 | } catch { 65 | // self.loadFailUI() 66 | completionHandler(false); 67 | } 68 | 69 | 70 | } 71 | 72 | func endAudioCapture() { 73 | self.captureSession!.stopRunning(); 74 | } 75 | 76 | public func endAudioSession() { 77 | do { 78 | try self.recordingSession.setActive(false, options: .notifyOthersOnDeactivation) 79 | } 80 | catch { 81 | print("ERROR CANCELLING RECORDING SESSION : \(error)") 82 | } 83 | } 84 | 85 | func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { 86 | 87 | guard sampleBuffer != nil else { 88 | print("SAMPLE BUFFER EQUALS NIL ") 89 | return 90 | } 91 | 92 | 93 | // You now have the sample buffer - correct the timestamp to the video timestamp 94 | 95 | //https://github.com/takecian/video-examples-ios/blob/master/recordings/TimelapseCameraEngine.swift 96 | 97 | var count: CMItemCount = 0 98 | CMSampleBufferGetSampleTimingInfoArray(sampleBuffer, entryCount: 0, arrayToFill: nil, entriesNeededOut: &count); 99 | var info = [CMSampleTimingInfo](repeating: CMSampleTimingInfo(duration: CMTimeMake(value: 0, timescale: 0), presentationTimeStamp: CMTimeMake(value: 0, timescale: 0), decodeTimeStamp: CMTimeMake(value: 0, timescale: 0)), count: count) 100 | CMSampleBufferGetSampleTimingInfoArray(sampleBuffer, entryCount: count, arrayToFill: &info, entriesNeededOut: &count); 101 | 102 | let scale = CMTimeScale(NSEC_PER_SEC) 103 | var currentFrameTime:CMTime = CMTime(value: CMTimeValue((self.sceneView.session.currentFrame!.timestamp) * Double(scale)), timescale: scale); 104 | 105 | if self.videoStartTime == CMTime.zero { 106 | self.videoStartTime = currentFrameTime; 107 | } 108 | 109 | currentFrameTime = currentFrameTime-self.videoStartTime!; 110 | 111 | for i in 0.. Void in 47 | 48 | self.isRecording = false; 49 | self.endAudioCapture(); 50 | print("ENDED RECORDING") 51 | 52 | self.finishVideoRecording { (videoURL) in 53 | print("VIDEO URL") 54 | DispatchQueue.main.sync { 55 | self.view.addSubview(self.previewView); 56 | self.view.bringSubviewToFront(artzyNotificationView); 57 | } 58 | self.previewView.showPreviewView(withURL: videoURL); 59 | } 60 | 61 | // } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /ArtzyCamera/HUD/Functionality/HUDVideoFunc.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewControllerReplayKitFunctionality.swift 3 | // xArt 4 | // 5 | // Created by Oscar De la Hera Gomez on 8/2/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import AVFoundation 12 | import Photos 13 | 14 | extension CameraHUDViewController { 15 | 16 | public func saveVideo(withName:String, imageArray:[[String:Any]], fps:Int, size:CGSize) { 17 | 18 | self.createURLForVideo(withName: withName) { (videoURL) in 19 | self.prepareWriterAndInput(size:size, videoURL: videoURL, completionHandler: { (error) in 20 | 21 | guard error == nil else { 22 | // it errored. 23 | return 24 | } 25 | 26 | self.createVideo(imageArray: imageArray, fps: fps, size:size, completionHandler: { _ in 27 | print("[F] saveVideo :: DONE"); 28 | 29 | guard error == nil else { 30 | // it errored. 31 | return 32 | } 33 | 34 | self.finishVideoRecordingAndSave(); 35 | 36 | }); 37 | }); 38 | } 39 | 40 | } 41 | 42 | public func createURLForVideo(withName:String, completionHandler:@escaping (URL)->()) { 43 | // Clear the location for the temporary file. 44 | let temporaryDirectoryURL:URL = URL.init(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true); 45 | let targetURL:URL = temporaryDirectoryURL.appendingPathComponent("\(withName).mp4") 46 | // Delete the file, incase it exists. 47 | do { 48 | try FileManager.default.removeItem(at: targetURL); 49 | 50 | } catch let error { 51 | NSLog("Unable to delete file, with error: \(error)") 52 | } 53 | // return the URL 54 | completionHandler(targetURL); 55 | } 56 | 57 | public func prepareWriterAndInput(size:CGSize, videoURL:URL, completionHandler:@escaping(Error?)->()) { 58 | 59 | do { 60 | self.assetWriter = try AVAssetWriter(outputURL: videoURL, fileType: AVFileType.mp4) 61 | 62 | // Input is the mic audio of the AVAudioEngine 63 | let audioOutputSettings = [ 64 | AVFormatIDKey : kAudioFormatMPEG4AAC, 65 | AVNumberOfChannelsKey : 2, 66 | AVSampleRateKey : 44100.0, 67 | AVEncoderBitRateKey: 192000 68 | ] as [String : Any] 69 | 70 | self.audioInput = AVAssetWriterInput(mediaType: AVMediaType.audio, outputSettings: audioOutputSettings); 71 | self.audioInput!.expectsMediaDataInRealTime = true 72 | self.assetWriter?.add(self.audioInput!); 73 | 74 | // self.audioInput. 75 | 76 | // Video Input Creator 77 | 78 | let videoOutputSettings: Dictionary = [ 79 | AVVideoCodecKey : AVVideoCodecType.h264, 80 | AVVideoWidthKey : size.width, 81 | AVVideoHeightKey : size.height 82 | ]; 83 | 84 | self.videoInput = AVAssetWriterInput (mediaType: AVMediaType.video, outputSettings: videoOutputSettings) 85 | self.videoInput!.expectsMediaDataInRealTime = true 86 | self.assetWriter!.add(self.videoInput!) 87 | 88 | // Create Pixel buffer Adaptor 89 | 90 | let sourceBufferAttributes:[String : Any] = [ 91 | (kCVPixelBufferPixelFormatTypeKey as String): Int(kCVPixelFormatType_32ARGB), 92 | (kCVPixelBufferWidthKey as String): Float(size.width), 93 | (kCVPixelBufferHeightKey as String): Float(size.height)] as [String : Any] 94 | 95 | self.pixelBufferAdaptor = AVAssetWriterInputPixelBufferAdaptor(assetWriterInput: self.videoInput!, sourcePixelBufferAttributes: sourceBufferAttributes); 96 | 97 | self.assetWriter?.startWriting(); 98 | self.assetWriter?.startSession(atSourceTime: CMTime.zero); 99 | completionHandler(nil); 100 | } 101 | catch { 102 | print("Failed to create assetWritter with error : \(error)"); 103 | completionHandler(error); 104 | } 105 | } 106 | 107 | private func createVideo(imageArray:[[String:Any]], fps:Int, size:CGSize, completionHandler:@escaping(String?)->()) { 108 | 109 | var currentframeTime:CMTime = CMTime.zero; 110 | var currentFrame:Int = 0; 111 | 112 | let startTime:CMTime = (imageArray[0])["time"] as! CMTime; 113 | 114 | while (currentFrame < imageArray.count) { 115 | 116 | // When the video input is ready for more media data... 117 | if (self.videoInput?.isReadyForMoreMediaData)! { 118 | print("processing current frame :: \(currentFrame)"); 119 | // Get current UI Image 120 | let currentImage:UIImage = (imageArray[currentFrame])["image"] as! UIImage; 121 | 122 | // Create the pixel buffer 123 | self.createPixelBufferFromUIImage(image: currentImage) { (error, pixelBuffer) in 124 | 125 | guard error == nil else { 126 | completionHandler("failed to get pixelBuffer"); 127 | return 128 | } 129 | 130 | // Calc the current frame time 131 | currentframeTime = (imageArray[currentFrame])["time"] as! CMTime - startTime; 132 | print("SECONDS : \(currentframeTime.seconds)") 133 | print("Current frame time :: \(currentframeTime)"); 134 | 135 | // Add pixel buffer to video input 136 | self.pixelBufferAdaptor!.append(pixelBuffer!, withPresentationTime: currentframeTime); 137 | 138 | // increment frame 139 | currentFrame += 1; 140 | } 141 | } 142 | } 143 | 144 | // FINISHED 145 | completionHandler(nil); 146 | } 147 | 148 | 149 | public func createPixelBufferFromCGImage(image:CGImage, completionHandler:@escaping(String?, CVPixelBuffer?) -> ()) { 150 | //https://stackoverflow.com/questions/44400741/convert-image-to-cvpixelbuffer-for-machine-learning-swift 151 | let attrs = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue, kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue] as CFDictionary 152 | var pixelBuffer : CVPixelBuffer? 153 | let status = CVPixelBufferCreate(kCFAllocatorDefault, image.width, image.height, kCVPixelFormatType_32ARGB, attrs, &pixelBuffer) 154 | guard (status == kCVReturnSuccess) else { 155 | completionHandler("Failed to create pixel buffer", nil) 156 | return 157 | } 158 | 159 | CVPixelBufferLockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0)) 160 | let pixelData = CVPixelBufferGetBaseAddress(pixelBuffer!) 161 | 162 | let rgbColorSpace = CGColorSpaceCreateDeviceRGB() 163 | let context = CGContext(data: pixelData, width: image.width, height: image.height, bitsPerComponent: 8, bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer!), space: rgbColorSpace, bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue) 164 | 165 | context?.translateBy(x: 0, y: CGFloat(image.height)) 166 | context?.scaleBy(x: 1.0, y: -1.0) 167 | 168 | // UIGraphicsPushContext(context!) 169 | // image.draw(in: CGRect(x: 0, y: 0, width: image.width, height: image.height)) 170 | // UIGraphicsPopContext() 171 | // context.draw(image, in: CGRect(x: 0.0,y: 0.0,width: image.width, height: image.height)); 172 | // context?.draw(image, in: CGRect(x: 0, y: 0, width: image.width, height: image.height)); 173 | 174 | UIGraphicsPushContext(context!) 175 | context?.draw(image, in: CGRect(x: 0, y: 0, width: image.width, height: image.height)); 176 | UIGraphicsPopContext() 177 | 178 | CVPixelBufferUnlockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0)) 179 | 180 | completionHandler(nil, pixelBuffer) 181 | } 182 | 183 | public func createPixelBufferFromUIImage(image:UIImage, completionHandler:@escaping(String?, CVPixelBuffer?) -> ()) { 184 | //https://stackoverflow.com/questions/44400741/convert-image-to-cvpixelbuffer-for-machine-learning-swift 185 | let attrs = [kCVPixelBufferCGImageCompatibilityKey: kCFBooleanTrue, kCVPixelBufferCGBitmapContextCompatibilityKey: kCFBooleanTrue] as CFDictionary 186 | var pixelBuffer : CVPixelBuffer? 187 | let status = CVPixelBufferCreate(kCFAllocatorDefault, Int(UIScreen.main.bounds.size.width), Int(UIScreen.main.bounds.size.height), kCVPixelFormatType_32ARGB, attrs, &pixelBuffer) 188 | 189 | guard (status == kCVReturnSuccess) else { 190 | completionHandler("Failed to create pixel buffer", nil) 191 | return 192 | } 193 | 194 | CVPixelBufferLockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0)) 195 | let pixelData = CVPixelBufferGetBaseAddress(pixelBuffer!) 196 | 197 | let rgbColorSpace = CGColorSpaceCreateDeviceRGB() 198 | let context = CGContext(data: pixelData, width: Int(UIScreen.main.bounds.size.width), height: Int(UIScreen.main.bounds.size.height), bitsPerComponent: 8, bytesPerRow: CVPixelBufferGetBytesPerRow(pixelBuffer!), space: rgbColorSpace, bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue) 199 | 200 | context?.translateBy(x: 0, y: UIScreen.main.bounds.size.height) 201 | context?.scaleBy(x: 1.0, y: -1.0) 202 | 203 | UIGraphicsPushContext(context!) 204 | image.draw(in: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height)) 205 | UIGraphicsPopContext() 206 | CVPixelBufferUnlockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0)) 207 | 208 | // CVPixelBufferReleaseBytesCallback( 209 | 210 | completionHandler(nil, pixelBuffer) 211 | } 212 | 213 | 214 | public func finishVideoRecordingAndSave() { 215 | self.videoInput!.markAsFinished(); 216 | self.audioInput?.markAsFinished(); 217 | self.assetWriter?.finishWriting(completionHandler: { 218 | print("output url : \(self.assetWriter?.outputURL)"); 219 | 220 | PHPhotoLibrary.requestAuthorization({ (status) in 221 | PHPhotoLibrary.shared().performChanges({ 222 | PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: (self.assetWriter?.outputURL)!) 223 | }) { saved, error in 224 | 225 | guard error == nil else { 226 | print("failed to save video"); 227 | print("error : \(error)") 228 | return 229 | } 230 | 231 | if saved { 232 | let alertController = UIAlertController(title: "Your video was successfully saved", message: nil, preferredStyle: .alert) 233 | let defaultAction = UIAlertAction(title: "OK", style: .default, handler: nil) 234 | alertController.addAction(defaultAction) 235 | self.present(alertController, animated: true, completion: nil) 236 | } 237 | 238 | self.snapshotArray.removeAll(); 239 | FileManager.default.clearTmpDirectory(); 240 | } 241 | }) 242 | }) 243 | } 244 | 245 | public func finishVideoRecording(completionHandler:@escaping(URL)->()) { 246 | self.videoInput!.markAsFinished(); 247 | self.audioInput?.markAsFinished(); 248 | self.assetWriter?.finishWriting(completionHandler: { 249 | print("output url : \(self.assetWriter?.outputURL)"); 250 | 251 | completionHandler((self.assetWriter?.outputURL)!); 252 | }) 253 | } 254 | 255 | public func exportVideo() { 256 | PHPhotoLibrary.requestAuthorization({ (status) in 257 | PHPhotoLibrary.shared().performChanges({ 258 | PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: (self.assetWriter?.outputURL)!) 259 | }) { saved, error in 260 | 261 | guard error == nil else { 262 | print("failed to save video"); 263 | print("error : \(error)") 264 | return 265 | } 266 | 267 | if saved { 268 | let alertController = UIAlertController(title: "Your video was successfully saved", message: nil, preferredStyle: .alert) 269 | let defaultAction = UIAlertAction(title: "OK", style: .default, handler: nil) 270 | alertController.addAction(defaultAction) 271 | self.present(alertController, animated: true, completion: nil) 272 | } 273 | 274 | self.videoInput = nil; 275 | self.pixelBufferAdaptor = nil; 276 | self.audioInput = nil; 277 | self.assetWriter = nil; 278 | 279 | FileManager.default.clearTmpDirectory(); 280 | } 281 | }) 282 | } 283 | 284 | } 285 | 286 | 287 | extension FileManager { 288 | func clearTmpDirectory() { 289 | do { 290 | let tmpDirURL = FileManager.default.temporaryDirectory 291 | let tmpDirectory = try contentsOfDirectory(atPath: tmpDirURL.path) 292 | try tmpDirectory.forEach { file in 293 | let fileUrl = tmpDirURL.appendingPathComponent(file) 294 | try removeItem(atPath: fileUrl.path) 295 | } 296 | } catch { 297 | //catch the error somehow 298 | } 299 | } 300 | } 301 | -------------------------------------------------------------------------------- /ArtzyCamera/HUD/NotificationView/NotificationBlimp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotificationBlimp.swift 3 | // ArtzyCamera 4 | // 5 | // Created by Oscar De la Hera Gomez on 12/4/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | class NotificationBlimp: UIView { 13 | 14 | let flash = CABasicAnimation(keyPath: "opacity") 15 | var previousState:ArtzyNotificationStyle = .searching; 16 | 17 | override init(frame: CGRect) { 18 | super.init(frame: frame); 19 | self.layer.backgroundColor = UIColor.white.cgColor; 20 | self.layer.cornerRadius = self.frame.width/2; 21 | } 22 | 23 | required init?(coder aDecoder: NSCoder) { 24 | super.init(coder: aDecoder); 25 | } 26 | 27 | public func updateNotificationStyle(style:ArtzyNotificationStyle) { 28 | 29 | print("STYLE : \(style)") 30 | 31 | switch style { 32 | case .searching: 33 | self.previousState = .searching 34 | self.blink() 35 | break 36 | case .preview: 37 | self.hide() 38 | break 39 | case .itemFound: 40 | self.previousState = .itemFound 41 | self.greenLight() 42 | break 43 | case .error: 44 | self.previousState = .error 45 | self.redLight() 46 | break 47 | case .previous: 48 | self.updateNotificationStyle(style: self.previousState) 49 | break 50 | default: 51 | // Error 52 | break 53 | } 54 | 55 | } 56 | 57 | private func redLight() { 58 | self.removeBlink(); 59 | self.alpha = 1; 60 | self.layer.backgroundColor = UIColor.red.cgColor; 61 | } 62 | 63 | private func greenLight() { 64 | self.removeBlink(); 65 | self.alpha = 1; 66 | self.layer.backgroundColor = UIColor.green.cgColor; 67 | } 68 | 69 | private func hide() { 70 | self.removeBlink(); 71 | self.alpha = 0; 72 | } 73 | 74 | 75 | 76 | private func blink() { 77 | self.alpha = 1; 78 | 79 | flash.duration = 1.33 80 | flash.fromValue = 1 // alpha 81 | flash.toValue = 0 // alpha 82 | flash.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut) 83 | flash.autoreverses = true 84 | flash.repeatCount = HUGE; 85 | 86 | layer.add(flash, forKey: nil) 87 | } 88 | 89 | private func removeBlink() { 90 | layer.removeAllAnimations() 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /ArtzyCamera/HUD/NotificationView/NotificationView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotificationBarView.swift 3 | // ArtzyCamera 4 | // 5 | // Created by Oscar De la Hera Gomez on 12/4/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import AVFoundation 12 | 13 | enum ArtzyNotificationStyle { 14 | case searching 15 | case itemFound 16 | case preview 17 | case error 18 | case previous 19 | } 20 | 21 | class NotificationView: UIView { 22 | 23 | public var title:String = "searching..."; 24 | private var previousTitle:String = ""; 25 | private var notificationLabel:UILabel = UILabel(); 26 | 27 | 28 | 29 | override init(frame: CGRect) { 30 | super.init(frame: frame); 31 | 32 | artzyNotificationBlimp = NotificationBlimp(frame: kArtzyBlimpBaseRect); 33 | self.addSubview(artzyNotificationBlimp) 34 | 35 | self.notificationLabel.frame = kArtzyNotificationLabelRect; 36 | self.updateNotification(title: self.title, style:.searching); 37 | 38 | self.addSubview(self.notificationLabel); 39 | } 40 | 41 | required init?(coder aDecoder: NSCoder) { 42 | super.init(coder: aDecoder); 43 | } 44 | 45 | func generateAttributedTitle(string:String, size:CGFloat) -> NSMutableAttributedString{ 46 | return NSMutableAttributedString(string: string, attributes: [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont(name: "Helvetica", size: size)]); 47 | } 48 | 49 | 50 | // Update Title 51 | 52 | public func updateNotification(title:String, style:ArtzyNotificationStyle) { 53 | 54 | self.previousTitle = self.title; 55 | self.title = title; 56 | 57 | self.notificationLabel.attributedText = self.generateAttributedTitle(string: self.title, size: 18) 58 | self.notificationLabel.numberOfLines = 3 59 | 60 | self.notificationLabel.textAlignment = .center; 61 | self.notificationLabel.frame = kArtzyNotificationLabelRect 62 | self.notificationLabel.sizeToFit(); 63 | 64 | self.notificationLabel.frame = CGRect(x: kArtzyNotificationLabelRect.minX, y: kArtzyNotificationLabelRect.minY, width: kArtzyNotificationLabelRect.width, height: self.notificationLabel.frame.height) 65 | 66 | artzyNotificationBlimp.updateNotificationStyle(style:style); 67 | } 68 | 69 | public func returnToPreviousTitle() { 70 | self.title = self.previousTitle; 71 | 72 | self.notificationLabel.attributedText = self.generateAttributedTitle(string: self.title, size: 18) 73 | self.notificationLabel.numberOfLines = 3 74 | 75 | self.notificationLabel.textAlignment = .center; 76 | self.notificationLabel.frame = kArtzyNotificationLabelRect 77 | self.notificationLabel.sizeToFit(); 78 | self.notificationLabel.frame = CGRect(x: kArtzyNotificationLabelRect.minX, y: kArtzyNotificationLabelRect.minY, width: kArtzyNotificationLabelRect.width, height: self.notificationLabel.frame.height) 79 | 80 | artzyNotificationBlimp.updateNotificationStyle(style:.previous); 81 | } 82 | 83 | public func makeNotificationBlink() { 84 | 85 | 86 | } 87 | } 88 | 89 | -------------------------------------------------------------------------------- /ArtzyCamera/HUD/Preview/PreviewView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PreviewView.swift 3 | // Artzy 4 | // 5 | // Created by Oscar De la Hera Gomez on 12/3/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import AVFoundation 12 | 13 | enum ArtzyPreviewTypes { 14 | case image 15 | case video 16 | } 17 | 18 | class PreviewView: UIView { 19 | 20 | public var cameraHUDDelegate:CameraHUDDelegate? 21 | 22 | private var previewType:ArtzyPreviewTypes = .image; 23 | 24 | private var imageView:UIImageView = UIImageView() 25 | private var previewImage:UIImage = UIImage(); 26 | 27 | private var player:AVPlayer? 28 | private var playerLayer:AVPlayerLayer? 29 | private var videoURL:URL? 30 | 31 | private var saveButton:SaveButton = SaveButton(); 32 | private var cancelButton:CancelButton = CancelButton(); 33 | 34 | override init(frame: CGRect) { 35 | super.init(frame: frame); 36 | 37 | self.frame = CGRect(x: 0, y: 0, width: screenWidth, height: screenHeight); 38 | 39 | self.imageView.frame = self.frame; 40 | 41 | // Save button 42 | // let saveButtonWidth:CGFloat = screenWidth/4; 43 | // let saveButtonHeight:CGFloat = screenHeight/15; 44 | // self.saveButton.frame = CGRect(x: screenWidth - saveButtonWidth - kArtzyHUDButtonGap/2, y: (screenHeight*0.7-saveButtonHeight), width: saveButtonWidth, height: saveButtonHeight); 45 | // self.saveButton.setAttributedTitle(self.generateAttributedTitle(string: "save", size:18), for: .normal); 46 | self.saveButton.addTarget(self, action: #selector(self.saveButtonPressed), for: .touchUpInside); 47 | 48 | // Cancel button 49 | // SAME AS RESET BUTTON 50 | // self.cancelButton.frame = CGRect(x: kArtzyHUDButtonGap/2, y:kArtzyResetButtonMinY, width: kArtzyResetButtonDimension*1.25, height: kArtzyResetButtonDimension); 51 | // self.cancelButton.setAttributedTitle(self.generateAttributedTitle(string: "cancel", size:18), for: .normal); 52 | self.cancelButton.addTarget(self, action: #selector(self.cancelButtonPressed), for: .touchUpInside); 53 | 54 | // Loop Observer 55 | NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: self.player?.currentItem, queue: .main) { _ in 56 | self.player?.seek(to: CMTime.zero) 57 | self.player?.play() 58 | } 59 | } 60 | 61 | required init?(coder aDecoder: NSCoder) { 62 | super.init(coder: aDecoder); 63 | } 64 | 65 | func generateAttributedTitle(string:String, size:CGFloat) -> NSMutableAttributedString{ 66 | return NSMutableAttributedString(string: string, attributes: [NSAttributedString.Key.foregroundColor: UIColor.white, NSAttributedString.Key.font: UIFont(name: "Helvetica", size: size)]); 67 | } 68 | 69 | public func showPreviewView(withImage:UIImage) { 70 | self.previewType = .image; 71 | 72 | DispatchQueue.main.async { 73 | self.imageView.image = withImage; 74 | self.addSubview(self.imageView); 75 | 76 | // Add Buttons 77 | self.addSubview(self.saveButton); 78 | self.addSubview(self.cancelButton); 79 | artzyNotificationView.updateNotification(title: "preview", style: .preview); 80 | } 81 | 82 | // DispatchQueue.main.sync { 83 | // artzyNotificationView.updateNotification(title: "preview", style: .preview); 84 | // } 85 | } 86 | 87 | public func showPreviewView(withURL:URL) { 88 | 89 | self.previewType = .video; 90 | 91 | self.videoURL = withURL; 92 | self.createPreviewVideo(); 93 | 94 | DispatchQueue.main.sync { 95 | artzyNotificationView.updateNotification(title: "preview", style: .preview); 96 | } 97 | } 98 | 99 | private func hidePreviewView() { 100 | 101 | self.removePreview(); 102 | self.removeFromSuperview(); 103 | 104 | if self.previewType == .video { 105 | self.cameraHUDDelegate?.endAudioSession(); 106 | } 107 | } 108 | 109 | private func createPreviewVideo() { 110 | 111 | guard self.videoURL != nil else { 112 | print("No video url") 113 | return 114 | } 115 | 116 | self.player = AVPlayer(url: self.videoURL!); 117 | 118 | guard self.player != nil else { 119 | print("Failed to create player") 120 | return 121 | } 122 | 123 | self.playerLayer = AVPlayerLayer(); 124 | self.playerLayer? = AVPlayerLayer(player: self.player); 125 | self.playerLayer?.frame = self.frame; 126 | 127 | guard self.playerLayer != nil else { 128 | print("Failed to create player layer") 129 | return 130 | } 131 | 132 | 133 | 134 | 135 | // Bring buttons to front 136 | DispatchQueue.main.async { 137 | // Add Player Layer 138 | self.layer.addSublayer(self.playerLayer!); 139 | // Add Buttons 140 | self.addSubview(self.saveButton); 141 | self.addSubview(self.cancelButton); 142 | self.player!.play(); 143 | } 144 | 145 | 146 | 147 | } 148 | 149 | 150 | // MARK : BUTTON FUNCTIONALITY 151 | 152 | @objc private func saveButtonPressed() { 153 | 154 | if self.previewType == .video { 155 | self.cameraHUDDelegate?.exportVideo(); 156 | } 157 | else { 158 | self.cameraHUDDelegate?.saveImage(image: self.imageView.image!) 159 | } 160 | 161 | self.hidePreviewView(); 162 | } 163 | 164 | @objc private func cancelButtonPressed() { 165 | print("CANCEL BUTTON PRESSED"); 166 | self.hidePreviewView(); 167 | FileManager.default.clearTmpDirectory(); 168 | } 169 | 170 | // MARK : COMMON FUNCTIONALITY 171 | 172 | private func removePreview() { 173 | 174 | // Video 175 | 176 | self.player?.pause(); 177 | self.playerLayer?.removeFromSuperlayer(); 178 | 179 | self.player = nil; 180 | self.playerLayer = nil; 181 | 182 | self.saveButton.removeFromSuperview(); 183 | self.cancelButton.removeFromSuperview(); 184 | 185 | // Image 186 | 187 | self.imageView.image = nil; 188 | self.imageView.removeFromSuperview(); 189 | 190 | // Notification 191 | 192 | artzyNotificationView.returnToPreviousTitle(); 193 | 194 | } 195 | 196 | 197 | 198 | } 199 | -------------------------------------------------------------------------------- /ArtzyCamera/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSCameraUsageDescription 24 | This application will use the camera for Augmented Reality. 25 | NSLocationWhenInUseUsageDescription 26 | This application will use location for Augmented Reality. 27 | NSMicrophoneUsageDescription 28 | This application will use the camera to record Augmented Reality. 29 | NSPhotoLibraryAddUsageDescription 30 | This application will use the Photo Library to save media. 31 | NSPhotoLibraryUsageDescription 32 | This application will use the Photo Library to save media. 33 | UIMainStoryboardFile 34 | Main 35 | UIRequiredDeviceCapabilities 36 | 37 | armv7 38 | arkit 39 | 40 | UIRequiresFullScreen 41 | 42 | UIStatusBarHidden 43 | 44 | UISupportedInterfaceOrientations 45 | 46 | UIInterfaceOrientationPortrait 47 | 48 | UISupportedInterfaceOrientations~ipad 49 | 50 | UIInterfaceOrientationPortrait 51 | UIInterfaceOrientationPortraitUpsideDown 52 | UIInterfaceOrientationLandscapeLeft 53 | UIInterfaceOrientationLandscapeRight 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /ArtzyCamera/PieceOfArtzy/Functionality/ShaderFunctionality.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShaderFunctionality.swift 3 | // ArtzyCamera 4 | // 5 | // Created by Oscar De la Hera Gomez on 12/3/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ARKit 11 | 12 | extension PieceOfArtzy { 13 | 14 | // MARK: SHADERS 15 | 16 | func addColorShaderForChild(child: SCNNode, red:Float, blue:Float, green:Float) { 17 | let program = SCNProgram() 18 | var programType:String = "Color" 19 | program.fragmentFunctionName = programType+"SurfaceFragment" 20 | program.vertexFunctionName = programType+"VertexShader" 21 | program.isOpaque = false; 22 | 23 | // CREATE A MATERIAL, ADD THE PROGRAM, AND ADD IT TO THE CHILD. 24 | let shaderMaterial = SCNMaterial() 25 | shaderMaterial.program = program; 26 | shaderMaterial.transparencyMode = .rgbZero; 27 | shaderMaterial.isDoubleSided = true; 28 | shaderMaterial.blendMode = .alpha; 29 | shaderMaterial.writesToDepthBuffer = false 30 | shaderMaterial.readsFromDepthBuffer = false 31 | shaderMaterial.cullMode = .back 32 | shaderMaterial.lightingModel = .lambert; 33 | 34 | var TimeVariables:timedShaderVariablesStruct = timedShaderVariablesStruct.init(loopTime: 10, startTime: 0, endTime: 0, colorR:red, colorB:blue, colorG:green); 35 | shaderMaterial.setValue(Data(bytes: &TimeVariables, count: MemoryLayout.stride), forKey: "timeVariables"); 36 | 37 | child.geometry?.materials = [shaderMaterial]; 38 | } 39 | 40 | func addTextureShaderForChild(child: SCNNode, texture:UIImage) { 41 | let program = SCNProgram() 42 | var programType:String = "Texture" 43 | program.fragmentFunctionName = programType+"SurfaceFragment" 44 | program.vertexFunctionName = programType+"VertexShader" 45 | program.isOpaque = false; 46 | 47 | // CREATE A MATERIAL, ADD THE PROGRAM, AND ADD IT TO THE CHILD. 48 | let shaderMaterial = SCNMaterial() 49 | shaderMaterial.program = program; 50 | shaderMaterial.transparencyMode = .rgbZero; 51 | shaderMaterial.isDoubleSided = false; 52 | shaderMaterial.blendMode = .alpha; 53 | shaderMaterial.writesToDepthBuffer = true 54 | shaderMaterial.readsFromDepthBuffer = true 55 | shaderMaterial.cullMode = .back 56 | shaderMaterial.lightingModel = .lambert; 57 | 58 | let imageProperty = SCNMaterialProperty(contents: texture) 59 | shaderMaterial.setValue(imageProperty, forKey: "diffuseTexture") 60 | 61 | // var TimeVariables:timedShaderVariablesStruct = timedShaderVariablesStruct.init(loopTime: 10, startTime: 0, endTime: 0, colorR:red, colorB:blue, colorG:green); 62 | // shaderMaterial.setValue(Data(bytes: &TimeVariables, count: MemoryLayout.stride), forKey: "timeVariables"); 63 | 64 | child.geometry?.materials = [shaderMaterial]; 65 | } 66 | 67 | func addTimedStrokeShaderWithTimeForChild(child:SCNNode, loopTime:Float, startTime:Float, endTime:Float) { 68 | 69 | 70 | DispatchQueue.main.async { 71 | let program = SCNProgram() 72 | let programType:String = "TimedStroke" 73 | 74 | 75 | program.fragmentFunctionName = programType+"SurfaceFragment" 76 | program.vertexFunctionName = programType+"VertexShader" 77 | 78 | program.isOpaque = false; 79 | 80 | let shaderMaterial = SCNMaterial(); 81 | shaderMaterial.program = program; 82 | shaderMaterial.transparencyMode = .rgbZero; 83 | shaderMaterial.blendMode = .alpha; 84 | shaderMaterial.writesToDepthBuffer = false 85 | shaderMaterial.readsFromDepthBuffer = false 86 | shaderMaterial.cullMode = .back 87 | 88 | var firstStrokeTimeVariableStruct:strokeTimeVariableStruct = strokeTimeVariableStruct.init(loopTime: loopTime, startTime: startTime, endTime: endTime); 89 | shaderMaterial.setValue(Data(bytes: &firstStrokeTimeVariableStruct, count: MemoryLayout.stride), forKey: "timeVariables"); 90 | 91 | child.geometry?.materials = [shaderMaterial]; 92 | } 93 | } 94 | 95 | func addBackwardsTimedStrokeShaderWithTimeForChild(child:SCNNode, loopTime:Float, startTime:Float, endTime:Float) { 96 | 97 | 98 | DispatchQueue.main.async { 99 | let program = SCNProgram() 100 | let programType:String = "BackwardsTimedStroke" 101 | 102 | 103 | program.fragmentFunctionName = programType+"SurfaceFragment" 104 | program.vertexFunctionName = programType+"VertexShader" 105 | 106 | program.isOpaque = false; 107 | 108 | let shaderMaterial = SCNMaterial(); 109 | shaderMaterial.program = program; 110 | shaderMaterial.transparencyMode = .rgbZero; 111 | shaderMaterial.blendMode = .alpha; 112 | shaderMaterial.writesToDepthBuffer = false 113 | shaderMaterial.readsFromDepthBuffer = false 114 | shaderMaterial.cullMode = .back 115 | 116 | var firstStrokeTimeVariableStruct:strokeTimeVariableStruct = strokeTimeVariableStruct.init(loopTime: loopTime, startTime: startTime, endTime: endTime); 117 | shaderMaterial.setValue(Data(bytes: &firstStrokeTimeVariableStruct, count: MemoryLayout.stride), forKey: "timeVariables"); 118 | 119 | child.geometry?.materials = [shaderMaterial]; 120 | } 121 | } 122 | 123 | func addTimedStrokeTextureShaderWithTimeForChild(child:SCNNode, loopTime:Float, startTime:Float, endTime:Float) { 124 | 125 | 126 | DispatchQueue.main.async { 127 | let program = SCNProgram() 128 | let programType:String = "TimedStrokeTexture" 129 | 130 | 131 | program.fragmentFunctionName = programType+"SurfaceFragment" 132 | program.vertexFunctionName = programType+"VertexShader" 133 | 134 | program.isOpaque = false; 135 | 136 | let shaderMaterial = SCNMaterial(); 137 | shaderMaterial.program = program; 138 | shaderMaterial.transparencyMode = .rgbZero; 139 | shaderMaterial.blendMode = .alpha; 140 | shaderMaterial.writesToDepthBuffer = false 141 | shaderMaterial.readsFromDepthBuffer = false 142 | shaderMaterial.cullMode = .back 143 | 144 | var firstStrokeTimeVariableStruct:strokeTimeVariableStruct = strokeTimeVariableStruct.init(loopTime: loopTime, startTime: startTime, endTime: endTime); 145 | shaderMaterial.setValue(Data(bytes: &firstStrokeTimeVariableStruct, count: MemoryLayout.stride), forKey: "timeVariables"); 146 | 147 | child.geometry?.materials = [shaderMaterial]; 148 | } 149 | } 150 | 151 | func addBackwardsTimedStrokeTextureShaderWithTimeForChild(child:SCNNode, texture:UIImage, loopTime:Float, startTime:Float, endTime:Float) { 152 | 153 | 154 | DispatchQueue.main.async { 155 | let program = SCNProgram() 156 | let programType:String = "BackwardsTimedStrokeTexture" 157 | 158 | 159 | program.fragmentFunctionName = programType+"SurfaceFragment" 160 | program.vertexFunctionName = programType+"VertexShader" 161 | 162 | program.isOpaque = false; 163 | 164 | let shaderMaterial = SCNMaterial(); 165 | shaderMaterial.program = program; 166 | shaderMaterial.transparencyMode = .rgbZero; 167 | shaderMaterial.blendMode = .alpha; 168 | shaderMaterial.writesToDepthBuffer = true 169 | shaderMaterial.readsFromDepthBuffer = true 170 | shaderMaterial.cullMode = .back 171 | // shaderMaterial.diffuse.contents? = texture; 172 | shaderMaterial.lightingModel = .lambert; 173 | 174 | let imageProperty = SCNMaterialProperty(contents: texture) 175 | // The name you supply here should match the texture parameter name in the fragment shader 176 | shaderMaterial.setValue(imageProperty, forKey: "diffuseTexture") 177 | 178 | var firstStrokeTimeVariableStruct:strokeTimeVariableStruct = strokeTimeVariableStruct.init(loopTime: loopTime, startTime: startTime, endTime: endTime); 179 | shaderMaterial.setValue(Data(bytes: &firstStrokeTimeVariableStruct, count: MemoryLayout.stride), forKey: "timeVariables"); 180 | 181 | child.geometry?.materials = [shaderMaterial]; 182 | } 183 | } 184 | 185 | func getShaderMaterialWithTitle(title:String) -> SCNMaterial { 186 | 187 | let program = SCNProgram() 188 | 189 | program.fragmentFunctionName = title+"SurfaceFragment" 190 | program.vertexFunctionName = title+"VertexShader" 191 | 192 | program.isOpaque = false; 193 | 194 | let shaderMaterial = SCNMaterial(); 195 | shaderMaterial.program = program; 196 | shaderMaterial.transparencyMode = .rgbZero; 197 | shaderMaterial.blendMode = .alpha; 198 | shaderMaterial.writesToDepthBuffer = false 199 | shaderMaterial.readsFromDepthBuffer = false 200 | shaderMaterial.cullMode = .back 201 | 202 | return shaderMaterial 203 | } 204 | 205 | func addTimedVariablesToShaderWithNameAndChild(programName:String, child:SCNNode, loopTime:Float, startTime:Float, endTime:Float, colorR:Float, colorB:Float, colorG:Float) { 206 | 207 | 208 | DispatchQueue.main.async { 209 | let program = SCNProgram(); 210 | 211 | 212 | program.fragmentFunctionName = programName+"SurfaceFragment" 213 | program.vertexFunctionName = programName+"VertexShader" 214 | 215 | program.isOpaque = false; 216 | 217 | let shaderMaterial = SCNMaterial(); 218 | shaderMaterial.program = program; 219 | shaderMaterial.transparencyMode = .rgbZero; 220 | shaderMaterial.blendMode = .alpha; 221 | shaderMaterial.writesToDepthBuffer = true 222 | shaderMaterial.readsFromDepthBuffer = true 223 | shaderMaterial.cullMode = .back 224 | 225 | var timedShaderVariables:timedShaderVariablesStruct = timedShaderVariablesStruct.init(loopTime: loopTime, startTime: startTime, endTime: endTime, colorR: colorR, colorB: colorB, colorG: colorG) 226 | shaderMaterial.setValue(Data(bytes: &timedShaderVariables, count: MemoryLayout.stride), forKey: "timedShaderVariables"); 227 | 228 | child.geometry?.materials = [shaderMaterial]; 229 | } 230 | } 231 | 232 | 233 | func addStrokeShaderWithTimeForChild(child:SCNNode, loopTime:Float, startTime:Float, endTime:Float) { 234 | 235 | 236 | let program = SCNProgram() 237 | var programType:String = "TimedStroke" 238 | 239 | 240 | program.fragmentFunctionName = programType+"SurfaceFragment" 241 | program.vertexFunctionName = programType+"VertexShader" 242 | 243 | program.isOpaque = false; 244 | 245 | let shaderMaterial = SCNMaterial(); 246 | shaderMaterial.program = program; 247 | shaderMaterial.transparencyMode = .rgbZero; 248 | shaderMaterial.blendMode = .alpha; 249 | shaderMaterial.writesToDepthBuffer = false 250 | shaderMaterial.readsFromDepthBuffer = false 251 | shaderMaterial.cullMode = .back 252 | 253 | var firstStrokeTimeVariableStruct:strokeTimeVariableStruct = strokeTimeVariableStruct.init(loopTime: loopTime, startTime: startTime, endTime: endTime); 254 | //strokeTimeVariableStruct(loopTime: loopTime, startTime: startTime, endTime: endTime); 255 | shaderMaterial.setValue(Data(bytes: &firstStrokeTimeVariableStruct, count: MemoryLayout.stride), forKey: "timeVariables"); 256 | 257 | child.geometry?.materials = [shaderMaterial]; 258 | } 259 | 260 | } 261 | 262 | -------------------------------------------------------------------------------- /ArtzyCamera/PieceOfArtzy/PieceOfArtzy.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ArtzyItem.swift 3 | // ArtzyCamera 4 | // 5 | // Created by Oscar De la Hera Gomez on 12/3/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | import ARKit 12 | 13 | class PieceOfArtzy: NSObject, UITextFieldDelegate { 14 | 15 | public var node:SCNNode?; 16 | public var referenceImage:ARReferenceImage?; 17 | public var sceneView:ARSCNView?; 18 | public var artzyHUD:UIWindow?; 19 | 20 | 21 | public var isWithinFieldOfView:Bool = false; 22 | public var weight:Float = 0; 23 | public var offset:Float = 0; 24 | public var distanceToCamera:Float = 0; 25 | public let glowModifierView:UIView = UIView(); 26 | 27 | public func start() { 28 | 29 | DispatchQueue.main.sync { 30 | artzyNotificationView.updateNotification(title: "displaying \(self.referenceImage!.name!)", style: .itemFound); 31 | } 32 | 33 | if self.referenceImage!.name == "local by adamfu x delasign"{ 34 | // self.performAdamLocalStroke() 35 | self.performAdamLocalStatic() 36 | } 37 | 38 | else if self.referenceImage!.name == "artzy loader by delasign"{ 39 | self.performLoaderStroke(); 40 | } 41 | else if self.referenceImage!.name == "hand by delasign" { 42 | let scn:SCNScene? = SCNScene(named: "art.scnassets/hand.dae"); 43 | for child in scn!.rootNode.childNodes { 44 | self.node!.addChildNode(child) 45 | } 46 | 47 | 48 | scn?.rootNode.enumerateHierarchy({ (child, _) in 49 | print("Child : ", child); 50 | for key in child.animationKeys { 51 | print("KEY : ", key); 52 | let animation = child.animationPlayer(forKey: key)?.animation; 53 | animation?.repeatCount = CGFloat(HUGE); 54 | animation?.isRemovedOnCompletion = false; 55 | self.sceneView!.scene.rootNode.addAnimation(animation!, forKey: key); 56 | print(animation!) 57 | } 58 | }) 59 | } 60 | 61 | 62 | 63 | } 64 | var show:Float = 0; 65 | 66 | public func didUpdateAtTime() { 67 | self.show += 0.01 68 | 69 | if self.show > 1 { 70 | self.show = 0; 71 | } 72 | 73 | if self.referenceImage!.name == "artzy loader by delasign"{ 74 | 75 | let distance = simd_distance(self.node!.simdTransform.columns.3, (self.sceneView!.session.currentFrame?.camera.transform.columns.3)!); 76 | 77 | // Update distance to camera 78 | self.sceneView!.technique?.setObject(NSNumber(value: distance), forKeyedSubscript: "distanceSymbol" as NSCopying); 79 | 80 | for child in (self.node?.childNodes)! { 81 | 82 | let shaderMaterial:SCNMaterial = (child.geometry?.firstMaterial)!; 83 | 84 | // Update what should be shown of the model 85 | var displayVariables:DisplayVariableStruct = DisplayVariableStruct(show: self.show) 86 | shaderMaterial.setValue(Data(bytes: &displayVariables, count: MemoryLayout.stride), forKey: "displayVariables"); 87 | 88 | 89 | } 90 | 91 | } 92 | } 93 | 94 | 95 | 96 | public func setIsWithinFieldOfView(bool:Bool){ 97 | self.isWithinFieldOfView = bool; 98 | 99 | if bool { 100 | // VISIBLE 101 | self.showArtzyPieceHUD(); 102 | } 103 | else { 104 | // INVISIBLE 105 | self.hideArtzyPieceHUD() 106 | } 107 | } 108 | 109 | public func showArtzyPieceHUD() { 110 | 111 | } 112 | 113 | public func hideArtzyPieceHUD() { 114 | 115 | } 116 | 117 | // MARK : CREATOR TOOLS 118 | 119 | func showDetectionPlane() { 120 | // Create a plane to visualize the initial position of the detected image. 121 | let plane = SCNPlane(width: self.referenceImage!.physicalSize.width, 122 | height: self.referenceImage!.physicalSize.height) 123 | 124 | let planeNode = SCNNode(geometry: plane) 125 | planeNode.opacity = 0.25 126 | 127 | /* 128 | `SCNPlane` is vertically oriented in its local coordinate space, but 129 | `ARImageAnchor` assumes the image is horizontal in its local space, so 130 | rotate the plane to match. 131 | */ 132 | planeNode.eulerAngles.x = -.pi / 2 133 | 134 | /* 135 | Image anchors are not tracked after initial detection, so create an 136 | animation that limits the duration for which the plane visualization appears. 137 | */ 138 | planeNode.runAction(self.imageHighlightAction) 139 | 140 | // Add the plane visualization to the scene. 141 | self.node!.addChildNode(planeNode) 142 | } 143 | 144 | var imageHighlightAction: SCNAction { 145 | return .sequence([ 146 | .wait(duration: 0.25), 147 | .fadeOpacity(to: 0.85, duration: 0.25), 148 | .fadeOpacity(to: 0.15, duration: 0.25), 149 | .fadeOpacity(to: 0.85, duration: 0.25), 150 | .fadeOut(duration: 0.5), 151 | .removeFromParentNode() 152 | ]) 153 | } 154 | 155 | // Pieces 156 | 157 | // Local 158 | 159 | func performAdamLocalStatic() { 160 | let scn:SCNScene? = SCNScene(named: "art.scnassets/localxAdamfu.scn"); 161 | 162 | for child in scn!.rootNode.childNodes { 163 | child.categoryBitMask = 4; 164 | 165 | self.addColorShaderForChild(child: child, red: 1, blue: 1, green: 1); 166 | 167 | child.position = SCNVector3.init(child.position.x, child.position.y+0.1, child.position.z); 168 | 169 | if child.name! == "halo" { 170 | child.categoryBitMask = 3; 171 | child.position = SCNVector3.init(child.position.x, 0.074, child.position.z); 172 | } 173 | else if child.name! == "haloDrip" { 174 | child.categoryBitMask = 3; 175 | } 176 | 177 | self.node!.addChildNode(child); 178 | 179 | } 180 | 181 | DispatchQueue.main.sync { 182 | self.sceneView!.scene.rootNode.addChildNode(self.node!); 183 | } 184 | 185 | if let path = Bundle.main.path(forResource: "GlowInTwoColors", ofType: "plist") { 186 | if let dict = NSDictionary(contentsOfFile: path) { 187 | print("DICT EXISTS"); 188 | let dict2 = dict as! [String : AnyObject] 189 | let technique = SCNTechnique(dictionary:dict2) 190 | self.sceneView!.technique = technique 191 | } 192 | 193 | } 194 | } 195 | 196 | func performAdamLocalStroke() { 197 | 198 | let scn:SCNScene? = SCNScene(named: "art.scnassets/localxAdamfu.scn"); 199 | 200 | for child in scn!.rootNode.childNodes { 201 | child.categoryBitMask = 4; 202 | child.position = SCNVector3.init(child.position.x, child.position.y+0.1, child.position.z); 203 | 204 | let globalLoopTime:Float = 15; 205 | 206 | if child.name! == "local" { 207 | self.addStrokeShaderWithTimeForChild(child: child, loopTime: globalLoopTime, startTime: 0, endTime: 8); 208 | } 209 | else if child.name! == "drip1" { 210 | self.addStrokeShaderWithTimeForChild(child: child, loopTime: globalLoopTime, startTime: 0.25, endTime: 0.5); 211 | } 212 | else if child.name! == "drip2" { 213 | self.addStrokeShaderWithTimeForChild(child: child, loopTime: globalLoopTime, startTime: 1.75, endTime: 2.5); 214 | } 215 | else if child.name! == "drip3" { 216 | self.addStrokeShaderWithTimeForChild(child: child, loopTime: globalLoopTime, startTime: 2.75, endTime: 2.85); 217 | } 218 | else if child.name! == "drip4" { 219 | self.addStrokeShaderWithTimeForChild(child: child, loopTime: globalLoopTime, startTime: 3.15, endTime: 3.75); 220 | } 221 | else if child.name! == "drip5" { 222 | self.addStrokeShaderWithTimeForChild(child: child, loopTime: globalLoopTime, startTime: 4.1, endTime: 5.4); 223 | } 224 | else if child.name! == "drip6" { 225 | self.addStrokeShaderWithTimeForChild(child: child, loopTime: globalLoopTime, startTime: 7, endTime: 7.5); 226 | } 227 | else if child.name! == "drip7" { 228 | self.addStrokeShaderWithTimeForChild(child: child, loopTime: globalLoopTime, startTime: 7.05, endTime: 7.55); 229 | } 230 | else if child.name! == "drip8" { 231 | self.addStrokeShaderWithTimeForChild(child: child, loopTime: globalLoopTime, startTime: 8, endTime: 8.5); 232 | } 233 | else if child.name! == "halo" { 234 | child.categoryBitMask = 3; 235 | child.position = SCNVector3.init(child.position.x, 0.074, child.position.z); 236 | self.addStrokeShaderWithTimeForChild(child: child, loopTime: globalLoopTime, startTime: 8, endTime: 9); 237 | } 238 | else if child.name! == "haloDrip" { 239 | child.categoryBitMask = 3; 240 | self.addStrokeShaderWithTimeForChild(child: child, loopTime: globalLoopTime, startTime: 9, endTime: 9.5); 241 | } 242 | 243 | 244 | self.node!.addChildNode(child); 245 | 246 | } 247 | 248 | DispatchQueue.main.sync { 249 | self.sceneView!.scene.rootNode.addChildNode(self.node!); 250 | } 251 | 252 | if let path = Bundle.main.path(forResource: "GlowInTwoColors", ofType: "plist") { 253 | if let dict = NSDictionary(contentsOfFile: path) { 254 | print("DICT EXISTS"); 255 | let dict2 = dict as! [String : AnyObject] 256 | let technique = SCNTechnique(dictionary:dict2) 257 | self.sceneView!.technique = technique 258 | } 259 | 260 | } 261 | 262 | } 263 | 264 | // Loader 265 | 266 | func performLoaderStroke() { 267 | DispatchQueue.main.async { 268 | 269 | let scnName:String = "art.scnassets/logo.scn"; 270 | 271 | let scn:SCNScene? = SCNScene(named: scnName); //cylinder 272 | print("update node"); 273 | 274 | for child in scn!.rootNode.childNodes { 275 | 276 | child.categoryBitMask = 1; 277 | 278 | print("Child : ", child.name); 279 | let scaleFactor:Float = 1; 280 | child.scale = SCNVector3.init(scaleFactor*child.scale.x,scaleFactor*child.scale.y, scaleFactor*child.scale.z); 281 | child.position = SCNVector3.init(child.position.x*scaleFactor, 0.1, child.position.z*scaleFactor); 282 | 283 | // self.addColorShaderForChild(child: child, red: 1, blue: 1, green: 1); 284 | self.addBackwardsTimedStrokeShaderWithTimeForChild(child: child, loopTime: 10, startTime: 0, endTime: 5); 285 | self.node!.addChildNode(child); 286 | } 287 | 288 | self.sceneView!.scene.rootNode.addChildNode(self.node!); 289 | 290 | if let path = Bundle.main.path(forResource: "Glow", ofType: "plist") { 291 | if let dict = NSDictionary(contentsOfFile: path) { 292 | print("DICT EXISTS"); 293 | let dict2 = dict as! [String : AnyObject] 294 | let technique = SCNTechnique(dictionary:dict2) 295 | self.sceneView!.technique = technique 296 | } 297 | } 298 | 299 | 300 | self.offset = 1.5; 301 | self.weight = 0.175; 302 | 303 | self.sceneView!.technique?.setObject(NSNumber(value: 0.6352941176), forKeyedSubscript: "redSymbol" as NSCopying); 304 | self.sceneView!.technique?.setObject(NSNumber(value: 0.1254901961), forKeyedSubscript: "greenSymbol" as NSCopying); 305 | self.sceneView!.technique?.setObject(NSNumber(value: 0.4), forKeyedSubscript: "blueSymbol" as NSCopying); 306 | self.sceneView!.technique?.setObject(NSNumber(value: self.offset), forKeyedSubscript: "offsetSymbol" as NSCopying); 307 | self.sceneView!.technique?.setObject(NSNumber(value: self.weight), forKeyedSubscript: "weightSymbol" as NSCopying); 308 | 309 | self.sceneView!.technique?.setObject(NSNumber(value: 1), forKeyedSubscript: "distanceSymbol" as NSCopying); 310 | 311 | } 312 | } 313 | 314 | 315 | 316 | } 317 | -------------------------------------------------------------------------------- /ArtzyCamera/PieceOfArtzy/Shaders/Fade/FadeIn.metal: -------------------------------------------------------------------------------- 1 | // 2 | // Glow.swift 3 | // Artzy 4 | // 5 | // Created by Oscar De la Hera Gomez on 8/12/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | #include 10 | using namespace metal; 11 | #include 12 | 13 | struct NodeBuffer { 14 | float4x4 modelTransform; 15 | float4x4 modelViewTransform; 16 | float4x4 normalTransform; 17 | float4x4 modelViewProjectionTransform; 18 | float2x3 boundingBox; 19 | 20 | float4x4 viewTransform; 21 | float4x4 inverseViewTransform; // view space to world space 22 | float4x4 projectionTransform; 23 | float4x4 viewProjectionTransform; 24 | float4x4 viewToCubeTransform; // view space to cube texture space (right-handed, y-axis-up) 25 | float4 ambientLightingColor; 26 | float4 fogColor; 27 | float3 fogParameters; // x: -1/(end-start) y: 1-start*x z: exponent 28 | float time; // system time elapsed since first render with this shader 29 | float sinTime; // precalculated sin(time) 30 | float cosTime; // precalculated cos(time) 31 | float random01; // random value between 0.0 and 1.0 32 | }; 33 | 34 | typedef struct { 35 | float3 position [[ attribute(SCNVertexSemanticPosition) ]]; 36 | float2 texCoords0 [[ attribute(SCNVertexSemanticTexcoord0) ]]; 37 | half4 color [[ attribute(SCNVertexSemanticColor)]]; 38 | 39 | } VertexInput; 40 | 41 | //static float rand(float2 uv) 42 | //{ 43 | // return fract(sin(dot(uv, float2(12.9898, 78.233))) * 43758.5453); 44 | //} 45 | // 46 | //static float2 uv2tri(float2 uv) 47 | //{ 48 | // float sx = uv.x - uv.y / 2; 49 | // float sxf = fract(sx); 50 | // float offs = step(fract(1 - uv.y), sxf); 51 | // return float2(floor(sx) * 2 + sxf + offs, uv.y); 52 | //} 53 | 54 | constant float milestoneTimeBreadth = 5; 55 | 56 | 57 | struct Vertex 58 | { 59 | float4 position [[position]]; 60 | float2 uv; 61 | half4 color; 62 | float2 texCoords [[user(tex_coords)]]; 63 | float time; 64 | }; 65 | 66 | vertex Vertex fadeInVertexShader(VertexInput in [[ stage_in ]], 67 | uint vertexID [[vertex_id]], 68 | constant SCNSceneBuffer& scn_frame [[buffer(0)]], 69 | constant NodeBuffer& scn_node [[buffer(1)]]) 70 | { 71 | Vertex vert; 72 | float alpha = 0.1; 73 | vert.color = half4( half3(1,1,1), alpha); 74 | vert.uv = in.texCoords0; 75 | vert.time = scn_frame.time; 76 | vert.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0); 77 | return vert; 78 | } 79 | 80 | 81 | 82 | fragment half4 fadeInSurfaceFragment(Vertex in [[stage_in]], 83 | constant SCNSceneBuffer& scn_frame [[buffer(0)]], 84 | constant NodeBuffer& scn_node [[buffer(1)]], 85 | texture2d texture [[texture(0)]], 86 | sampler texSampler [[sampler(0)]]) 87 | { 88 | float timerMilestone = floor(in.time/milestoneTimeBreadth); 89 | float currentTime = in.time; 90 | float timer = (currentTime - timerMilestone*milestoneTimeBreadth); 91 | 92 | 93 | half4 fragColor; 94 | fragColor.rgb = half3(in.color.rgb); 95 | fragColor.a = in.color.a; 96 | fragColor.rgb *= fragColor.a*timer; 97 | return fragColor; 98 | 99 | } 100 | -------------------------------------------------------------------------------- /ArtzyCamera/PieceOfArtzy/Shaders/Fade/FadeInTexture.metal: -------------------------------------------------------------------------------- 1 | // 2 | // FadeInTexture.metal 3 | // Artzy 4 | // 5 | // Created by Oscar De la Hera Gomez on 8/12/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | #include 10 | using namespace metal; 11 | #include 12 | 13 | struct NodeBuffer { 14 | float4x4 modelTransform; 15 | float4x4 modelViewTransform; 16 | float4x4 normalTransform; 17 | float4x4 modelViewProjectionTransform; 18 | float2x3 boundingBox; 19 | 20 | float4x4 viewTransform; 21 | float4x4 inverseViewTransform; // view space to world space 22 | float4x4 projectionTransform; 23 | float4x4 viewProjectionTransform; 24 | float4x4 viewToCubeTransform; // view space to cube texture space (right-handed, y-axis-up) 25 | float4 ambientLightingColor; 26 | float4 fogColor; 27 | float3 fogParameters; // x: -1/(end-start) y: 1-start*x z: exponent 28 | float time; // system time elapsed since first render with this shader 29 | float sinTime; // precalculated sin(time) 30 | float cosTime; // precalculated cos(time) 31 | float random01; // random value between 0.0 and 1.0 32 | }; 33 | 34 | typedef struct { 35 | float3 position [[ attribute(SCNVertexSemanticPosition) ]]; 36 | float2 texCoords0 [[ attribute(SCNVertexSemanticTexcoord0) ]]; 37 | half4 color [[ attribute(SCNVertexSemanticColor)]]; 38 | 39 | } VertexInput; 40 | 41 | //static float rand(float2 uv) 42 | //{ 43 | // return fract(sin(dot(uv, float2(12.9898, 78.233))) * 43758.5453); 44 | //} 45 | // 46 | //static float2 uv2tri(float2 uv) 47 | //{ 48 | // float sx = uv.x - uv.y / 2; 49 | // float sxf = fract(sx); 50 | // float offs = step(fract(1 - uv.y), sxf); 51 | // return float2(floor(sx) * 2 + sxf + offs, uv.y); 52 | //} 53 | 54 | constant float milestoneTimeBreadth = 5; 55 | 56 | 57 | struct Vertex 58 | { 59 | float4 position [[position]]; 60 | float2 uv; 61 | half4 color; 62 | // float2 texCoords [[user(tex_coords)]]; 63 | float2 texCoords; 64 | float time; 65 | }; 66 | 67 | vertex Vertex fadeInTextureVertexShader(VertexInput in [[ stage_in ]], 68 | uint vertexID [[vertex_id]], 69 | constant SCNSceneBuffer& scn_frame [[buffer(0)]], 70 | constant NodeBuffer& scn_node [[buffer(1)]]) 71 | { 72 | Vertex vert; 73 | 74 | // float alpha = 0.2; 75 | // 76 | // vert.color = half4( half3(1,1,1), alpha); 77 | vert.texCoords = in.texCoords0[vertexID]; 78 | vert.uv = in.texCoords0; 79 | vert.time = scn_frame.time; 80 | vert.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0); 81 | return vert; 82 | } 83 | 84 | 85 | 86 | fragment half4 fadeInTextureSurfaceFragment(Vertex in [[stage_in]], 87 | constant SCNSceneBuffer& scn_frame [[buffer(0)]], 88 | constant NodeBuffer& scn_node [[buffer(1)]], 89 | texture2d diffuseTexture [[texture(0)]]) 90 | { 91 | 92 | constexpr sampler sampler2d(coord::normalized, filter::linear, address::repeat); 93 | float4 color = diffuseTexture.sample(sampler2d, in.texCoords); 94 | 95 | float timerMilestone = floor(in.time/milestoneTimeBreadth); 96 | float currentTime = in.time; 97 | float timer = (currentTime - timerMilestone*milestoneTimeBreadth); 98 | 99 | 100 | half4 fragColor; 101 | fragColor.rgb = half3(color.rgb); 102 | fragColor.a = 0.2*timer; 103 | // fragColor.a = 1*timer;//in.color.a 104 | fragColor.rgb *= fragColor.a; 105 | return fragColor; 106 | 107 | } 108 | -------------------------------------------------------------------------------- /ArtzyCamera/PieceOfArtzy/Shaders/Standard/Color.metal: -------------------------------------------------------------------------------- 1 | // 2 | // Color.metal 3 | // Artzy 4 | // 5 | // Created by Oscar De la Hera Gomez on 9/5/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | #include 10 | using namespace metal; 11 | #include 12 | 13 | struct NodeBuffer { 14 | float4x4 modelTransform; 15 | float4x4 modelViewTransform; 16 | float4x4 normalTransform; 17 | float4x4 modelViewProjectionTransform; 18 | float2x3 boundingBox; 19 | 20 | float4x4 viewTransform; 21 | float4x4 inverseViewTransform; // view space to world space 22 | float4x4 projectionTransform; 23 | float4x4 viewProjectionTransform; 24 | float4x4 viewToCubeTransform; // view space to cube texture space (right-handed, y-axis-up) 25 | float4 ambientLightingColor; 26 | float4 fogColor; 27 | float3 fogParameters; // x: -1/(end-start) y: 1-start*x z: exponent 28 | float time; // system time elapsed since first render with this shader 29 | float sinTime; // precalculated sin(time) 30 | float cosTime; // precalculated cos(time) 31 | float random01; // random value between 0.0 and 1.0 32 | }; 33 | 34 | typedef struct { 35 | float3 position [[ attribute(SCNVertexSemanticPosition) ]]; 36 | float2 texCoords0 [[ attribute(SCNVertexSemanticTexcoord0) ]]; 37 | half4 color [[ attribute(SCNVertexSemanticColor)]]; 38 | 39 | } VertexInput; 40 | 41 | struct TimeVariables { 42 | float loopTime; 43 | float startTime; 44 | float endTime; 45 | float red; 46 | float blue; 47 | float green; 48 | }; 49 | 50 | 51 | struct Vertex 52 | { 53 | float4 position [[position]]; 54 | float2 uv; 55 | half4 color; 56 | float2 texCoords [[user(tex_coords)]]; 57 | float time; 58 | }; 59 | 60 | vertex Vertex ColorVertexShader(VertexInput in [[ stage_in ]], 61 | uint vertexID [[vertex_id]], 62 | constant SCNSceneBuffer& scn_frame [[buffer(0)]], 63 | constant NodeBuffer& scn_node [[buffer(1)]], 64 | constant TimeVariables& timeVariables [[buffer(2)]]) 65 | { 66 | Vertex vert; 67 | vert.color = half4( half3(timeVariables.red, timeVariables.blue, timeVariables.green), 1); 68 | vert.uv = in.texCoords0; 69 | vert.time = scn_frame.time; 70 | vert.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0); 71 | return vert; 72 | } 73 | 74 | 75 | 76 | fragment half4 ColorSurfaceFragment(Vertex in [[stage_in]], 77 | constant SCNSceneBuffer& scn_frame [[buffer(0)]], 78 | constant NodeBuffer& scn_node [[buffer(1)]], 79 | texture2d texture [[texture(0)]], 80 | sampler texSampler [[sampler(0)]], 81 | constant TimeVariables& timeVariables [[buffer(2)]]) 82 | { 83 | half4 fragColor; 84 | fragColor.rgb = half3(in.color.rgb); 85 | fragColor.a = in.color.a; 86 | fragColor *= in.color.a; 87 | return fragColor; 88 | } 89 | 90 | -------------------------------------------------------------------------------- /ArtzyCamera/PieceOfArtzy/Shaders/Standard/Texture.metal: -------------------------------------------------------------------------------- 1 | // 2 | // Texture.metal 3 | // Artzy 4 | // 5 | // Created by Oscar De la Hera Gomez on 8/12/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | #include 10 | using namespace metal; 11 | #include 12 | 13 | struct NodeBuffer { 14 | float4x4 modelTransform; 15 | float4x4 modelViewTransform; 16 | float4x4 normalTransform; 17 | float4x4 modelViewProjectionTransform; 18 | float2x3 boundingBox; 19 | 20 | float4x4 viewTransform; 21 | float4x4 inverseViewTransform; // view space to world space 22 | float4x4 projectionTransform; 23 | float4x4 viewProjectionTransform; 24 | float4x4 viewToCubeTransform; // view space to cube texture space (right-handed, y-axis-up) 25 | float4 ambientLightingColor; 26 | float4 fogColor; 27 | float3 fogParameters; // x: -1/(end-start) y: 1-start*x z: exponent 28 | float time; // system time elapsed since first render with this shader 29 | float sinTime; // precalculated sin(time) 30 | float cosTime; // precalculated cos(time) 31 | float random01; // random value between 0.0 and 1.0 32 | }; 33 | 34 | typedef struct { 35 | float3 position [[ attribute(SCNVertexSemanticPosition) ]]; 36 | float2 texCoords0 [[ attribute(SCNVertexSemanticTexcoord0) ]]; 37 | half4 color [[ attribute(SCNVertexSemanticColor)]]; 38 | 39 | } VertexInput; 40 | 41 | 42 | 43 | struct Vertex 44 | { 45 | float4 position [[position]]; 46 | float2 uv; 47 | half4 color; 48 | float2 texCoords; 49 | float time; 50 | }; 51 | 52 | vertex Vertex TextureVertexShader(VertexInput in [[ stage_in ]], 53 | uint vertexID [[vertex_id]], 54 | constant SCNSceneBuffer& scn_frame [[buffer(0)]], 55 | constant NodeBuffer& scn_node [[buffer(1)]]) 56 | { 57 | Vertex vert; 58 | vert.texCoords = in.texCoords0; 59 | vert.time = scn_frame.time; 60 | vert.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0); 61 | return vert; 62 | } 63 | 64 | 65 | 66 | fragment half4 TextureSurfaceFragment(Vertex in [[stage_in]], 67 | constant SCNSceneBuffer& scn_frame [[buffer(0)]], 68 | constant NodeBuffer& scn_node [[buffer(1)]], 69 | texture2d diffuseTexture [[texture(1)]]) 70 | { 71 | 72 | constexpr sampler sampler2d(coord::normalized, filter::linear, address::repeat); 73 | float4 color = diffuseTexture.sample(sampler2d, in.texCoords); 74 | return half4(color); 75 | 76 | } 77 | -------------------------------------------------------------------------------- /ArtzyCamera/PieceOfArtzy/Shaders/Stroke/BackwardStroke.metal: -------------------------------------------------------------------------------- 1 | // 2 | // BackwardStroke.swift 3 | // Artzy 4 | // 5 | // Created by Oscar De la Hera Gomez on 8/12/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | #include 10 | using namespace metal; 11 | #include 12 | 13 | struct NodeBuffer { 14 | float4x4 modelTransform; 15 | float4x4 modelViewTransform; 16 | float4x4 normalTransform; 17 | float4x4 modelViewProjectionTransform; 18 | float2x3 boundingBox; 19 | 20 | float4x4 viewTransform; 21 | float4x4 inverseViewTransform; // view space to world space 22 | float4x4 projectionTransform; 23 | float4x4 viewProjectionTransform; 24 | float4x4 viewToCubeTransform; // view space to cube texture space (right-handed, y-axis-up) 25 | float4 ambientLightingColor; 26 | float4 fogColor; 27 | float3 fogParameters; // x: -1/(end-start) y: 1-start*x z: exponent 28 | float time; // system time elapsed since first render with this shader 29 | float sinTime; // precalculated sin(time) 30 | float cosTime; // precalculated cos(time) 31 | float random01; // random value between 0.0 and 1.0 32 | }; 33 | 34 | typedef struct { 35 | float3 position [[ attribute(SCNVertexSemanticPosition) ]]; 36 | float2 texCoords0 [[ attribute(SCNVertexSemanticTexcoord0) ]]; 37 | half4 color [[ attribute(SCNVertexSemanticColor)]]; 38 | 39 | } VertexInput; 40 | 41 | //static float rand(float2 uv) 42 | //{ 43 | // return fract(sin(dot(uv, float2(12.9898, 78.233))) * 43758.5453); 44 | //} 45 | // 46 | //static float2 uv2tri(float2 uv) 47 | //{ 48 | // float sx = uv.x - uv.y / 2; 49 | // float sxf = fract(sx); 50 | // float offs = step(fract(1 - uv.y), sxf); 51 | // return float2(floor(sx) * 2 + sxf + offs, uv.y); 52 | //} 53 | 54 | constant float milestoneTimeBreadth = 5; 55 | 56 | 57 | struct Vertex 58 | { 59 | float4 position [[position]]; 60 | float2 uv; 61 | half4 color; 62 | float2 texCoords [[user(tex_coords)]]; 63 | float time; 64 | }; 65 | 66 | vertex Vertex backwardStrokeVertexShader(VertexInput in [[ stage_in ]], 67 | uint vertexID [[vertex_id]], 68 | constant SCNSceneBuffer& scn_frame [[buffer(0)]], 69 | constant NodeBuffer& scn_node [[buffer(1)]]) 70 | { 71 | Vertex vert; 72 | float alpha = 1; 73 | vert.color = half4( half3(1,1,1), alpha); 74 | vert.uv = in.texCoords0; 75 | vert.time = scn_frame.time; 76 | vert.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0); 77 | return vert; 78 | } 79 | 80 | 81 | 82 | fragment half4 backwardStrokeSurfaceFragment(Vertex in [[stage_in]], 83 | constant SCNSceneBuffer& scn_frame [[buffer(0)]], 84 | constant NodeBuffer& scn_node [[buffer(1)]], 85 | texture2d texture [[texture(0)]], 86 | sampler texSampler [[sampler(0)]]) 87 | { 88 | float timerMilestone = floor(in.time/milestoneTimeBreadth); 89 | float currentTime = in.time; 90 | float timer = (currentTime - timerMilestone*milestoneTimeBreadth); 91 | 92 | float2 vUv = in.uv; 93 | 94 | if (in.uv.y > timer/milestoneTimeBreadth) { 95 | discard_fragment(); 96 | } 97 | 98 | half4 fragColor; 99 | fragColor.rgb = half3(in.color.rgb); 100 | fragColor.a = in.color.a; 101 | // fragColor.rgb *= fragColor.a; 102 | return fragColor; 103 | 104 | } 105 | -------------------------------------------------------------------------------- /ArtzyCamera/PieceOfArtzy/Shaders/Stroke/BackwardsTimedStroke.metal: -------------------------------------------------------------------------------- 1 | // 2 | // BackwardsTimedStroke.metal 3 | // ArtzyCamera 4 | // 5 | // Created by Oscar De la Hera Gomez on 12/6/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | 10 | #include 11 | using namespace metal; 12 | #include 13 | 14 | 15 | struct NodeBuffer { 16 | float4x4 modelTransform; 17 | float4x4 modelViewTransform; 18 | float4x4 normalTransform; 19 | float4x4 modelViewProjectionTransform; 20 | float2x3 boundingBox; 21 | 22 | float4x4 viewTransform; 23 | float4x4 inverseViewTransform; // view space to world space 24 | float4x4 projectionTransform; 25 | float4x4 viewProjectionTransform; 26 | float4x4 viewToCubeTransform; // view space to cube texture space (right-handed, y-axis-up) 27 | float4 ambientLightingColor; 28 | float4 fogColor; 29 | float3 fogParameters; // x: -1/(end-start) y: 1-start*x z: exponent 30 | float time; // system time elapsed since first render with this shader 31 | float sinTime; // precalculated sin(time) 32 | float cosTime; // precalculated cos(time) 33 | float random01; // random value between 0.0 and 1.0 34 | }; 35 | 36 | typedef struct { 37 | float3 position [[ attribute(SCNVertexSemanticPosition) ]]; 38 | float2 texCoords0 [[ attribute(SCNVertexSemanticTexcoord0) ]]; 39 | half4 color [[ attribute(SCNVertexSemanticColor)]]; 40 | 41 | } VertexInput; 42 | 43 | 44 | //constant float loopTime = 10; // In Seconds 45 | //constant float startTime = 1.25; 46 | //constant float endTime = 9.25; 47 | 48 | struct TimeVariables { 49 | float loopTime; 50 | float startTime; 51 | float endTime; 52 | }; 53 | 54 | struct DisplayVariables { 55 | float show; 56 | }; 57 | 58 | struct Vertex 59 | { 60 | float4 position [[position]]; 61 | float2 uv; 62 | half4 color; 63 | float2 texCoords [[user(tex_coords)]]; 64 | float time; 65 | float4 modelViewProjectionTransformColumn; 66 | }; 67 | 68 | vertex Vertex BackwardsTimedStrokeVertexShader(VertexInput in [[ stage_in ]], 69 | uint vertexID [[vertex_id]], 70 | constant SCNSceneBuffer& scn_frame [[buffer(0)]], 71 | constant NodeBuffer& scn_node [[buffer(1)]]) 72 | { 73 | Vertex vert; 74 | vert.color = half4( half3(1,1,1), 0.1); 75 | vert.uv = in.texCoords0; 76 | vert.time = scn_frame.time; 77 | vert.modelViewProjectionTransformColumn = scn_node.modelViewProjectionTransform[3]; 78 | vert.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0); 79 | return vert; 80 | } 81 | 82 | 83 | 84 | fragment half4 BackwardsTimedStrokeSurfaceFragment(Vertex in [[stage_in]], 85 | constant SCNSceneBuffer& scn_frame [[buffer(0)]], 86 | constant NodeBuffer& scn_node [[buffer(1)]], 87 | constant TimeVariables& timeVariables [[buffer(2)]], 88 | constant DisplayVariables& displayVariables [[buffer(3)]]) 89 | { 90 | 91 | // float currentTime = in.time; 92 | // float timerMilestone = floor(currentTime/timeVariables.loopTime); 93 | // 94 | // float loopTimer = (currentTime - timerMilestone*timeVariables.loopTime); 95 | // 96 | // if ( loopTimer < timeVariables.startTime) { 97 | // // hasnt started 98 | // discard_fragment(); 99 | // } 100 | // else if (loopTimer < timeVariables.endTime) { 101 | // // has started 102 | // 103 | // float showUVsIfSmallerThan = (loopTimer-timeVariables.startTime)/(timeVariables.endTime-timeVariables.startTime); 104 | // 105 | // if ((in.uv.y) > showUVsIfSmallerThan) { 106 | // // These Are Invalid, remove 107 | // discard_fragment(); 108 | // } 109 | // 110 | // } 111 | // else { 112 | // // SHOW ALL 113 | // } 114 | 115 | if ((in.uv.y) > displayVariables.show) { 116 | // These Are Invalid, remove 117 | discard_fragment(); 118 | } 119 | else { 120 | // show 121 | } 122 | 123 | 124 | 125 | half4 fragColor; 126 | fragColor.rgb = half3(in.color.rgb); 127 | fragColor.a = in.color.a; 128 | // fragColor.rgb *= fragColor.a; 129 | return fragColor; 130 | 131 | } 132 | -------------------------------------------------------------------------------- /ArtzyCamera/PieceOfArtzy/Shaders/Stroke/BackwardsTimedStrokeTexture.metal: -------------------------------------------------------------------------------- 1 | // 2 | // BackwardsTimedStrokeTexture.metal 3 | // Artzy 4 | // 5 | // Created by Oscar De la Hera Gomez on 11/19/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | #include 10 | using namespace metal; 11 | #include 12 | 13 | struct NodeBuffer { 14 | float4x4 modelTransform; 15 | float4x4 modelViewTransform; 16 | float4x4 normalTransform; 17 | float4x4 modelViewProjectionTransform; 18 | float2x3 boundingBox; 19 | 20 | float4x4 viewTransform; 21 | float4x4 inverseViewTransform; // view space to world space 22 | float4x4 projectionTransform; 23 | float4x4 viewProjectionTransform; 24 | float4x4 viewToCubeTransform; // view space to cube texture space (right-handed, y-axis-up) 25 | float4 ambientLightingColor; 26 | float4 fogColor; 27 | float3 fogParameters; // x: -1/(end-start) y: 1-start*x z: exponent 28 | float time; // system time elapsed since first render with this shader 29 | float sinTime; // precalculated sin(time) 30 | float cosTime; // precalculated cos(time) 31 | float random01; // random value between 0.0 and 1.0 32 | }; 33 | 34 | typedef struct { 35 | float3 position [[ attribute(SCNVertexSemanticPosition) ]]; 36 | float2 texCoords0 [[ attribute(SCNVertexSemanticTexcoord0) ]]; 37 | half4 color [[ attribute(SCNVertexSemanticColor)]]; 38 | 39 | } VertexInput; 40 | 41 | 42 | struct Vertex 43 | { 44 | float4 position [[position]]; 45 | float2 uv; 46 | half4 color; 47 | // float2 texCoords [[user(tex_coords)]]; 48 | float2 texCoords; 49 | float time; 50 | }; 51 | 52 | struct TimeVariables { 53 | float loopTime; 54 | float startTime; 55 | float endTime; 56 | }; 57 | 58 | vertex Vertex BackwardsTimedStrokeTextureVertexShader(VertexInput in [[ stage_in ]], 59 | uint vertexID [[vertex_id]], 60 | constant SCNSceneBuffer& scn_frame [[buffer(0)]], 61 | constant NodeBuffer& scn_node [[buffer(1)]]) 62 | { 63 | Vertex vert; 64 | 65 | // float alpha = 0.2; 66 | // 67 | // vert.color = half4( half3(1,1,1), alpha); 68 | vert.texCoords = in.texCoords0; 69 | vert.uv = in.texCoords0; 70 | vert.time = scn_frame.time; 71 | vert.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0); 72 | return vert; 73 | } 74 | 75 | 76 | 77 | fragment half4 BackwardsTimedStrokeTextureSurfaceFragment(Vertex in [[stage_in]], 78 | constant SCNSceneBuffer& scn_frame [[buffer(0)]], 79 | constant NodeBuffer& scn_node [[buffer(1)]], 80 | texture2d diffuseTexture [[texture(0)]], 81 | constant TimeVariables& timeVariables [[buffer(2)]]) 82 | { 83 | constexpr sampler sampler2d(coord::normalized, filter::linear, address::repeat); 84 | float4 color = diffuseTexture.sample(sampler2d, in.texCoords); 85 | 86 | float currentTime = in.time; 87 | float timerMilestone = floor(currentTime/timeVariables.loopTime); 88 | 89 | float loopTimer = (currentTime - timerMilestone*timeVariables.loopTime); 90 | 91 | if ( loopTimer < timeVariables.startTime) { 92 | // hasnt started 93 | discard_fragment(); 94 | } 95 | else if (loopTimer < timeVariables.endTime) { 96 | // has started 97 | 98 | float showUVsIfSmallerThan = (loopTimer-timeVariables.startTime)/(timeVariables.endTime-timeVariables.startTime); 99 | 100 | if ((in.uv.y) > showUVsIfSmallerThan) { 101 | // These Are Invalid, remove 102 | discard_fragment(); 103 | } 104 | 105 | } 106 | else { 107 | // SHOW ALL 108 | } 109 | 110 | half4 fragColor; 111 | fragColor.rgb = half3(color.rgb); 112 | fragColor.a = color.a; 113 | // fragColor.rgb *= fragColor.a; 114 | return fragColor; 115 | 116 | } 117 | -------------------------------------------------------------------------------- /ArtzyCamera/PieceOfArtzy/Shaders/Stroke/Stroke.metal: -------------------------------------------------------------------------------- 1 | // 2 | // Stroke.swift 3 | // Delasign 4 | // 5 | // Created by Oscar De la Hera Gomez on 8/12/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | #include 10 | using namespace metal; 11 | #include 12 | 13 | struct NodeBuffer { 14 | float4x4 modelTransform; 15 | float4x4 modelViewTransform; 16 | float4x4 normalTransform; 17 | float4x4 modelViewProjectionTransform; 18 | float2x3 boundingBox; 19 | 20 | float4x4 viewTransform; 21 | float4x4 inverseViewTransform; // view space to world space 22 | float4x4 projectionTransform; 23 | float4x4 viewProjectionTransform; 24 | float4x4 viewToCubeTransform; // view space to cube texture space (right-handed, y-axis-up) 25 | float4 ambientLightingColor; 26 | float4 fogColor; 27 | float3 fogParameters; // x: -1/(end-start) y: 1-start*x z: exponent 28 | float time; // system time elapsed since first render with this shader 29 | float sinTime; // precalculated sin(time) 30 | float cosTime; // precalculated cos(time) 31 | float random01; // random value between 0.0 and 1.0 32 | }; 33 | 34 | typedef struct { 35 | float3 position [[ attribute(SCNVertexSemanticPosition) ]]; 36 | float2 texCoords0 [[ attribute(SCNVertexSemanticTexcoord0) ]]; 37 | half4 color [[ attribute(SCNVertexSemanticColor)]]; 38 | 39 | } VertexInput; 40 | 41 | constant float milestoneTimeBreadth = 5; 42 | 43 | 44 | struct Vertex 45 | { 46 | float4 position [[position]]; 47 | float2 uv; 48 | half4 color; 49 | float2 texCoords [[user(tex_coords)]]; 50 | float time; 51 | }; 52 | 53 | vertex Vertex strokeVertexShader(VertexInput in [[ stage_in ]], 54 | uint vertexID [[vertex_id]], 55 | constant SCNSceneBuffer& scn_frame [[buffer(0)]], 56 | constant NodeBuffer& scn_node [[buffer(1)]]) 57 | { 58 | Vertex vert; 59 | vert.color = half4( half3(1,1,1), 0.1); 60 | vert.uv = in.texCoords0; 61 | vert.time = scn_frame.time; 62 | vert.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0); 63 | return vert; 64 | } 65 | 66 | 67 | 68 | fragment half4 strokeSurfaceFragment(Vertex in [[stage_in]], 69 | constant SCNSceneBuffer& scn_frame [[buffer(0)]], 70 | constant NodeBuffer& scn_node [[buffer(1)]], 71 | texture2d texture [[texture(0)]], 72 | sampler texSampler [[sampler(0)]]) 73 | { 74 | float timerMilestone = floor(in.time/milestoneTimeBreadth); 75 | float currentTime = in.time; 76 | float timer = (currentTime - timerMilestone*milestoneTimeBreadth); 77 | 78 | float2 vUv = in.uv; 79 | 80 | if ((1-in.uv.y) > timer/milestoneTimeBreadth) { 81 | discard_fragment(); 82 | } 83 | 84 | half4 fragColor; 85 | fragColor.rgb = half3(in.color.rgb); 86 | fragColor.a = in.color.a; 87 | return fragColor; 88 | } 89 | -------------------------------------------------------------------------------- /ArtzyCamera/PieceOfArtzy/Shaders/Stroke/TimedStroke.metal: -------------------------------------------------------------------------------- 1 | // 2 | // AdamLocalStroke.metal 3 | // Artzy 4 | // 5 | // Created by Oscar De la Hera Gomez on 9/21/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | 10 | #include 11 | using namespace metal; 12 | #include 13 | 14 | 15 | struct NodeBuffer { 16 | float4x4 modelTransform; 17 | float4x4 modelViewTransform; 18 | float4x4 normalTransform; 19 | float4x4 modelViewProjectionTransform; 20 | float2x3 boundingBox; 21 | 22 | float4x4 viewTransform; 23 | float4x4 inverseViewTransform; // view space to world space 24 | float4x4 projectionTransform; 25 | float4x4 viewProjectionTransform; 26 | float4x4 viewToCubeTransform; // view space to cube texture space (right-handed, y-axis-up) 27 | float4 ambientLightingColor; 28 | float4 fogColor; 29 | float3 fogParameters; // x: -1/(end-start) y: 1-start*x z: exponent 30 | float time; // system time elapsed since first render with this shader 31 | float sinTime; // precalculated sin(time) 32 | float cosTime; // precalculated cos(time) 33 | float random01; // random value between 0.0 and 1.0 34 | }; 35 | 36 | typedef struct { 37 | float3 position [[ attribute(SCNVertexSemanticPosition) ]]; 38 | float2 texCoords0 [[ attribute(SCNVertexSemanticTexcoord0) ]]; 39 | half4 color [[ attribute(SCNVertexSemanticColor)]]; 40 | 41 | } VertexInput; 42 | 43 | 44 | //constant float loopTime = 10; // In Seconds 45 | //constant float startTime = 1.25; 46 | //constant float endTime = 9.25; 47 | 48 | struct TimeVariables { 49 | float loopTime; 50 | float startTime; 51 | float endTime; 52 | }; 53 | 54 | struct Vertex 55 | { 56 | float4 position [[position]]; 57 | float2 uv; 58 | half4 color; 59 | float2 texCoords [[user(tex_coords)]]; 60 | float time; 61 | float4 modelViewProjectionTransformColumn; 62 | }; 63 | 64 | vertex Vertex TimedStrokeVertexShader(VertexInput in [[ stage_in ]], 65 | uint vertexID [[vertex_id]], 66 | constant SCNSceneBuffer& scn_frame [[buffer(0)]], 67 | constant NodeBuffer& scn_node [[buffer(1)]]) 68 | { 69 | Vertex vert; 70 | vert.color = half4( half3(1,1,1), 0.1); 71 | vert.uv = in.texCoords0; 72 | vert.time = scn_frame.time; 73 | vert.modelViewProjectionTransformColumn = scn_node.modelViewProjectionTransform[3]; 74 | vert.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0); 75 | return vert; 76 | } 77 | 78 | 79 | 80 | fragment half4 TimedStrokeSurfaceFragment(Vertex in [[stage_in]], 81 | constant SCNSceneBuffer& scn_frame [[buffer(0)]], 82 | constant NodeBuffer& scn_node [[buffer(1)]], 83 | constant TimeVariables& timeVariables [[buffer(2)]]) 84 | { 85 | 86 | float currentTime = in.time; 87 | float timerMilestone = floor(currentTime/timeVariables.loopTime); 88 | 89 | float loopTimer = (currentTime - timerMilestone*timeVariables.loopTime); 90 | 91 | if ( loopTimer < timeVariables.startTime) { 92 | // hasnt started 93 | discard_fragment(); 94 | } 95 | else if (loopTimer < timeVariables.endTime) { 96 | // has started 97 | 98 | float showUVsIfSmallerThan = (loopTimer-timeVariables.startTime)/(timeVariables.endTime-timeVariables.startTime); 99 | 100 | if ((1-in.uv.y) > showUVsIfSmallerThan) { 101 | // These Are Invalid, remove 102 | discard_fragment(); 103 | } 104 | 105 | } 106 | else { 107 | // SHOW ALL 108 | } 109 | 110 | half4 fragColor; 111 | fragColor.rgb = half3(in.color.rgb); 112 | fragColor.a = in.color.a; 113 | // fragColor.rgb *= fragColor.a; 114 | return fragColor; 115 | 116 | } 117 | -------------------------------------------------------------------------------- /ArtzyCamera/PieceOfArtzy/Shaders/Stroke/TimedStrokeTexture.metal: -------------------------------------------------------------------------------- 1 | // 2 | // StrokeTexture.metal 3 | // Artzy 4 | // 5 | // Created by Oscar De la Hera Gomez on 8/12/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | #include 10 | using namespace metal; 11 | #include 12 | 13 | struct NodeBuffer { 14 | float4x4 modelTransform; 15 | float4x4 modelViewTransform; 16 | float4x4 normalTransform; 17 | float4x4 modelViewProjectionTransform; 18 | float2x3 boundingBox; 19 | 20 | float4x4 viewTransform; 21 | float4x4 inverseViewTransform; // view space to world space 22 | float4x4 projectionTransform; 23 | float4x4 viewProjectionTransform; 24 | float4x4 viewToCubeTransform; // view space to cube texture space (right-handed, y-axis-up) 25 | float4 ambientLightingColor; 26 | float4 fogColor; 27 | float3 fogParameters; // x: -1/(end-start) y: 1-start*x z: exponent 28 | float time; // system time elapsed since first render with this shader 29 | float sinTime; // precalculated sin(time) 30 | float cosTime; // precalculated cos(time) 31 | float random01; // random value between 0.0 and 1.0 32 | }; 33 | 34 | typedef struct { 35 | float3 position [[ attribute(SCNVertexSemanticPosition) ]]; 36 | float2 texCoords0 [[ attribute(SCNVertexSemanticTexcoord0) ]]; 37 | half4 color [[ attribute(SCNVertexSemanticColor)]]; 38 | 39 | } VertexInput; 40 | 41 | 42 | struct Vertex 43 | { 44 | float4 position [[position]]; 45 | float2 uv; 46 | half4 color; 47 | // float2 texCoords [[user(tex_coords)]]; 48 | float2 texCoords; 49 | float time; 50 | }; 51 | 52 | struct TimeVariables { 53 | float loopTime; 54 | float startTime; 55 | float endTime; 56 | }; 57 | 58 | vertex Vertex TimedStrokeTextureVertexShader(VertexInput in [[ stage_in ]], 59 | uint vertexID [[vertex_id]], 60 | constant SCNSceneBuffer& scn_frame [[buffer(0)]], 61 | constant NodeBuffer& scn_node [[buffer(1)]]) 62 | { 63 | Vertex vert; 64 | 65 | // float alpha = 0.2; 66 | // 67 | // vert.color = half4( half3(1,1,1), alpha); 68 | vert.texCoords = in.texCoords0; 69 | vert.uv = in.texCoords0; 70 | vert.time = scn_frame.time; 71 | vert.position = scn_node.modelViewProjectionTransform * float4(in.position, 1.0); 72 | return vert; 73 | } 74 | 75 | 76 | 77 | fragment half4 TimedStrokeTextureSurfaceFragment(Vertex in [[stage_in]], 78 | constant SCNSceneBuffer& scn_frame [[buffer(0)]], 79 | constant NodeBuffer& scn_node [[buffer(1)]], 80 | texture2d diffuseTexture [[texture(0)]], 81 | constant TimeVariables& timeVariables [[buffer(2)]]) 82 | { 83 | 84 | float currentTime = in.time; 85 | float timerMilestone = floor(currentTime/timeVariables.loopTime); 86 | 87 | float loopTimer = (currentTime - timerMilestone*timeVariables.loopTime); 88 | 89 | if ( loopTimer < timeVariables.startTime) { 90 | // hasnt started 91 | discard_fragment(); 92 | } 93 | else if (loopTimer < timeVariables.endTime) { 94 | // has started 95 | 96 | float showUVsIfSmallerThan = (loopTimer-timeVariables.startTime)/(timeVariables.endTime-timeVariables.startTime); 97 | 98 | if ((1-in.uv.y) > showUVsIfSmallerThan) { 99 | // These Are Invalid, remove 100 | discard_fragment(); 101 | } 102 | 103 | } 104 | else { 105 | // SHOW ALL 106 | } 107 | 108 | half4 fragColor; 109 | fragColor.rgb = half3(in.color.rgb); 110 | fragColor.a = in.color.a; 111 | // fragColor.rgb *= fragColor.a; 112 | return fragColor; 113 | 114 | } 115 | -------------------------------------------------------------------------------- /ArtzyCamera/PieceOfArtzy/SpecialEffects/Glow/Glow.metal: -------------------------------------------------------------------------------- 1 | // 2 | // TextureGlow.metal 3 | // Artzy 4 | // 5 | // Created by Oscar De la Hera Gomez on 11/20/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | #include 9 | 10 | using namespace metal; 11 | #include 12 | #include 13 | 14 | 15 | struct NodeBuffer { 16 | float4x4 modelTransform; 17 | float4x4 modelViewTransform; 18 | float4x4 normalTransform; 19 | float4x4 modelViewProjectionTransform; 20 | float2x3 boundingBox; 21 | 22 | float4x4 viewTransform; 23 | float4x4 inverseViewTransform; // view space to world space 24 | float4x4 projectionTransform; 25 | float4x4 viewProjectionTransform; 26 | float4x4 viewToCubeTransform; // view space to cube texture space (right-handed, y-axis-up) 27 | float4 ambientLightingColor; 28 | float4 fogColor; 29 | float3 fogParameters; // x: -1/(end-start) y: 1-start*x z: exponent 30 | float time; // system time elapsed since first render with this shader 31 | float sinTime; // precalculated sin(time) 32 | float cosTime; // precalculated cos(time) 33 | float random01; // random value between 0.0 and 1.0 34 | }; 35 | 36 | struct modelViewProjectionTransform 37 | { 38 | float4x4 transform; 39 | }; 40 | 41 | struct custom_vertex_t 42 | { 43 | float4 position [[attribute(SCNVertexSemanticPosition)]]; 44 | float4 normal [[attribute(SCNVertexSemanticNormal)]]; 45 | half4 color [[attribute(SCNVertexSemanticColor)]]; 46 | float3 boneWeights [[attribute(SCNVertexSemanticBoneWeights)]]; 47 | }; 48 | 49 | struct out_vertex_t 50 | { 51 | float4 position [[position]]; 52 | float2 uv; 53 | }; 54 | 55 | typedef struct { 56 | float red; 57 | float blue; 58 | float green; 59 | float offset; 60 | float weight; 61 | float distanceToCamera; 62 | } Uniforms; 63 | 64 | 65 | vertex out_vertex_t texture_mask_vertex(custom_vertex_t in [[stage_in]]) 66 | { 67 | out_vertex_t out; 68 | out.position = in.position; 69 | return out; 70 | }; 71 | 72 | 73 | fragment half4 texture_mask_fragment(out_vertex_t in [[stage_in]], 74 | texture2d colorSampler [[texture(0)]]) 75 | { 76 | constexpr sampler sampler2d(coord::normalized, filter::linear, address::repeat); 77 | return half4(1.0); 78 | }; 79 | 80 | 81 | //////////// 82 | 83 | constexpr sampler s = sampler(coord::normalized, 84 | r_address::clamp_to_edge, 85 | t_address::repeat, 86 | filter::linear); 87 | 88 | vertex out_vertex_t texture_combine_vertex(custom_vertex_t in [[stage_in]]) 89 | { 90 | out_vertex_t out; 91 | out.position = in.position; 92 | out.uv = float2( (in.position.x + 1.0) * 0.5, 1.0 - (in.position.y + 1.0) * 0.5 ); 93 | return out; 94 | }; 95 | 96 | 97 | fragment half4 texture_combine_fragment(out_vertex_t vert [[stage_in]], 98 | texture2d colorSampler [[texture(0)]], 99 | texture2d maskSampler [[texture(1)]], 100 | constant Uniforms& uniforms [[ buffer(0) ]]) 101 | { 102 | 103 | float4 FragmentColor = colorSampler.sample( s, vert.uv); 104 | float4 maskColor = maskSampler.sample(s, vert.uv); 105 | // Don't render glow on top of the object itself 106 | if ( maskColor.g > 0.5 ) { 107 | return half4(FragmentColor); 108 | } 109 | 110 | 111 | 112 | float3 glowColor = float3(uniforms.red, uniforms.green, uniforms.blue); 113 | 114 | float alpha = maskColor.r; 115 | float3 out = FragmentColor.rgb * ( 1.0 - alpha ) + alpha * glowColor; 116 | return half4( float4(out.rgb, 1.0) ); 117 | } 118 | 119 | ///// Blur ////// 120 | 121 | vertex out_vertex_t texture_blur_vertex(custom_vertex_t in [[stage_in]]) 122 | { 123 | out_vertex_t out; 124 | out.position = in.position; 125 | out.uv = float2( (in.position.x + 1.0) * 0.5, 1.0 - (in.position.y + 1.0) * 0.5 ); 126 | return out; 127 | }; 128 | 129 | // http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/ 130 | //constant float weightConstant = 0.175;//0.175 131 | constant float offset[] = { 0.0, 1.0, 2.0, 3.0, 4.0 }; 132 | //constant float weight[] = { weightConstant, weightConstant, weightConstant, weightConstant, weightConstant }; //{ 0.2270270270, 0.1945945946, 0.1216216216, 0.0540540541, 0.0162162162 }; 133 | constant float bufferSize = 512.0; 134 | 135 | fragment half4 texture_blur_fragment_h(out_vertex_t vert [[stage_in]], 136 | texture2d maskSampler [[texture(0)]], 137 | constant Uniforms& uniforms [[ buffer(0) ]]) 138 | { 139 | // float4 modelViewProjectionTransform = vert.modelViewProjectionTransformColumn; 140 | 141 | float4 FragmentColor = maskSampler.sample( s, vert.uv); 142 | float FragmentR = FragmentColor.r * uniforms.weight; 143 | 144 | 145 | for (int i=1; i<5; i++) { 146 | FragmentR += maskSampler.sample( s, ( vert.uv + float2(offset[i] * uniforms.offset, 0.0)/bufferSize / uniforms.distanceToCamera ) ).r * uniforms.weight; 147 | FragmentR += maskSampler.sample( s, ( vert.uv - float2(offset[i] * uniforms.offset, 0.0)/bufferSize / uniforms.distanceToCamera ) ).r * uniforms.weight; 148 | } 149 | return half4(FragmentR, FragmentColor.g, FragmentColor.b, 1.0); 150 | } 151 | 152 | fragment half4 texture_blur_fragment_v(out_vertex_t vert [[stage_in]], 153 | texture2d maskSampler [[texture(0)]], 154 | constant Uniforms& uniforms [[ buffer(0) ]]) 155 | { 156 | 157 | // float4 modelViewProjectionTransform = vert.modelViewProjectionTransformColumn; 158 | 159 | float4 FragmentColor = maskSampler.sample( s, vert.uv); 160 | float FragmentR = FragmentColor.r * uniforms.weight; 161 | 162 | for (int i=1; i<5; i++) { 163 | FragmentR += maskSampler.sample( s, ( vert.uv + float2(0.0, offset[i] * uniforms.offset)/bufferSize / uniforms.distanceToCamera ) ).r * uniforms.weight; 164 | FragmentR += maskSampler.sample( s, ( vert.uv - float2(0.0, offset[i] * uniforms.offset)/bufferSize / uniforms.distanceToCamera ) ).r * uniforms.weight; 165 | } 166 | 167 | return half4(FragmentR, FragmentColor.g, FragmentColor.b, 1.0); 168 | 169 | }; 170 | 171 | 172 | -------------------------------------------------------------------------------- /ArtzyCamera/PieceOfArtzy/SpecialEffects/Glow/Glow.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | passes 6 | 7 | pass_blur_h 8 | 9 | colorStates 10 | 11 | clear 12 | 13 | 14 | inputs 15 | 16 | red 17 | redSymbol 18 | blue 19 | blueSymbol 20 | green 21 | greenSymbol 22 | offset 23 | offsetSymbol 24 | weight 25 | weightSymbol 26 | distanceToCamera 27 | distanceSymbol 28 | maskSampler 29 | MASK 30 | 31 | outputs 32 | 33 | color 34 | MASK 35 | 36 | metalFragmentShader 37 | texture_blur_fragment_h 38 | program 39 | doesntexist 40 | draw 41 | DRAW_QUAD 42 | metalVertexShader 43 | texture_blur_vertex 44 | 45 | pass_draw_masks 46 | 47 | inputs 48 | 49 | red 50 | redSymbol 51 | blue 52 | blueSymbol 53 | green 54 | greenSymbol 55 | offset 56 | offsetSymbol 57 | weight 58 | weightSymbol 59 | distanceToCamera 60 | distanceSymbol 61 | 62 | outputs 63 | 64 | color 65 | MASK 66 | 67 | metalFragmentShader 68 | texture_mask_vertex 69 | draw 70 | DRAW_SCENE 71 | metalVertexShader 72 | texture_mask_fragment 73 | 74 | pass_blur_v 75 | 76 | colorStates 77 | 78 | clear 79 | 80 | 81 | inputs 82 | 83 | red 84 | redSymbol 85 | blue 86 | blueSymbol 87 | green 88 | greenSymbol 89 | offset 90 | offsetSymbol 91 | weight 92 | weightSymbol 93 | distanceToCamera 94 | distanceSymbol 95 | maskSampler 96 | MASK 97 | 98 | outputs 99 | 100 | color 101 | MASK 102 | 103 | metalFragmentShader 104 | texture_blur_fragment_v 105 | program 106 | doesntexist 107 | draw 108 | DRAW_QUAD 109 | metalVertexShader 110 | texture_blur_vertex 111 | 112 | pass_combine 113 | 114 | colorStates 115 | 116 | clear 117 | 118 | 119 | inputs 120 | 121 | red 122 | redSymbol 123 | blue 124 | blueSymbol 125 | green 126 | greenSymbol 127 | offset 128 | offsetSymbol 129 | weight 130 | weightSymbol 131 | distanceToCamera 132 | distanceSymbol 133 | colorSampler 134 | COLOR 135 | maskSampler 136 | MASK 137 | 138 | outputs 139 | 140 | color 141 | COLOR 142 | 143 | metalFragmentShader 144 | texture_combine_fragment 145 | program 146 | doesntexist 147 | draw 148 | DRAW_QUAD 149 | metalVertexShader 150 | texture_combine_vertex 151 | 152 | 153 | sequence 154 | 155 | pass_draw_masks 156 | pass_blur_h 157 | pass_blur_v 158 | pass_blur_h 159 | pass_blur_v 160 | pass_combine 161 | 162 | symbols 163 | 164 | redSymbol 165 | 166 | type 167 | float 168 | 169 | blueSymbol 170 | 171 | type 172 | float 173 | 174 | greenSymbol 175 | 176 | type 177 | float 178 | 179 | offsetSymbol 180 | 181 | type 182 | float 183 | 184 | weightSymbol 185 | 186 | type 187 | float 188 | 189 | distanceSymbol 190 | 191 | type 192 | float 193 | 194 | 195 | targets 196 | 197 | MASK 198 | 199 | format 200 | rgb 201 | size 202 | 512x512 203 | scaleFactor 204 | 1 205 | type 206 | color 207 | 208 | 209 | 210 | 211 | -------------------------------------------------------------------------------- /ArtzyCamera/PieceOfArtzy/SpecialEffects/GlowInTwoColors/GlowBlue.metal: -------------------------------------------------------------------------------- 1 | // 2 | // GlowBlue.metal 3 | // ArtzyCamera 4 | // 5 | // Created by Oscar De la Hera Gomez on 12/24/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | #include 9 | 10 | using namespace metal; 11 | #include 12 | #include 13 | 14 | 15 | 16 | 17 | 18 | struct custom_node_t3 { 19 | float4x4 modelTransform; 20 | float4x4 inverseModelTransform; 21 | float4x4 modelViewTransform; 22 | float4x4 inverseModelViewTransform; 23 | float4x4 normalTransform; // Inverse transpose of modelViewTransform 24 | float4x4 modelViewProjectionTransform; 25 | float4x4 inverseModelViewProjectionTransform; 26 | float2x3 boundingBox; 27 | float2x3 worldBoundingBox; 28 | }; 29 | 30 | struct custom_vertex_t 31 | { 32 | float4 position [[attribute(SCNVertexSemanticPosition)]]; 33 | float4 normal [[attribute(SCNVertexSemanticNormal)]]; 34 | half4 color [[attribute(SCNVertexSemanticColor)]]; 35 | float3 boneWeights [[attribute(SCNVertexSemanticBoneWeights)]]; 36 | }; 37 | 38 | struct out_vertex_t 39 | { 40 | float4 position [[position]]; 41 | float2 uv; 42 | }; 43 | 44 | typedef struct { 45 | float symbolAsCalledInMetal; 46 | } Uniforms; 47 | 48 | 49 | vertex out_vertex_t blue_mask_vertex(custom_vertex_t in [[stage_in]], 50 | constant Uniforms& uniforms [[ buffer(0) ]]) 51 | { 52 | out_vertex_t out; 53 | out.position = in.position; 54 | return out; 55 | }; 56 | 57 | 58 | fragment half4 blue_mask_fragment(out_vertex_t in [[stage_in]], 59 | texture2d colorSampler [[texture(0)]], 60 | constant Uniforms& uniforms [[ buffer(0) ]]) 61 | { 62 | constexpr sampler sampler2d(coord::normalized, filter::linear, address::repeat); 63 | return half4(1.0); 64 | }; 65 | 66 | 67 | //////////// 68 | 69 | constexpr sampler s = sampler(coord::normalized, 70 | r_address::clamp_to_edge, 71 | t_address::repeat, 72 | filter::linear); 73 | 74 | struct MyNodeBuffer { 75 | float4x4 modelTransform; 76 | float4x4 modelViewTransform; 77 | float4x4 normalTransform; 78 | float4x4 modelViewProjectionTransform; 79 | }; 80 | 81 | 82 | vertex out_vertex_t blue_combine_vertex(custom_vertex_t in [[stage_in]], 83 | constant Uniforms& uniforms [[ buffer(0) ]]) 84 | { 85 | float test = uniforms.symbolAsCalledInMetal; 86 | out_vertex_t out; 87 | out.position = in.position; 88 | out.uv = float2( (in.position.x + 1.0) * 0.5, 1.0 - (in.position.y + 1.0) * 0.5 ); 89 | return out; 90 | }; 91 | 92 | 93 | fragment half4 blue_combine_fragment(out_vertex_t vert [[stage_in]], 94 | texture2d colorSampler [[texture(0)]], 95 | texture2d maskSampler [[texture(1)]], 96 | constant Uniforms& uniforms [[ buffer(0) ]]) 97 | { 98 | float test = uniforms.symbolAsCalledInMetal; 99 | float4 FragmentColor = colorSampler.sample( s, vert.uv); 100 | float4 maskColor = maskSampler.sample(s, vert.uv); 101 | 102 | // Don't render glow on top of the object itself 103 | if ( maskColor.g > 0.5 ) { 104 | return half4(FragmentColor); 105 | } 106 | 107 | float r = 0.1411764706; // 0.56 108 | float g = 0.4; // 0.84 109 | float b = 0.6470588235; // 0.95 110 | 111 | float3 glowColor = float3(r, g, b); 112 | 113 | float alpha = maskColor.r; 114 | float3 out = FragmentColor.rgb * ( 1.0 - alpha ) + alpha * glowColor; 115 | return half4( float4(out.rgb, 1.0) ); 116 | } 117 | 118 | ///// Blur ////// 119 | 120 | vertex out_vertex_t blue_blur_vertex(custom_vertex_t in [[stage_in]], 121 | constant Uniforms& uniforms [[ buffer(0) ]]) 122 | { 123 | float test = uniforms.symbolAsCalledInMetal; 124 | out_vertex_t out; 125 | out.position = in.position; 126 | out.uv = float2( (in.position.x + 1.0) * 0.5, 1.0 - (in.position.y + 1.0) * 0.5 ); 127 | return out; 128 | }; 129 | 130 | // http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/ 131 | constant float weightConstant = 0.175; 132 | constant float offset[] = { 0.0, 1.0, 2.0, 3.0, 4.0 }; 133 | constant float weight[] = { weightConstant, weightConstant, weightConstant, weightConstant, weightConstant }; //{ 0.2270270270, 0.1945945946, 0.1216216216, 0.0540540541, 0.0162162162 }; 134 | constant float bufferSize = 512.0; 135 | 136 | fragment half4 blue_blur_fragment_h(out_vertex_t vert [[stage_in]], 137 | texture2d maskSampler [[texture(0)]], 138 | constant Uniforms& uniforms [[ buffer(0) ]]) 139 | { 140 | float test = uniforms.symbolAsCalledInMetal; 141 | float4 FragmentColor = maskSampler.sample( s, vert.uv); 142 | float FragmentR = FragmentColor.r * weight[0]; 143 | 144 | 145 | for (int i=1; i<5; i++) { 146 | FragmentR += maskSampler.sample( s, ( vert.uv + float2(offset[i], 0.0)/bufferSize ) ).r * weight[i]; 147 | FragmentR += maskSampler.sample( s, ( vert.uv - float2(offset[i], 0.0)/bufferSize ) ).r * weight[i]; 148 | } 149 | return half4(FragmentR, FragmentColor.g, FragmentColor.b, 1.0); 150 | } 151 | 152 | fragment half4 blue_blur_fragment_v(out_vertex_t vert [[stage_in]], 153 | texture2d maskSampler [[texture(0)]], 154 | constant Uniforms& uniforms [[ buffer(0) ]]) 155 | { 156 | float test = uniforms.symbolAsCalledInMetal; 157 | float4 FragmentColor = maskSampler.sample( s, vert.uv); 158 | float FragmentR = FragmentColor.r * weight[0]; 159 | 160 | for (int i=1; i<5; i++) { 161 | FragmentR += maskSampler.sample( s, ( vert.uv + float2(0.0, offset[i])/bufferSize ) ).r * weight[i]; 162 | FragmentR += maskSampler.sample( s, ( vert.uv - float2(0.0, offset[i])/bufferSize ) ).r * weight[i]; 163 | } 164 | 165 | return half4(FragmentR, FragmentColor.g, FragmentColor.b, 1.0); 166 | 167 | }; 168 | 169 | 170 | -------------------------------------------------------------------------------- /ArtzyCamera/PieceOfArtzy/SpecialEffects/GlowInTwoColors/GlowInTwoColors.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | passes 6 | 7 | pass_red_blur_v 8 | 9 | colorStates 10 | 11 | clear 12 | 13 | 14 | inputs 15 | 16 | symbolAsCalledInMetal 17 | customVariableSymbol 18 | maskSampler 19 | MASK 20 | 21 | outputs 22 | 23 | color 24 | MASK 25 | 26 | metalFragmentShader 27 | red_blur_fragment_v 28 | program 29 | doesntexist 30 | draw 31 | DRAW_QUAD 32 | metalVertexShader 33 | red_blur_vertex 34 | 35 | pass_red_combine 36 | 37 | colorStates 38 | 39 | clear 40 | 41 | 42 | inputs 43 | 44 | symbolAsCalledInMetal 45 | customVariableSymbol 46 | colorSampler 47 | COLOR 48 | maskSampler 49 | MASK 50 | 51 | outputs 52 | 53 | color 54 | COLOR 55 | 56 | metalFragmentShader 57 | red_combine_fragment 58 | program 59 | doesntexist 60 | draw 61 | DRAW_QUAD 62 | metalVertexShader 63 | red_combine_vertex 64 | 65 | pass_blur_h 66 | 67 | colorStates 68 | 69 | clear 70 | 71 | 72 | inputs 73 | 74 | symbolAsCalledInMetal 75 | customVariableSymbol 76 | maskSampler 77 | MASK 78 | 79 | outputs 80 | 81 | color 82 | MASK 83 | 84 | metalFragmentShader 85 | blue_blur_fragment_h 86 | program 87 | doesntexist 88 | draw 89 | DRAW_QUAD 90 | metalVertexShader 91 | blue_blur_vertex 92 | 93 | pass_red_blur_h 94 | 95 | colorStates 96 | 97 | clear 98 | 99 | 100 | inputs 101 | 102 | symbolAsCalledInMetal 103 | customVariableSymbol 104 | maskSampler 105 | MASK 106 | 107 | outputs 108 | 109 | color 110 | MASK 111 | 112 | metalFragmentShader 113 | red_blur_fragment_h 114 | program 115 | doesntexist 116 | draw 117 | DRAW_QUAD 118 | metalVertexShader 119 | red_blur_vertex 120 | 121 | pass_halo_mask 122 | 123 | inputs 124 | 125 | symbolAsCalledInMetal 126 | customVariableSymbol 127 | colorSampler 128 | COLOR 129 | 130 | outputs 131 | 132 | color 133 | MASK 134 | 135 | metalFragmentShader 136 | red_mask_fragment 137 | program 138 | doesntexist 139 | excludeCategoryMask 140 | 4 141 | draw 142 | DRAW_SCENE 143 | metalVertexShader 144 | red_mask_vertex 145 | 146 | pass_draw_masks 147 | 148 | inputs 149 | 150 | symbolAsCalledInMetal 151 | customVariableSymbol 152 | colorSampler 153 | COLOR 154 | 155 | outputs 156 | 157 | color 158 | MASK 159 | 160 | metalFragmentShader 161 | blue_mask_vertex 162 | program 163 | doesntexist 164 | draw 165 | DRAW_SCENE 166 | metalVertexShader 167 | blue_mask_fragment 168 | includeCategoryMask 169 | 4 170 | 171 | pass_blur_v 172 | 173 | colorStates 174 | 175 | clear 176 | 177 | 178 | inputs 179 | 180 | symbolAsCalledInMetal 181 | customVariableSymbol 182 | maskSampler 183 | MASK 184 | 185 | outputs 186 | 187 | color 188 | MASK 189 | 190 | metalFragmentShader 191 | blue_blur_fragment_v 192 | program 193 | doesntexist 194 | draw 195 | DRAW_QUAD 196 | metalVertexShader 197 | blue_blur_vertex 198 | 199 | pass_combine 200 | 201 | colorStates 202 | 203 | clear 204 | 205 | 206 | inputs 207 | 208 | symbolAsCalledInMetal 209 | customVariableSymbol 210 | colorSampler 211 | COLOR 212 | maskSampler 213 | MASK 214 | 215 | outputs 216 | 217 | color 218 | COLOR 219 | 220 | metalFragmentShader 221 | blue_combine_fragment 222 | program 223 | doesntexist 224 | draw 225 | DRAW_QUAD 226 | metalVertexShader 227 | blue_combine_vertex 228 | 229 | 230 | sequence 231 | 232 | pass_draw_masks 233 | pass_blur_h 234 | pass_blur_v 235 | pass_blur_h 236 | pass_blur_v 237 | pass_combine 238 | pass_halo_mask 239 | pass_red_blur_h 240 | pass_red_blur_v 241 | pass_red_blur_h 242 | pass_red_blur_v 243 | pass_red_combine 244 | 245 | symbols 246 | 247 | customVariableSymbol 248 | 249 | type 250 | float 251 | 252 | 253 | targets 254 | 255 | MASK 256 | 257 | format 258 | rgb 259 | size 260 | 512x512 261 | scaleFactor 262 | 1 263 | type 264 | color 265 | 266 | 267 | 268 | 269 | -------------------------------------------------------------------------------- /ArtzyCamera/PieceOfArtzy/SpecialEffects/GlowInTwoColors/GlowRed.metal: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace metal; 4 | #include 5 | #include 6 | 7 | 8 | 9 | 10 | 11 | struct custom_node_t3 { 12 | float4x4 modelTransform; 13 | float4x4 inverseModelTransform; 14 | float4x4 modelViewTransform; 15 | float4x4 inverseModelViewTransform; 16 | float4x4 normalTransform; // Inverse transpose of modelViewTransform 17 | float4x4 modelViewProjectionTransform; 18 | float4x4 inverseModelViewProjectionTransform; 19 | float2x3 boundingBox; 20 | float2x3 worldBoundingBox; 21 | }; 22 | 23 | struct custom_vertex_t 24 | { 25 | float4 position [[attribute(SCNVertexSemanticPosition)]]; 26 | float4 normal [[attribute(SCNVertexSemanticNormal)]]; 27 | half4 color [[attribute(SCNVertexSemanticColor)]]; 28 | float3 boneWeights [[attribute(SCNVertexSemanticBoneWeights)]]; 29 | }; 30 | 31 | struct out_vertex_t 32 | { 33 | float4 position [[position]]; 34 | float2 uv; 35 | }; 36 | 37 | typedef struct { 38 | float symbolAsCalledInMetal; 39 | } Uniforms; 40 | 41 | 42 | vertex out_vertex_t red_mask_vertex(custom_vertex_t in [[stage_in]], 43 | constant Uniforms& uniforms [[ buffer(0) ]]) 44 | { 45 | out_vertex_t out; 46 | out.position = in.position; 47 | return out; 48 | }; 49 | 50 | 51 | fragment half4 red_mask_fragment(out_vertex_t in [[stage_in]], 52 | texture2d colorSampler [[texture(0)]], 53 | constant Uniforms& uniforms [[ buffer(0) ]]) 54 | { 55 | constexpr sampler sampler2d(coord::normalized, filter::linear, address::repeat); 56 | return half4(1.0); 57 | }; 58 | 59 | 60 | //////////// 61 | 62 | constexpr sampler s = sampler(coord::normalized, 63 | r_address::clamp_to_edge, 64 | t_address::repeat, 65 | filter::linear); 66 | 67 | struct MyNodeBuffer { 68 | float4x4 modelTransform; 69 | float4x4 modelViewTransform; 70 | float4x4 normalTransform; 71 | float4x4 modelViewProjectionTransform; 72 | }; 73 | 74 | 75 | vertex out_vertex_t red_combine_vertex(custom_vertex_t in [[stage_in]], 76 | constant Uniforms& uniforms [[ buffer(0) ]]) 77 | { 78 | float test = uniforms.symbolAsCalledInMetal; 79 | out_vertex_t out; 80 | out.position = in.position; 81 | out.uv = float2( (in.position.x + 1.0) * 0.5, 1.0 - (in.position.y + 1.0) * 0.5 ); 82 | return out; 83 | }; 84 | 85 | 86 | fragment half4 red_combine_fragment(out_vertex_t vert [[stage_in]], 87 | texture2d colorSampler [[texture(0)]], 88 | texture2d maskSampler [[texture(1)]], 89 | constant Uniforms& uniforms [[ buffer(0) ]]) 90 | { 91 | float test = uniforms.symbolAsCalledInMetal; 92 | float4 FragmentColor = colorSampler.sample( s, vert.uv); 93 | float4 maskColor = maskSampler.sample(s, vert.uv); 94 | 95 | // Don't render glow on top of the object itself 96 | if ( maskColor.g > 0.5 ) { 97 | return half4(FragmentColor); 98 | } 99 | 100 | float r = 0.9176470588; // 0.56 101 | float g = 0.2392156863; // 0.84 102 | float b = 0.2666666667; // 0.95 103 | 104 | float3 glowColor = float3(r, g, b); 105 | 106 | float alpha = maskColor.r; 107 | float3 out = FragmentColor.rgb * ( 1.0 - alpha ) + alpha * glowColor; 108 | return half4( float4(out.rgb, 1.0) ); 109 | } 110 | 111 | ///// Blur ////// 112 | 113 | vertex out_vertex_t red_blur_vertex(custom_vertex_t in [[stage_in]], 114 | constant Uniforms& uniforms [[ buffer(0) ]]) 115 | { 116 | float test = uniforms.symbolAsCalledInMetal; 117 | out_vertex_t out; 118 | out.position = in.position; 119 | out.uv = float2( (in.position.x + 1.0) * 0.5, 1.0 - (in.position.y + 1.0) * 0.5 ); 120 | return out; 121 | }; 122 | 123 | // http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/ 124 | constant float weightConstant = 0.175; 125 | constant float offset[] = { 0.0, 1.0, 2.0, 3.0, 4.0 }; 126 | constant float weight[] = { weightConstant, weightConstant, weightConstant, weightConstant, weightConstant }; //{ 0.2270270270, 0.1945945946, 0.1216216216, 0.0540540541, 0.0162162162 }; 127 | constant float bufferSize = 512.0; 128 | 129 | fragment half4 red_blur_fragment_h(out_vertex_t vert [[stage_in]], 130 | texture2d maskSampler [[texture(0)]], 131 | constant Uniforms& uniforms [[ buffer(0) ]]) 132 | { 133 | float test = uniforms.symbolAsCalledInMetal; 134 | float4 FragmentColor = maskSampler.sample( s, vert.uv); 135 | float FragmentR = FragmentColor.r * weight[0]; 136 | 137 | 138 | for (int i=1; i<5; i++) { 139 | FragmentR += maskSampler.sample( s, ( vert.uv + float2(offset[i], 0.0)/bufferSize ) ).r * weight[i]; 140 | FragmentR += maskSampler.sample( s, ( vert.uv - float2(offset[i], 0.0)/bufferSize ) ).r * weight[i]; 141 | } 142 | return half4(FragmentR, FragmentColor.g, FragmentColor.b, 1.0); 143 | } 144 | 145 | fragment half4 red_blur_fragment_v(out_vertex_t vert [[stage_in]], 146 | texture2d maskSampler [[texture(0)]], 147 | constant Uniforms& uniforms [[ buffer(0) ]]) 148 | { 149 | float test = uniforms.symbolAsCalledInMetal; 150 | float4 FragmentColor = maskSampler.sample( s, vert.uv); 151 | float FragmentR = FragmentColor.r * weight[0]; 152 | 153 | for (int i=1; i<5; i++) { 154 | FragmentR += maskSampler.sample( s, ( vert.uv + float2(0.0, offset[i])/bufferSize ) ).r * weight[i]; 155 | FragmentR += maskSampler.sample( s, ( vert.uv - float2(0.0, offset[i])/bufferSize ) ).r * weight[i]; 156 | } 157 | 158 | return half4(FragmentR, FragmentColor.g, FragmentColor.b, 1.0); 159 | 160 | }; 161 | 162 | 163 | -------------------------------------------------------------------------------- /ArtzyCamera/PieceOfArtzy/Variables/PieceOfArtzyVariables.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PieceOfArtzyVariables.swift 3 | // ArtzyCamera 4 | // 5 | // Created by Oscar De la Hera Gomez on 12/3/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct DisplayVariableStruct { 12 | var show:Float = 10; 13 | 14 | init(show:Float) { 15 | self.show = show; 16 | } 17 | } 18 | 19 | 20 | 21 | struct strokeTimeVariableStruct { 22 | var loopTime:Float = 10; 23 | var startTime:Float = 0; 24 | var endTime:Float = 5; 25 | 26 | init(loopTime:Float, startTime:Float, endTime:Float) { 27 | self.loopTime = loopTime; 28 | self.startTime = startTime; 29 | self.endTime = endTime; 30 | } 31 | } 32 | 33 | struct timedShaderVariablesStruct { 34 | var loopTime:Float = 0; 35 | var startTime:Float = 0; 36 | var endTime:Float = 0; 37 | var colorR:Float = 0; 38 | var colorB:Float = 0; 39 | var colorG:Float = 0; 40 | 41 | init(loopTime:Float, startTime:Float, endTime:Float, colorR:Float, colorB:Float, colorG:Float) { 42 | self.loopTime = loopTime; 43 | self.startTime = startTime; 44 | self.endTime = endTime; 45 | self.colorR = colorR; 46 | self.colorB = colorB; 47 | self.colorG = colorG; 48 | } 49 | }; 50 | 51 | struct blurVariableStruct { 52 | var distanceToNode:Float = 10; 53 | 54 | init(distanceToNode:Float) { 55 | self.distanceToNode = distanceToNode; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /ArtzyCamera/Variables/AppVariables.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppVariables.swift 3 | // ArtzyCamera 4 | // 5 | // Created by Oscar De la Hera Gomez on 12/3/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | var artzyNotificationView:NotificationView = NotificationView(); 13 | var artzyNotificationBlimp:NotificationBlimp = NotificationBlimp(); 14 | 15 | var screenWidth:CGFloat = CGFloat(); 16 | var screenHeight:CGFloat = CGFloat(); 17 | 18 | var kArtzyNotificationRect:CGRect = CGRect(); 19 | var kArtzMinYLabelLine:CGFloat = CGFloat(); 20 | 21 | var kArtzyBlimpDimension:CGFloat = CGFloat(); 22 | var kArtzyBlimpBaseRect:CGRect = CGRect(); 23 | 24 | var kArtzyNotificationLabelRect:CGRect = CGRect(); 25 | 26 | var kArtzyCameraButtonDimension:CGFloat = CGFloat(); 27 | var kArtzyCameraButtonMinY:CGFloat = CGFloat(); 28 | 29 | var kArtzyResetButtonDimension:CGFloat = CGFloat(); 30 | var kArtzyResetButtonMinY:CGFloat = CGFloat(); 31 | 32 | 33 | var kArtzyHUDButtonGap:CGFloat = CGFloat(); 34 | var kArtzyHUDButtonDimension:CGFloat = CGFloat(); 35 | var kArtzyHUDButtonMinY:CGFloat = CGFloat(); 36 | 37 | 38 | public func instantiateArtzyVariables() { 39 | 40 | kArtzyHUDButtonDimension = 0.15*screenWidth; 41 | kArtzyHUDButtonGap = 0.048*screenWidth; 42 | kArtzyHUDButtonMinY = kArtzyCameraButtonMinY-kArtzyHUDButtonDimension-kArtzyHUDButtonGap; 43 | 44 | kArtzyCameraButtonDimension = screenWidth*0.2; 45 | kArtzyCameraButtonMinY = screenHeight*0.9-kArtzyCameraButtonDimension; 46 | 47 | kArtzyResetButtonDimension = screenWidth*0.125; 48 | kArtzyResetButtonMinY = screenHeight*0.05+kArtzyHUDButtonGap/2 49 | 50 | kArtzyNotificationRect = CGRect(x: screenWidth*0.25, y: 0, width: screenWidth*0.5, height: screenHeight*0.2) 51 | kArtzMinYLabelLine = screenHeight*0.0625 52 | 53 | kArtzyBlimpDimension = screenHeight*0.025; 54 | 55 | kArtzyBlimpBaseRect = CGRect(x: 0, y: kArtzMinYLabelLine, width: kArtzyBlimpDimension, height: kArtzyBlimpDimension) 56 | 57 | kArtzyNotificationLabelRect = CGRect(x: kArtzyBlimpDimension, y: kArtzMinYLabelLine, width: kArtzyNotificationRect.width-kArtzyBlimpDimension, height: kArtzyNotificationRect.height); 58 | } 59 | -------------------------------------------------------------------------------- /ArtzyCamera/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // ArtzyCamera 4 | // 5 | // Created by Oscar De la Hera Gomez on 12/3/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import SceneKit 11 | import ARKit 12 | import Photos 13 | import AVKit 14 | 15 | 16 | protocol ViewControllerDelegate { 17 | func resetTracking(); 18 | } 19 | 20 | 21 | class ViewController: UIViewController, ARSCNViewDelegate, ARSessionDelegate, ViewControllerDelegate { 22 | 23 | public var activeArtzyPieces:[NSMutableDictionary] = [NSMutableDictionary](); 24 | 25 | var HUD:UIWindow! 26 | @IBOutlet var sceneView: ARSCNView! 27 | 28 | /// A serial queue for thread safety when modifying the SceneKit node graph. 29 | let updateQueue = DispatchQueue(label: Bundle.main.bundleIdentifier! + 30 | ".serialSceneKitQueue") 31 | 32 | /// Convenience accessor for the session owned by ARSCNView. 33 | var session: ARSession { 34 | return sceneView.session 35 | } 36 | 37 | // HIDE STATUS BAR 38 | override var prefersStatusBarHidden: Bool { 39 | return true 40 | } 41 | 42 | override func viewDidLoad() { 43 | super.viewDidLoad() 44 | 45 | print("VIEW DID LOAD"); 46 | //Instantiate variables 47 | screenWidth = self.view.frame.width; 48 | screenHeight = self.view.frame.height; 49 | instantiateArtzyVariables(); 50 | 51 | // Set the view's delegate 52 | self.sceneView.delegate = self 53 | self.sceneView.session.delegate = self 54 | 55 | // self.sceneView.antialiasingMode = .multisampling4X 56 | 57 | self.HUD = UIWindow(frame: self.view.frame); 58 | 59 | let cameraHUD:CameraHUDViewController = CameraHUDViewController(); 60 | cameraHUD.sceneView = self.sceneView; 61 | cameraHUD.viewControllerDelegate = self; 62 | self.HUD.rootViewController = cameraHUD; 63 | self.HUD.rootViewController!.view.alpha = 1; 64 | self.HUD.makeKeyAndVisible() 65 | 66 | 67 | 68 | //Photos 69 | let photos = PHPhotoLibrary.authorizationStatus() 70 | if photos == .notDetermined { 71 | PHPhotoLibrary.requestAuthorization({status in 72 | if status == .authorized{ 73 | print("AUthorized"); 74 | } else { 75 | print("status ", PHPhotoLibrary.authorizationStatus() ); 76 | } 77 | }) 78 | } 79 | 80 | AVAudioSession.sharedInstance().requestRecordPermission () { 81 | [unowned self] allowed in 82 | if allowed { 83 | // Microphone allowed, do what you like! 84 | 85 | } else { 86 | // User denied microphone. Tell them off! 87 | 88 | } 89 | } 90 | 91 | } 92 | 93 | override func viewDidAppear(_ animated: Bool) { 94 | super.viewDidAppear(animated) 95 | 96 | // Prevent the screen from being dimmed to avoid interuppting the AR experience. 97 | UIApplication.shared.isIdleTimerDisabled = true 98 | 99 | // Start the AR experience 100 | resetTracking() 101 | 102 | } 103 | 104 | 105 | override func viewWillDisappear(_ animated: Bool) { 106 | super.viewWillDisappear(animated) 107 | 108 | // Pause the view's session 109 | self.sceneView.session.pause() 110 | } 111 | 112 | override func didReceiveMemoryWarning() { 113 | super.didReceiveMemoryWarning() 114 | // Release any cached data, images, etc that aren't in use. 115 | } 116 | 117 | // MARK: - Session management (Image detection setup) 118 | 119 | /// Prevents restarting the session while a restart is in progress. 120 | var isRestartAvailable = true 121 | 122 | /// Creates a new AR configuration to run on the `session`. 123 | /// - Tag: ARReferenceImage-Loading 124 | public func resetTracking() { 125 | 126 | print("RESET TRACKING"); 127 | 128 | guard let referenceImages = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil) else { 129 | fatalError("Missing expected asset catalog resources.") 130 | } 131 | 132 | let configuration = ARWorldTrackingConfiguration() 133 | configuration.detectionImages = referenceImages 134 | session.run(configuration, options: [.resetTracking, .removeExistingAnchors]) 135 | 136 | // REMOVE ALL OBJECTS 137 | self.sceneView.scene.rootNode.enumerateChildNodes { (node, _) in 138 | node.removeFromParentNode(); 139 | } 140 | } 141 | 142 | // MARK: - ARSCNViewDelegate (Image detection results) 143 | /// - Tag: ARImageAnchor-Visualizing 144 | func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) { 145 | guard let imageAnchor = anchor as? ARImageAnchor else { return } 146 | let referenceImage = imageAnchor.referenceImage 147 | 148 | print("REGISTERED IMAGE : \(referenceImage)"); 149 | 150 | updateQueue.async { 151 | 152 | let pieceOfArtzy:PieceOfArtzy = PieceOfArtzy(); 153 | pieceOfArtzy.sceneView = self.sceneView; 154 | // artzyPiece.artzyHUD = self.artzyHUD; 155 | pieceOfArtzy.node = node; 156 | pieceOfArtzy.referenceImage = referenceImage; 157 | pieceOfArtzy.start(); 158 | 159 | let ArtzyPieces:NSMutableDictionary = [ 160 | "node" : node, 161 | "pieceOfArtzy" : pieceOfArtzy, 162 | "withinPointOfView": false, 163 | "distanceToObject": 0 164 | ] 165 | 166 | self.activeArtzyPieces.append(ArtzyPieces); 167 | 168 | 169 | } 170 | } 171 | 172 | func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) { 173 | // print("OPEN GL CONTEXT \(self.sceneView)" ) 174 | 175 | DispatchQueue.main.async { 176 | 177 | (self.HUD.rootViewController as! CameraHUDViewController).didUpdateAtTime(time:time); 178 | 179 | } 180 | 181 | } 182 | 183 | func renderer(_ renderer: SCNSceneRenderer, didRenderScene scene: SCNScene, atTime time: TimeInterval) { 184 | for ArtzyDict in self.activeArtzyPieces { 185 | let pieceOfArtzy:PieceOfArtzy = ArtzyDict.value(forKey: "pieceOfArtzy") as! PieceOfArtzy; 186 | pieceOfArtzy.didUpdateAtTime(); 187 | } 188 | } 189 | 190 | var imageHighlightAction: SCNAction { 191 | return .sequence([ 192 | .wait(duration: 0.25), 193 | .fadeOpacity(to: 0.85, duration: 0.25), 194 | .fadeOpacity(to: 0.15, duration: 0.25), 195 | .fadeOpacity(to: 0.85, duration: 0.25), 196 | .fadeOut(duration: 0.5), 197 | .removeFromParentNode() 198 | ]) 199 | } 200 | 201 | 202 | 203 | 204 | } 205 | -------------------------------------------------------------------------------- /ArtzyCamera/art.scnassets/localxAdamfu.scn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/ArtzyCamera/art.scnassets/localxAdamfu.scn -------------------------------------------------------------------------------- /ArtzyCameraTests/ArtzyCameraTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ArtzyCameraTests.swift 3 | // ArtzyCameraTests 4 | // 5 | // Created by Oscar De la Hera Gomez on 12/3/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import ArtzyCamera 11 | 12 | class ArtzyCameraTests: XCTestCase { 13 | 14 | override func setUp() { 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDown() { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | } 21 | 22 | func testExample() { 23 | // This is an example of a functional test case. 24 | // Use XCTAssert and related functions to verify your tests produce the correct results. 25 | } 26 | 27 | func testPerformanceExample() { 28 | // This is an example of a performance test case. 29 | self.measure { 30 | // Put the code you want to measure the time of here. 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /ArtzyCameraTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ArtzyCameraUITests/ArtzyCameraUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ArtzyCameraUITests.swift 3 | // ArtzyCameraUITests 4 | // 5 | // Created by Oscar De la Hera Gomez on 12/3/18. 6 | // Copyright © 2018 Delasign. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class ArtzyCameraUITests: XCTestCase { 12 | 13 | override func setUp() { 14 | // Put setup code here. This method is called before the invocation of each test method in the class. 15 | 16 | // In UI tests it is usually best to stop immediately when a failure occurs. 17 | continueAfterFailure = false 18 | 19 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 20 | XCUIApplication().launch() 21 | 22 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 23 | } 24 | 25 | override func tearDown() { 26 | // Put teardown code here. This method is called after the invocation of each test method in the class. 27 | } 28 | 29 | func testExample() { 30 | // Use recording to get started writing UI tests. 31 | // Use XCTAssert and related functions to verify your tests produce the correct results. 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /ArtzyCameraUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /GettingStarted/Hand-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/GettingStarted/Hand-02.png -------------------------------------------------------------------------------- /GettingStarted/a4Logo-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/GettingStarted/a4Logo-01.png -------------------------------------------------------------------------------- /GettingStarted/adamLocal-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/GettingStarted/adamLocal-01.png -------------------------------------------------------------------------------- /HowItWasMade/Hand/Files/hand.mb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/HowItWasMade/Hand/Files/hand.mb -------------------------------------------------------------------------------- /HowItWasMade/Hand/Image/Hand-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/HowItWasMade/Hand/Image/Hand-02.png -------------------------------------------------------------------------------- /HowItWasMade/Loader/Files/Loading.mb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/HowItWasMade/Loader/Files/Loading.mb -------------------------------------------------------------------------------- /HowItWasMade/Loader/Files/logo.scn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/HowItWasMade/Loader/Files/logo.scn -------------------------------------------------------------------------------- /HowItWasMade/Loader/Image/1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/HowItWasMade/Loader/Image/1024.png -------------------------------------------------------------------------------- /HowItWasMade/Local/Files/adamLocalFinal.mb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/HowItWasMade/Local/Files/adamLocalFinal.mb -------------------------------------------------------------------------------- /HowItWasMade/Local/Image/adamLocal-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delasign/ArtzyCamera/af6ae64d257b12e4e5436c575a2e1c775572cae2/HowItWasMade/Local/Image/adamLocal-01.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Open Source Artzy™ Camera 2 | 3 | The Open Source Artzy™ Camera is an ARKit super-starter project created by Delasign that features an AR multi-media recorder, 3 AR samples, a library of free metal shaders and special effects, illustrator and maya files. 4 | 5 | 6 | 7 | # Sharing is caring. 8 | 9 | If you create anything, please share it on Instagram and tag @artzyapp along with #artzy. 10 | 11 | 12 | # Getting started 13 | Download the repo and print the three images in the "GettingStarted" folder. These are the three AR samples that come with the project. 14 | 15 | After printing, open the app and place your phone infront of the images to experience the three samples. 16 | 17 | # Ok, I want to start creating. 18 | I recommend reading up on AR and ARKit before becoming familiar with how the samples were created. These are found in the "HowItWasMade" folder, which includes the files that were used and the corresponding images. 19 | 20 | If you have any questions please email questions to : artzy@delasign.com 21 | 22 | # Recommended reading 23 | 24 | For all posts ever, please visit my blog. 25 | 26 | Apple Documentation: 27 | 28 | - ARKit 29 | - Building your first ARKit Experience 30 | 31 | 32 | - AR World Tracking Configuration 33 | - Understanding World Tracking in ARKit 34 | 35 | - ARReferenceImages 36 | - ARImageAnchor 37 | - Recognizing Images in an AR Experience 38 | 39 | 40 | - ARFrame 41 | - ARCamera 42 | 43 | 44 | - SceneKit 45 | - SCNNode 46 | - SCNProgram 47 | - SCNTechnique 48 | 49 | ARKit Theory: 50 | 51 | - The Point Cloud, Image Recognition, AR Ready Images, True Scale, The Renderer and Nodes 52 | - Vertices, Metal Shaders, UV Mapping and SCNProgram’s. 53 | - ARCamera POV. 54 | - Intro to SCNTechniques. 55 | 56 | 57 | # Sample projects 58 | 59 | The repository comes with three opensource AR samples, which are detailed below. 60 | 61 | ## 'local' by adamfu x delasign 62 | 63 | 64 | 65 | This project features a double neon glow - the word glows in blue, whilst the halo glows in red. 66 | 67 | For tutorials on how this was created please read the following: 68 | 69 | Geometry: 70 | 71 | - How to use an Adobe Illustrator Curve in Maya. 72 | - How to turn a turn a simple sketch into an extruded model on Maya 73 | - UV Mapping: How to Convert an Extruded Cylinder’s UV’s to Simple Layout 74 | 75 | Neon: 76 | 77 | - Apple Documentation : SCNTechnique 78 | - ARKit Theory: Intro to SCNTechniques. 79 | - How to create a glowing neon effect for a geometry in ARKit through a SCN Technique 80 | - A SCNTechnique requires a .scn model 81 | 82 | 83 | Code: 84 | 85 | The key parts to this working are found in *PieceOfArtzy/PieceOfArtzy.swift* line 182 -> 264, with the SCNTechnique and associated assets under the *PieceOfArtzy/SpecialEffects/GlowInTwoColors* folder. 86 | 87 | Extra: 88 | To see it perform an animated, timed stroke - switch the functionality in *PieceOfArtzy/PieceOfArtzy.swift* line 34. 89 | 90 | ## 'loader' by delasign 91 | 92 | 93 | 94 | This project features a 3d stroke neon glow - it appears as though the word has been drawn. 95 | 96 | For tutorials on how this was created please read the following: 97 | 98 | Geometry: 99 | 100 | - How to use an Adobe Illustrator Curve in Maya. 101 | - How to turn a turn a simple sketch into an extruded model on Maya 102 | - UV Mapping: How to Convert an Extruded Cylinder’s UV’s to Simple Layout 103 | 104 | Neon: 105 | 106 | - Apple Documentation : SCNTechnique 107 | - ARKit Theory: Intro to SCNTechniques. 108 | - How to create a glowing neon effect for a geometry in ARKit through a SCN Technique 109 | - How to connect custom variables to SCNTechniques and Associated Metal Shaders 110 | - A SCNTechnique requires a .scn model 111 | 112 | Stroke: 113 | The key parts to this working are found in *PieceOfArtzy/PieceOfArtzy.swift* line 66 -> 92. The amount of the letter that must be shown at any given instance has to be programmed in order for the camera to be able to capture it. For a non-capturable version and how to take it from there to the latest version, please read: 114 | 115 | - Free Stroke Metal Shader on a Timer 116 | 117 | - ARKit Tutorial: How to attach Custom Variables to a Metal Shader & its associated SCNProgram through a TimedStroke Shader iOS 12. 118 | 119 | - How to connect custom variables to SCNTechniques and Associated Metal Shaders 120 | 121 | 122 | Code: 123 | 124 | The key parts to this working are found in *PieceOfArtzy/PieceOfArtzy.swift* line 264 -> 312, with the SCNTechnique and associated assets under the *PieceOfArtzy/SpecialEffects/Glow* folder. 125 | 126 | 127 | ## 'hand' by delasign 128 | 129 | 130 | 131 | This project features an outline of a hand that animates to show you the peace sign. 132 | 133 | For tutorials on how this was created please read the following: 134 | 135 | Geometry: 136 | 137 | - How to use an Adobe Illustrator Curve in Maya. 138 | - How to turn a turn a simple sketch into an extruded model on Maya 139 | - UV Mapping: How to Convert an Extruded Cylinder’s UV’s to Simple Layout 140 | 141 | Animation: 142 | Please note that the key to this is to only rotate the joints. 143 | 144 | - How to make an animtion in Maya that works in SceneKit or ARKit. 145 | 146 | - Maya Weight Painting Tutorial 147 | 148 | Code: 149 | 150 | The key parts to this working are found in *PieceOfArtzy/PieceOfArtzy.swift* line 41 -> 59. 151 | 152 | 153 | # Shader library 154 | If you are new to Shaders please read this: Vertices, Metal Shaders, UV Mapping and SCNProgram’s. 155 | 156 | The current shader library can be found in *PieceOfArtzy/Shaders* and includes: 157 | 158 | - Color Shader 159 | - Texture Shader 160 | - Stroke Shader 161 | - Backwards Stroke Shader 162 | - Timed Stroke Shader 163 | - Timed Backwards Stroke Shader 164 | - Fade In Color Shader 165 | - Fade In Texture Shader 166 | 167 | 168 | 169 | # License 170 | MIT License 171 | 172 | Copyright (c) 2018 Delasign LLC. 173 | 174 | Permission is hereby granted, free of charge, to any person obtaining a copy 175 | of this software and associated documentation files (the "Software"), to deal 176 | in the Software without restriction, including without limitation the rights 177 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 178 | copies of the Software, and to permit persons to whom the Software is 179 | furnished to do so, subject to the following conditions: 180 | 181 | The above copyright notice and this permission notice shall be included in all 182 | copies or substantial portions of the Software. 183 | 184 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 185 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 186 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 187 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 188 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 189 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 190 | SOFTWARE. 191 | 192 | ## Artzy™ Logo 193 | 194 | Created by AdamFu under the and licensed under the Creative Commons Attribution 4.0 International License. 195 | 196 | 197 | 198 | 199 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Delasign LLC. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. --------------------------------------------------------------------------------