├── Assets ├── SwiftMetal.png └── SwiftMetal-Bond-Logo-Mini.png ├── .gitignore ├── Resources ├── TestMedia.xcassets │ ├── Contents.json │ ├── photo1.imageset │ │ ├── 5146521371_da07f238ab_o.jpg │ │ └── Contents.json │ └── photo2.imageset │ │ ├── 6145695930_547db05626_o.jpg │ │ └── Contents.json ├── Headers │ ├── SwiftMetal.h │ ├── SwiftMetal_tvOS.h │ └── SwiftMetal_macOS.h ├── Info.plist └── Template.metal ├── SwiftMetalDemo ├── Assets.xcassets │ ├── Contents.json │ └── AppIcon.appiconset │ │ └── Contents.json ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json ├── ContentView.swift ├── AppDelegate.swift ├── SceneDelegate.swift ├── Base.lproj │ └── LaunchScreen.storyboard ├── Info.plist └── Main.swift ├── SwiftMetal.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── xcuserdata │ ├── anton.xcuserdatad │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ └── hexagons.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ └── xcschememanagement.plist ├── xcshareddata │ └── xcschemes │ │ └── SwiftMetal_iOS.xcscheme └── project.pbxproj ├── Package.swift ├── SwiftMetalTests ├── Info.plist └── SwiftMetalTests.swift ├── SwiftMetalTool └── main.swift ├── SwiftMetal.podspec ├── Sources ├── SMCode.swift ├── Types │ ├── SMValue.swift │ ├── SMEntity.swift │ ├── SMBool.swift │ ├── SMFloat.swift │ ├── SMVector.swift │ └── SMTexture.swift ├── SMFunction.swift ├── Other │ └── Float16.swift ├── Types.swift ├── SMShader.swift ├── SMView.swift ├── SMBuilder.swift └── SMRenderer.swift ├── LICENSE ├── ExampleShaders ├── Photos.swift ├── Camera.swift └── Logo.swift └── README.md /Assets/SwiftMetal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heestand-xyz/SwiftMetal/HEAD/Assets/SwiftMetal.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | .build/* 4 | .swiftpm/* 5 | 6 | *.xcodeproj/project.xcworkspace/xcuserdata/* -------------------------------------------------------------------------------- /Resources/TestMedia.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /SwiftMetalDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Assets/SwiftMetal-Bond-Logo-Mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heestand-xyz/SwiftMetal/HEAD/Assets/SwiftMetal-Bond-Logo-Mini.png -------------------------------------------------------------------------------- /SwiftMetalDemo/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Resources/TestMedia.xcassets/photo1.imageset/5146521371_da07f238ab_o.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heestand-xyz/SwiftMetal/HEAD/Resources/TestMedia.xcassets/photo1.imageset/5146521371_da07f238ab_o.jpg -------------------------------------------------------------------------------- /Resources/TestMedia.xcassets/photo2.imageset/6145695930_547db05626_o.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heestand-xyz/SwiftMetal/HEAD/Resources/TestMedia.xcassets/photo2.imageset/6145695930_547db05626_o.jpg -------------------------------------------------------------------------------- /SwiftMetal.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SwiftMetal.xcodeproj/xcuserdata/anton.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /SwiftMetal.xcodeproj/xcuserdata/hexagons.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /SwiftMetal.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Resources/TestMedia.xcassets/photo1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "5146521371_da07f238ab_o.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Resources/TestMedia.xcassets/photo2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "6145695930_547db05626_o.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "SwiftMetal", 6 | platforms: [ 7 | .iOS(.v13), 8 | .macOS(.v10_15), 9 | .tvOS(.v13), 10 | ], 11 | products: [ 12 | .library(name: "SwiftMetal", targets: ["SwiftMetal"]), 13 | ], 14 | targets: [ 15 | .target(name: "SwiftMetal", path: "Sources"), 16 | .testTarget(name: "SwiftMetalTests", dependencies: ["SwiftMetal"], path: "SwiftMetalTests"), 17 | ] 18 | ) 19 | -------------------------------------------------------------------------------- /Resources/Headers/SwiftMetal.h: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftMetal.h 3 | // SwiftMetal 4 | // 5 | // Created by Anton Heestand on 2019-12-06. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for SwiftMetal. 12 | FOUNDATION_EXPORT double SwiftMetalVersionNumber; 13 | 14 | //! Project version string for SwiftMetal. 15 | FOUNDATION_EXPORT const unsigned char SwiftMetalVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Resources/Headers/SwiftMetal_tvOS.h: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftMetal_tvOS.h 3 | // SwiftMetal_tvOS 4 | // 5 | // Created by Hexagons on 2019-12-09. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for SwiftMetal_tvOS. 12 | FOUNDATION_EXPORT double SwiftMetal_tvOSVersionNumber; 13 | 14 | //! Project version string for SwiftMetal_tvOS. 15 | FOUNDATION_EXPORT const unsigned char SwiftMetal_tvOSVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Resources/Headers/SwiftMetal_macOS.h: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftMetal_macOS.h 3 | // SwiftMetal_macOS 4 | // 5 | // Created by Hexagons on 2019-12-09. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for SwiftMetal_macOS. 12 | FOUNDATION_EXPORT double SwiftMetal_macOSVersionNumber; 13 | 14 | //! Project version string for SwiftMetal_macOS. 15 | FOUNDATION_EXPORT const unsigned char SwiftMetal_macOSVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /SwiftMetalDemo/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // SwiftMetalDemo 4 | // 5 | // Created by Anton Heestand on 2019-12-09. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | import SwiftMetal 11 | 12 | struct ContentView: View { 13 | // @EnvironmentObject var main: Main 14 | var body: some View { 15 | SMView { 16 | SMShader { uv in 17 | let uv4: SMFloat4 = float4(uv.x, uv.y, 0.0, 1.0) 18 | let c: SMFloat4 = max(uv4, float4(0.5)) 19 | return c 20 | } 21 | } 22 | } 23 | } 24 | 25 | struct ContentView_Previews: PreviewProvider { 26 | static var previews: some View { 27 | ContentView() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /SwiftMetalTests/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /SwiftMetalTool/main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // main.swift 3 | // SwiftMetalTool 4 | // 5 | // Created by Hexagons on 2019-12-09. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | import SwiftMetal 11 | 12 | print("SwiftMetal") 13 | 14 | let shader = SMShader { uv in 15 | float4(uv.x, uv.y, 0.0, 1.0) 16 | } 17 | 18 | print("Render...") 19 | 20 | let res = CGSize(width: 4096, height: 4096) 21 | let texture = try! SMRenderer.render(shader, at: res, as: .rgba32Float) 22 | let image = try! texture.image() 23 | 24 | print("Rendered!") 25 | 26 | let desktopURL = FileManager.default.urls(for: .desktopDirectory, in: .userDomainMask).first! 27 | let fileURL = desktopURL.appendingPathComponent("swift-metal-render-32.tiff") 28 | let data: Data = image.tiffRepresentation! 29 | try! data.write(to: fileURL, options: .atomic) 30 | //let pngData = NSBitmapImageRep(data: data)!.representation(using: .png, properties: [:])! 31 | 32 | print("Saved!") 33 | -------------------------------------------------------------------------------- /Resources/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSHumanReadableCopyright 22 | Copyright © 2019 Hexagons. All rights reserved. 23 | 24 | 25 | -------------------------------------------------------------------------------- /SwiftMetal.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | 3 | spec.name = "SwiftMetal" 4 | spec.version = "0.1.3" 5 | 6 | spec.summary = "Write Metal in Swift" 7 | spec.description = <<-DESC 8 | Write Metal in Swift 9 | Auto generated Metal code 10 | DESC 11 | 12 | spec.homepage = "http://hexagons.se" 13 | 14 | spec.license = { :type => "MIT", :file => "LICENSE" } 15 | 16 | spec.author = { "Hexagons" => "anton@hexagons.se" } 17 | spec.social_media_url = "https://twitter.com/anton_hexagons" 18 | 19 | spec.ios.deployment_target = "13.0" 20 | spec.osx.deployment_target = "10.15" 21 | spec.tvos.deployment_target = "13.0" 22 | 23 | spec.swift_version = '5.0' 24 | 25 | spec.source = { :git => "https://github.com/hexagons/SwiftMetal.git", :branch => "master", :tag => "#{spec.version}" } 26 | 27 | spec.source_files = "Sources", "Sources/**/*.swift" 28 | 29 | end 30 | -------------------------------------------------------------------------------- /SwiftMetalDemo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SwiftMetalDemo 4 | // 5 | // Created by Anton Heestand on 2019-12-09. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 15 | return true 16 | } 17 | 18 | // MARK: UISceneSession Lifecycle 19 | 20 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 21 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 22 | } 23 | 24 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {} 25 | 26 | } 27 | 28 | -------------------------------------------------------------------------------- /Sources/SMCode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SMCode.swift 3 | // SwiftMetal 4 | // 5 | // Created by Anton Heestand on 2019-12-06. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct SMCode { 12 | 13 | var snippet: String 14 | var uniforms: [SMUniformPack] 15 | var variables: [SMVariablePack] 16 | var functions: [SMFunction] 17 | 18 | init(_ snippet: String, uniforms: [SMUniformPack], variables: [SMVariablePack], functions: [SMFunction]) { 19 | self.snippet = snippet 20 | self.uniforms = uniforms 21 | self.variables = variables 22 | self.functions = functions 23 | } 24 | 25 | // init(_ snippet: String) { 26 | // self.snippet = snippet 27 | // uniforms = [] 28 | // variables = [] 29 | // functions = [] 30 | // } 31 | 32 | // init() { 33 | // snippet = "" 34 | // uniforms = [] 35 | // variables = [] 36 | // functions = [] 37 | // } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /SwiftMetal.xcodeproj/xcuserdata/hexagons.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SwiftMetalDemo.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 3 11 | 12 | SwiftMetalTool.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 4 16 | 17 | SwiftMetal_iOS.xcscheme_^#shared#^_ 18 | 19 | orderHint 20 | 0 21 | 22 | SwiftMetal_macOS.xcscheme_^#shared#^_ 23 | 24 | orderHint 25 | 1 26 | 27 | SwiftMetal_tvOS.xcscheme_^#shared#^_ 28 | 29 | orderHint 30 | 2 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 ⬢ Hexagons 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. 22 | -------------------------------------------------------------------------------- /SwiftMetal.xcodeproj/xcuserdata/anton.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SwiftMetal.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | SwiftMetalDemo.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 3 16 | 17 | SwiftMetalTool.xcscheme_^#shared#^_ 18 | 19 | orderHint 20 | 4 21 | 22 | SwiftMetal_iOS.xcscheme_^#shared#^_ 23 | 24 | orderHint 25 | 0 26 | 27 | SwiftMetal_macOS.xcscheme_^#shared#^_ 28 | 29 | orderHint 30 | 1 31 | 32 | SwiftMetal_tvOS.xcscheme_^#shared#^_ 33 | 34 | orderHint 35 | 2 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Sources/Types/SMValue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SMValue.swift 3 | // SwiftMetal 4 | // 5 | // Created by Anton Heestand on 2019-12-06. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | //public protocol SMRawValue { 12 | // static var typeName: String { get } 13 | //} 14 | 15 | public class SMValue: SMEntity { 16 | 17 | public typealias FV = () -> (V) 18 | 19 | var futureValue: FV? 20 | var _value: V? 21 | public var value: V? { _value ?? futureValue?() } 22 | 23 | init(_ value: V, type: String, fromEntities: [SMEntity] = []) { 24 | self._value = value 25 | super.init(type: type, fromEntities: fromEntities) 26 | } 27 | 28 | init(_ futureValue: @escaping FV, type: String) { 29 | self.futureValue = futureValue 30 | super.init(type: type, isFuture: true) 31 | } 32 | 33 | init(operation: SMOperation, snippet: @escaping () -> (String), type: String) { 34 | super.init(type: type, operation: operation) 35 | self.snippet = snippet 36 | } 37 | 38 | init(type: String, fromEntities: [SMEntity] = []) { 39 | super.init(type: type, fromEntities: fromEntities) 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /SwiftMetalDemo/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // SwiftMetalDemo 4 | // 5 | // Created by Anton Heestand on 2019-12-09. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import SwiftUI 11 | 12 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 17 | 18 | // let main = Main() 19 | 20 | let contentView = ContentView() 21 | // .environmentObject(main) 22 | 23 | if let windowScene = scene as? UIWindowScene { 24 | let window = UIWindow(windowScene: windowScene) 25 | window.rootViewController = UIHostingController(rootView: contentView) 26 | self.window = window 27 | window.makeKeyAndVisible() 28 | } 29 | 30 | } 31 | 32 | func sceneDidDisconnect(_ scene: UIScene) {} 33 | 34 | func sceneDidBecomeActive(_ scene: UIScene) {} 35 | func sceneWillResignActive(_ scene: UIScene) {} 36 | 37 | func sceneWillEnterForeground(_ scene: UIScene) {} 38 | func sceneDidEnterBackground(_ scene: UIScene) {} 39 | 40 | } 41 | 42 | -------------------------------------------------------------------------------- /ExampleShaders/Photos.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Photos.swift 3 | // SwiftMetal_iOS 4 | // 5 | // Created by Anton Heestand on 2019-12-12. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | import SwiftMetal 11 | 12 | let photosShader: SMShader = SMShader { uv in 13 | let photo1 = SMTexture(image: UIImage(named: "photo1")!)! 14 | let photo2 = SMTexture(image: UIImage(named: "photo2")!)! 15 | let mask: SMBool = photo2.r < 0.1 16 | return mask photo1 <=> photo2 17 | } 18 | 19 | struct PhotosView: View { 20 | var body: some View { 21 | ZStack { 22 | Color.black 23 | .edgesIgnoringSafeArea(.all) 24 | VStack(spacing: 0) { 25 | HStack(spacing: 0) { 26 | Image("photo1") 27 | .resizable() 28 | .aspectRatio(1.5, contentMode: .fit) 29 | Image("photo2") 30 | .resizable() 31 | .aspectRatio(1.5, contentMode: .fit) 32 | } 33 | SMView { photosShader } 34 | .aspectRatio(1.5, contentMode: .fit) 35 | } 36 | } 37 | } 38 | } 39 | 40 | struct PhotosView_Previews: PreviewProvider { 41 | static var previews: some View { 42 | PhotosView() 43 | .previewLayout(.fixed(width: 750, height: 750)) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Resources/Template.metal: -------------------------------------------------------------------------------- 1 | // 2 | // Template.metal 3 | // SwiftMetal 4 | // 5 | // Created by Anton Heestand on 2019-12-06. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | #include 10 | using namespace metal; 11 | 12 | float4 f0(float4 input) { 13 | return input + input; 14 | } 15 | 16 | struct Uniforms { 17 | float u0; 18 | }; 19 | 20 | kernel void swiftMetal(constant Uniforms& us [[ buffer(0) ]], 21 | texture2d tex [[ texture(0) ]], 22 | texture2d tex0 [[ texture(1) ]], 23 | texture2d tex1 [[ texture(2) ]], 24 | uint2 pos [[ thread_position_in_grid ]], 25 | sampler smp [[ sampler(0) ]]) { 26 | 27 | int x = pos.x; 28 | int y = pos.y; 29 | int w = tex.get_width(); 30 | int h = tex.get_height(); 31 | 32 | if (x >= w || y >= h) { return; } 33 | 34 | float u = (float(x) + 0.5) / float(w); 35 | float v = (float(y) + 0.5) / float(h); 36 | float2 uv = float2(u, v); 37 | 38 | float4 t0 = tex0.read(pos); 39 | float4 t1 = tex1.sample(smp, uv); 40 | float4 k0 = float4(0); 41 | bool b0 = true; 42 | bool b1 = false; 43 | bool v0 = b0 && b1; 44 | float4 v1 = max(t0, t1); 45 | 46 | float4 val = f0(t0) + float4(us.u0, 0.0, 0.0, 1.0) * t1 + k0 + (!v0 ? 1.0 : 0.0) + v1; 47 | 48 | tex.write(val, pos); 49 | 50 | } 51 | -------------------------------------------------------------------------------- /SwiftMetalDemo/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 | -------------------------------------------------------------------------------- /Sources/Types/SMEntity.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SMEntity.swift 3 | // SwiftMetal 4 | // 5 | // Created by Anton Heestand on 2019-12-06. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public class SMEntity: Identifiable, Equatable { 12 | 13 | public let id: UUID 14 | 15 | let type: String 16 | 17 | public var snippet: () -> (String) = { "#" } 18 | 19 | let operation: SMOperation? 20 | 21 | var isArg: Bool = false 22 | var returnId: UUID? 23 | var isReturn: Bool { returnId != nil } 24 | 25 | let isFuture: Bool 26 | var futureIndex: Int? 27 | var futureSnippet: String { 28 | "us.u\(futureIndex ?? -1)" 29 | } 30 | 31 | var subscriptEntity: SMEntity? 32 | 33 | var sampleTexture: SMTexture? 34 | var sampleUV: SMFloat2? 35 | 36 | let fromEntities: [SMEntity] 37 | 38 | var hasSink: Bool = false 39 | var sink: (() -> ())? 40 | 41 | var rawUniforms: [SMRawType]? { nil } 42 | 43 | var children: [SMEntity] { 44 | var children: [SMEntity] = [ 45 | operation?.lhs, 46 | operation?.rhs, 47 | subscriptEntity, 48 | sampleTexture, 49 | sampleUV 50 | ] 51 | .compactMap({ $0 }) 52 | children.append(contentsOf: fromEntities) 53 | return children 54 | } 55 | 56 | init(type: String, operation: SMOperation? = nil, isFuture: Bool = false, fromEntities: [SMEntity] = []) { 57 | id = UUID() 58 | self.type = type 59 | self.operation = operation 60 | self.isFuture = isFuture 61 | self.fromEntities = fromEntities 62 | if isFuture { 63 | snippet = { 64 | self.futureSnippet 65 | } 66 | } 67 | } 68 | 69 | // MARK: - Equatable 70 | 71 | public static func == (lhs: SMEntity, rhs: SMEntity) -> Bool { 72 | lhs.id == rhs.id 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /SwiftMetalDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /SwiftMetalDemo/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 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSCameraUsageDescription 24 | SwiftMetalDemo 25 | UIApplicationSceneManifest 26 | 27 | UIApplicationSupportsMultipleScenes 28 | 29 | UISceneConfigurations 30 | 31 | UIWindowSceneSessionRoleApplication 32 | 33 | 34 | UISceneConfigurationName 35 | Default Configuration 36 | UISceneDelegateClassName 37 | $(PRODUCT_MODULE_NAME).SceneDelegate 38 | 39 | 40 | 41 | 42 | UILaunchStoryboardName 43 | LaunchScreen 44 | UIRequiredDeviceCapabilities 45 | 46 | armv7 47 | 48 | UISupportedInterfaceOrientations 49 | 50 | UIInterfaceOrientationPortrait 51 | 52 | UISupportedInterfaceOrientations~ipad 53 | 54 | UIInterfaceOrientationPortrait 55 | UIInterfaceOrientationPortraitUpsideDown 56 | UIInterfaceOrientationLandscapeLeft 57 | UIInterfaceOrientationLandscapeRight 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /SwiftMetalTests/SwiftMetalTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftMetalTests.swift 3 | // SwiftMetalTests 4 | // 5 | // Created by Anton Heestand on 2019-12-06. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import SwiftMetal 11 | 12 | class SwiftMetalTests: XCTestCase { 13 | 14 | override func setUp() {} 15 | 16 | override func tearDown() {} 17 | 18 | func testShader() { 19 | 20 | let shader = SMShader { uv in 21 | let add: SMFunc = function { args -> SMFloat4 in 22 | let a = args[0] as! SMFloat4 23 | let b = args[1] as! SMFloat4 24 | return a + b 25 | } 26 | let sub = function { args -> SMFloat4 in 27 | (args[0] as! SMFloat4) - (args[1] as! SMFloat4) 28 | } 29 | let mult = function { args -> SMFloat4 in 30 | (args[0] as! SMFloat4) * (args[1] as! SMFloat4) * (args[2] as! SMFloat4) 31 | } 32 | let a = float4(1, 1, 1, 1) 33 | let b = float4(2, 2, 2, 2) 34 | let c = float4(2, 2, 2, 2) 35 | let d = float4(3) 36 | let e = float4(4) 37 | let aa = a + a - a 38 | let bb = b + b - b 39 | let cc = c + c - c 40 | return add.call(d, e) + mult.call(aa, bb, cc) + sub.call(d, e) 41 | } 42 | 43 | let res = CGSize(width: 1, height: 1) 44 | let render: SMTexture = try! SMRenderer.render(shader, at: res, as: .rgba16Float) 45 | 46 | if let raw8 = try? render.raw8() { 47 | if raw8.count <= 256 { 48 | print("raw8", raw8.map({ CGFloat($0) / 255 })) 49 | } 50 | XCTAssertNotEqual(raw8.first!, 0) 51 | } else if let raw16 = try? render.raw16() { 52 | if raw16.count <= 256 { 53 | print("raw16", raw16) 54 | } 55 | XCTAssertNotEqual(raw16.first!, 0.0) 56 | } else if let raw32 = try? render.raw32() { 57 | if raw32.count <= 256 { 58 | print("raw32", raw32) 59 | } 60 | XCTAssertNotEqual(raw32.first!, 0.0) 61 | } 62 | 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /Sources/SMFunction.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SMFunction.swift 3 | // SwiftMetal 4 | // 5 | // Created by Hexagons on 2019-12-07. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public class SMFunc: Identifiable { 12 | 13 | public let id: UUID 14 | 15 | let function: ([SMEntity]) -> (SMEntity) 16 | 17 | public init(_ function: @escaping ([SMEntity]) -> (R)) { 18 | id = UUID() 19 | self.function = function 20 | } 21 | 22 | public func call(_ arguments: SMEntity...) -> R { 23 | arguments.forEach { entity in 24 | entity.isArg = true 25 | } 26 | let returnEntity = function(arguments) 27 | returnEntity.returnId = id 28 | return returnEntity as! R 29 | } 30 | 31 | } 32 | 33 | public func function(_ function: @escaping ([SMEntity]) -> (R)) -> SMFunc { 34 | SMFunc(function) 35 | } 36 | 37 | struct SMFunction { 38 | let argEntities: [SMEntity] 39 | let returnEntity: SMEntity 40 | let index: Int 41 | var name: String { 42 | return "f\(index)" 43 | } 44 | var code: String { 45 | var lines: [Line] = [] 46 | var declaration = "" 47 | declaration += "\(returnEntity.type) \(name)(" 48 | for (i, argEntity) in argEntities.enumerated() { 49 | if i > 0 { 50 | declaration += ", " 51 | } 52 | declaration += "\(argEntity.type) a\(i)" 53 | } 54 | declaration += ") {" 55 | lines.append(Line(declaration)) 56 | var snippet: String = returnEntity.snippet() 57 | for (i, argEntity) in argEntities.enumerated() { 58 | if let snippetIndexRange = snippet.range(of: argEntity.snippet()) { 59 | snippet = snippet.replacingCharacters(in: snippetIndexRange, with: "a\(i)") 60 | } 61 | } 62 | lines.append(Line(in: 1, "return \(snippet);")) 63 | lines.append(Line("}")) 64 | return Line.merge(lines) 65 | } 66 | func snippet(with args: [SMEntity]) -> String { 67 | var call = "" 68 | call += "\(name)(" 69 | for (i, arg) in args.enumerated() { 70 | if i > 0 { 71 | call += ", " 72 | } 73 | call += "\(arg.snippet())" 74 | } 75 | call += ")" 76 | return call 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /Sources/Other/Float16.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Float16.swift 3 | // SwiftMetal 4 | // 5 | // Created by Hexagons on 2019-12-09. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | // by kerfuffle on Dec 5, 2017 1:59 AM 9 | // https://forums.developer.apple.com/thread/93282 10 | // 11 | 12 | import Foundation 13 | import Accelerate 14 | 15 | /* Utility functions for dealing with 16-bit floating point values in Swift. */ 16 | 17 | /** 18 | Since Swift has no datatype for a 16-bit float we use `UInt16`s instead, 19 | which take up the same amount of memory. (Note: The simd framework does 20 | have "half" types but only for 2, 3, or 4-element vectors, not scalars.) 21 | */ 22 | public typealias Float16 = UInt16 23 | 24 | /** 25 | Creates a new array of Swift `Float` values from a buffer of float-16s. 26 | */ 27 | public func float16to32(_ input: UnsafeMutablePointer, count: Int) -> [Float] { 28 | var output = [Float](repeating: 0, count: count) 29 | float16to32(input: input, output: &output, count: count) 30 | return output 31 | } 32 | 33 | /** 34 | Converts a buffer of float-16s into a buffer of `Float`s, in-place. 35 | */ 36 | public func float16to32(input: UnsafeMutablePointer, output: UnsafeMutableRawPointer, count: Int) { 37 | var bufferFloat16 = vImage_Buffer(data: input, height: 1, width: UInt(count), rowBytes: count * 2) 38 | var bufferFloat32 = vImage_Buffer(data: output, height: 1, width: UInt(count), rowBytes: count * 4) 39 | 40 | if vImageConvert_Planar16FtoPlanarF(&bufferFloat16, &bufferFloat32, 0) != kvImageNoError { 41 | print("Error converting float16 to float32") 42 | } 43 | } 44 | 45 | /** 46 | Creates a new array of float-16 values from a buffer of `Float`s. 47 | */ 48 | public func float32to16(_ input: UnsafeMutablePointer, count: Int) -> [Float16] { 49 | var output = [Float16](repeating: 0, count: count) 50 | float32to16(input: input, output: &output, count: count) 51 | return output 52 | } 53 | 54 | /** 55 | Converts a buffer of `Float`s into a buffer of float-16s, in-place. 56 | */ 57 | public func float32to16(input: UnsafeMutablePointer, output: UnsafeMutableRawPointer, count: Int) { 58 | var bufferFloat32 = vImage_Buffer(data: input, height: 1, width: UInt(count), rowBytes: count * 4) 59 | var bufferFloat16 = vImage_Buffer(data: output, height: 1, width: UInt(count), rowBytes: count * 2) 60 | 61 | if vImageConvert_PlanarFtoPlanar16F(&bufferFloat32, &bufferFloat16, 0) != kvImageNoError { 62 | print("Error converting float32 to float16") 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /ExampleShaders/Camera.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Camera.swift 3 | // SwiftMetal_iOS 4 | // 5 | // Created by Anton Heestand on 2019-12-12. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | import SwiftMetal 11 | import AVKit 12 | 13 | struct CameraView: View { 14 | @ObservedObject var camera: Camera = Camera.main 15 | var body: some View { 16 | ZStack { 17 | Color.black 18 | .edgesIgnoringSafeArea(.all) 19 | SMView { 20 | SMShader { uv in 21 | SMLiveTexture(self.$camera.pixelBuffer) 22 | .sample(at: float2(uv.y, 1.0 - uv.x)) 23 | } 24 | } 25 | .aspectRatio(9 / 16, contentMode: .fit) 26 | } 27 | } 28 | } 29 | 30 | class Camera: NSObject, ObservableObject, AVCaptureVideoDataOutputSampleBufferDelegate { 31 | 32 | static let main = Camera() 33 | 34 | @Published var pixelBuffer: CVPixelBuffer? 35 | 36 | let device: AVCaptureDevice 37 | let session: AVCaptureSession 38 | let input: AVCaptureDeviceInput 39 | let output: AVCaptureVideoDataOutput 40 | 41 | override init() { 42 | device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back)! 43 | session = AVCaptureSession() 44 | input = try! AVCaptureDeviceInput(device: device) 45 | output = AVCaptureVideoDataOutput() 46 | super.init() 47 | setup() 48 | } 49 | 50 | func setup() { 51 | output.alwaysDiscardsLateVideoFrames = true 52 | output.videoSettings = [ 53 | kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_32BGRA 54 | ] 55 | guard session.canAddInput(input) else { 56 | print("Camera - Can't add input") 57 | return 58 | } 59 | session.addInput(input) 60 | guard session.canAddOutput(output) else { 61 | print("Camera - Can't add output") 62 | return 63 | } 64 | session.addOutput(output) 65 | let queue = DispatchQueue(label: "camera.queue") 66 | output.setSampleBufferDelegate(self, queue: queue) 67 | session.startRunning() 68 | } 69 | 70 | func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) { 71 | guard let buffer: CVImageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { 72 | print("Camera - Buffer get failed.") 73 | return 74 | } 75 | DispatchQueue.main.async { 76 | self.pixelBuffer = buffer 77 | } 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /SwiftMetalDemo/Main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Main.swift 3 | // SwiftMetalDemo 4 | // 5 | // Created by Anton Heestand on 2019-12-13. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import SwiftMetal 11 | import Metal 12 | 13 | class Main: ObservableObject { 14 | 15 | let res: CGSize 16 | 17 | let camera: Camera 18 | 19 | var shader: SMShader! 20 | 21 | let drawableTexture: MTLTexture 22 | @Published var finalTexture: MTLTexture? 23 | 24 | @Published var value: Float = 0.5 25 | 26 | var displayLink: CADisplayLink! 27 | var rendering: Bool = false 28 | 29 | init() { 30 | 31 | let width: CGFloat = UIScreen.main.nativeBounds.width 32 | res = CGSize(width: width, height: width * (16 / 9)) 33 | 34 | drawableTexture = SMTexture.emptyTexture(at: res, as: .rgba8Unorm)! 35 | 36 | camera = Camera() 37 | 38 | shader = SMShader({ uv in 39 | let cross: SMFunc = function { args -> SMFloat4 in 40 | let a: SMFloat4 = args[0] as! SMFloat4 41 | let b: SMFloat4 = args[1] as! SMFloat4 42 | let f: SMFloat = args[2] as! SMFloat 43 | let f4: SMFloat4 = float4(f) 44 | return a * (float(1.0) - f4) + b * f4 45 | } 46 | let cam = SMLiveTexture(self.camera.$pixelBuffer) 47 | .sample(at: float2(uv.y, 1.0 - uv.x)) 48 | let feed = SMTexture(texture: drawableTexture) 49 | let val: SMFloat = 0.9 + 0.2 * SMLiveFloat($value) 50 | let disp = feed.sample(at: float2((uv.x - 0.5) * val + 0.5, 51 | (uv.y - 0.5) * val + 0.5)) 52 | return cross.call(cam, disp, float(0.9)) 53 | }) 54 | 55 | displayLink = CADisplayLink(target: self, selector: #selector(frameLoop)) 56 | displayLink.add(to: .current, forMode: .common) 57 | 58 | } 59 | 60 | @objc func frameLoop() { 61 | print("Demo - Frame Loop") 62 | guard !rendering else { return } 63 | rendering = true 64 | DispatchQueue.global(qos: .background).async { 65 | print("Demo - Render Start") 66 | let startTime = CFAbsoluteTimeGetCurrent() 67 | let renderedTexture = try! SMRenderer.render(self.shader, at: self.res, on: self.drawableTexture) 68 | let endTime = CFAbsoluteTimeGetCurrent() 69 | let renderTime = endTime - startTime 70 | let renderTimeMs = Double(Int(round(renderTime * 1_000_000))) / 1_000 71 | print("Demo - Render Time \(renderTimeMs)ms") 72 | DispatchQueue.main.async { 73 | print("Demo - Render Done") 74 | self.finalTexture = renderedTexture.texture //copyTexture() 75 | self.rendering = false 76 | } 77 | } 78 | 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /SwiftMetal.xcodeproj/xcshareddata/xcschemes/SwiftMetal_iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 54 | 60 | 61 | 67 | 68 | 69 | 70 | 72 | 73 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # SwiftMetal 4 | 5 | [![License](https://img.shields.io/cocoapods/l/SwiftMetal.svg)](https://github.com/hexagons/SwiftMetal/blob/master/LICENSE) 6 | [![Cocoapods](https://img.shields.io/cocoapods/v/SwiftMetal.svg)](http://cocoapods.org/pods/SwiftMetal) 7 | [![Platform](https://img.shields.io/cocoapods/p/SwiftMetal.svg)](http://cocoapods.org/pods/SwiftMetal) 8 | 9 | 10 | ## Install 11 | 12 | Swift Package or CocoaPods 13 | 14 | ```ruby 15 | pod 'SwiftMetal' 16 | ``` 17 | 18 | ## Write Metal in Swift 19 | 20 | ~~~~swift 21 | import SwiftMetal 22 | ~~~~ 23 | 24 | ~~~~swift 25 | let add: SMFunc = function { args -> SMFloat4 in 26 | let a = args[0] as! SMFloat4 27 | let b = args[1] as! SMFloat4 28 | return a + b 29 | } 30 | let shader = SMShader { uv in 31 | let a = float4(0.1, 0.0, 0.0, 1.0) 32 | let b = float4(0.2, 0.0, 0.0, 1.0) 33 | let t = SMTexture(image: UIImage(named: "photo1")!)! 34 | let c: SMFloat4 = add.call(a, a) * add.call(b, b) + t 35 | return c 36 | } 37 | let res = CGSize(width: 1024, height: 1024) 38 | let render: SMTexture = try! SMRenderer.render(shader: shader, at: res) 39 | let image: UIImage = try! render.image() 40 | let texture: MTLTexture = render.texture 41 | ~~~~ 42 | 43 | 44 | ## Write Metal in SwiftUI 45 | 46 | ~~~~swift 47 | import SwiftUI 48 | import SwiftMetal 49 | ~~~~ 50 | 51 | ~~~~swift 52 | struct ContentView: View { 53 | @State var value: Float = 0.5 54 | var body: some View { 55 | VStack { 56 | Slider(value: $value) 57 | SMView { 58 | SMShader { uv in 59 | let tex1 = SMTexture(image: UIImage(named: "photo1")!)! 60 | let tex2 = SMTexture(image: UIImage(named: "photo2")!)! 61 | let val = SMLiveFloat(self.$value) 62 | return tex1.sample(at: uv + float2(tex2.r * -val, 0.0)) 63 | } 64 | } 65 | .aspectRatio(1.5, contentMode: .fit) 66 | .cornerRadius(10) 67 | } 68 | } 69 | } 70 | ~~~~ 71 | 72 | 73 | ## Auto generated Metal code 74 | 75 | Generated from first Swift example. 76 | 77 | ~~~~metal 78 | #include 79 | using namespace metal; 80 | 81 | float4 f0(float4 a0, float4 a1) { 82 | return (a0 + a1); 83 | } 84 | 85 | kernel void swiftMetal( 86 | texture2d tex [[ texture(0) ]], 87 | texture2d tex0 [[ texture(1) ]], 88 | uint2 pos [[ thread_position_in_grid ]], 89 | sampler smp [[ sampler(0) ]] 90 | ) { 91 | 92 | if (pos.x >= tex.get_width() || pos.y >= tex.get_height()) { return; } 93 | 94 | float4 t0 = tex0.read(pos); 95 | 96 | float4 v0 = float4(0.1, 0.0, 0.0, 1.0); 97 | float4 v1 = float4(0.2, 0.0, 0.0, 1.0); 98 | 99 | float4 val = ((f0(v0, v0) * f0(v1, v1)) + t0); 100 | 101 | tex.write(val, pos); 102 | 103 | } 104 | ~~~~ 105 | -------------------------------------------------------------------------------- /ExampleShaders/Logo.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Logo.swift 3 | // SwiftMetalDemo 4 | // 5 | // Created by Anton Heestand on 2019-12-12. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | import SwiftMetal 11 | 12 | let aspect: Float = 2.5 13 | 14 | func color(_ hex: String, alpha: SMFloat = 1.0) -> SMFloat4 { 15 | var hex = hex 16 | if hex[0..<1] == "#" { 17 | if hex.count == 4 { 18 | hex = hex[1..<4] 19 | } else { 20 | hex = hex[1..<7] 21 | } 22 | } 23 | if hex.count == 3 { 24 | let r = hex[0..<1] 25 | let g = hex[1..<2] 26 | let b = hex[2..<3] 27 | hex = r + r + g + g + b + b 28 | } 29 | var hexInt: UInt32 = 0 30 | let scanner: Scanner = Scanner(string: hex) 31 | scanner.scanHexInt32(&hexInt) 32 | let r = SMFloat(Float((hexInt & 0xff0000) >> 16) / 255.0) 33 | let g = SMFloat(Float((hexInt & 0xff00) >> 8) / 255.0) 34 | let b = SMFloat(Float((hexInt & 0xff) >> 0) / 255.0) 35 | return SMFloat4([r, g, b, alpha]) 36 | } 37 | 38 | let logoShader: SMShader = SMShader { uv in 39 | 40 | let swiftColorA: SMFloat4 = color("#fd442a") 41 | let swiftColorB: SMFloat4 = color("#faa33d") 42 | let metalColorA: SMFloat4 = color("#1ffe72") 43 | let metalColorB: SMFloat4 = color("#1efdc6") 44 | 45 | let circle: SMFunc = function { args -> SMBool in 46 | let s: SMFloat = args[0] as! SMFloat 47 | let x: SMFloat = args[1] as! SMFloat 48 | let y: SMFloat = args[2] as! SMFloat 49 | let c: SMFloat = sqrt(pow(x, 2) + pow(y, 2)) 50 | return c < s 51 | } 52 | let gradient: SMFunc = function { args -> SMFloat4 in 53 | let v: SMFloat = args[0] as! SMFloat 54 | let a: SMFloat4 = args[1] as! SMFloat4 55 | let b: SMFloat4 = args[2] as! SMFloat4 56 | let f: SMFloat4 = float4(v) 57 | return (float(1.0) - f) * a + f * b 58 | } 59 | 60 | let x: SMFloat = uv.x - 0.5 61 | let y: SMFloat = (uv.y - 0.5) / SMFloat(aspect) 62 | let h: SMFloat = sqrt(3 / 4) 63 | let s: SMFloat = (1.0 / 5.0) 64 | let s2: SMFloat = s * h 65 | let s3: SMFloat = s * sqrt(1.75) 66 | 67 | let aCL: SMBool = circle.call(s, x + s * 1.5, y) 68 | let bCL: SMBool = circle.call(s / 2, x + s * 1.5, y) 69 | let aCR: SMBool = circle.call(s, x - s * 1.5, y) 70 | let bCR: SMBool = circle.call(s / 2, x - s * 1.5, y) 71 | let aCB: SMBool = circle.call(s * 2, x, y - s2 * 3) 72 | let aCT: SMBool = circle.call(s * 2, x, y + s2 * 3) 73 | let aCX: SMBool = circle.call(s3, x, y) 74 | 75 | let o1: SMBool = aCB || aCT 76 | let o2: SMBool = (aCL || aCR || aCX) && !o1 77 | let c: SMFloat4 = o2 float4(1.0) <=> float4(0.0) 78 | 79 | let swiftGradient: SMFloat4 = gradient.call(1.0 - uv.y, swiftColorA, swiftColorB) 80 | let metalGradient: SMFloat4 = gradient.call(1.0 - uv.y, metalColorA, metalColorB) 81 | let ug: SMFloat = uv.x * 2 - 0.5 82 | let swiftMetalGradient: SMFloat4 = gradient.call(ug, swiftGradient, metalGradient) 83 | 84 | let white: SMFloat4 = float4(1.0, 1.0, 1.0, 1.0) 85 | let black: SMFloat4 = float4(0.0, 0.0, 0.0, 1.0) 86 | 87 | let final: SMFloat4 = bCL white <=> (bCR black <=> (c * swiftMetalGradient)) 88 | 89 | return final 90 | } 91 | 92 | struct LogoView: View { 93 | var body: some View { 94 | ZStack { 95 | Color.black 96 | .edgesIgnoringSafeArea(.all) 97 | SMView { logoShader } 98 | .aspectRatio(CGFloat(aspect), contentMode: .fit) 99 | } 100 | } 101 | } 102 | 103 | struct LogoView_Previews: PreviewProvider { 104 | static var previews: some View { 105 | LogoView() 106 | .previewLayout(.fixed(width: CGFloat(aspect) * 350, height: 350)) 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Sources/Types.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Types.swift 3 | // SwiftMetal 4 | // 5 | // Created by Hexagons on 2019-12-08. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | #if os(macOS) 11 | import Cocoa 12 | #else 13 | import UIKit 14 | #endif 15 | 16 | #if os(macOS) 17 | public typealias _View = NSView 18 | public typealias _Image = NSImage 19 | public typealias _Color = NSColor 20 | #else 21 | public typealias _View = UIView 22 | public typealias _Image = UIImage 23 | public typealias _Color = UIColor 24 | #endif 25 | 26 | class SMVariablePack { 27 | let entity: SMEntity 28 | let index: Int 29 | let snippet: String 30 | var name: String { 31 | return "v\(index)" 32 | } 33 | var code: String { 34 | code(with: snippet) 35 | } 36 | // var rawCode: String { 37 | // code(with: entity.snippet()) 38 | // } 39 | init(for entity: SMEntity, at index: Int, with snippet: String) { 40 | self.entity = entity 41 | self.index = index 42 | self.snippet = snippet 43 | } 44 | fileprivate func code(with snippet: String) -> String { 45 | "\(entity.type) \(name) = \(snippet);" 46 | } 47 | } 48 | 49 | struct SMUniformPack { 50 | let entity: SMEntity 51 | let index: Int 52 | var name: String { 53 | return "u\(index)" 54 | } 55 | var code: String { 56 | "\(entity.type) \(name);" 57 | } 58 | var snippet: String { 59 | "us.\(name)" 60 | } 61 | } 62 | 63 | struct SMOperation { 64 | let lhs: SMEntity 65 | let rhs: SMEntity 66 | } 67 | 68 | public protocol SMRaw {} 69 | public protocol SMRawType: SMRaw { 70 | static var typeName: String { get } 71 | } 72 | 73 | public class SMTuple: SMRaw { 74 | let values: [SMValue] 75 | var count: Int { values.count } 76 | init(_ values: [SMValue]) { 77 | self.values = values 78 | } 79 | } 80 | 81 | struct Line { 82 | let indent: Int 83 | let snippet: String 84 | init(in indent: Int = 0, _ snippet: String = "") { 85 | self.indent = indent 86 | self.snippet = snippet 87 | } 88 | static func merge(_ lines: [Line]) -> String { 89 | lines.map({ line -> String in 90 | var row = "" 91 | for _ in 0.. String { 115 | var snippet: String = "" 116 | snippet += "\(name)(" 117 | for (i, entity) in entities.enumerated() { 118 | if i > 0 { 119 | snippet += ", " 120 | } 121 | snippet += entity.snippet() 122 | } 123 | snippet += ")" 124 | return snippet 125 | } 126 | } 127 | 128 | extension String { 129 | 130 | public subscript (bounds: CountableClosedRange) -> String { 131 | let start = index(startIndex, offsetBy: bounds.lowerBound) 132 | let end = index(startIndex, offsetBy: bounds.upperBound) 133 | return String(self[start...end]) 134 | } 135 | 136 | public subscript (bounds: CountableRange) -> String { 137 | let start = index(startIndex, offsetBy: bounds.lowerBound) 138 | let end = index(startIndex, offsetBy: bounds.upperBound) 139 | return String(self[start..: TernaryIf 24 | infix operator <=>: TernaryElse 25 | 26 | extension Bool: SMRawType { 27 | public static let typeName: String = "bool" 28 | } 29 | 30 | public class SMBool: SMValue, ExpressibleByBooleanLiteral { 31 | 32 | static let kType: String = "bool" 33 | public typealias T = Bool 34 | 35 | override var rawUniforms: [SMRawType]? { value != nil ? [value!] : nil } 36 | 37 | public init(_ value: T) { 38 | super.init(value, type: SMBool.kType) 39 | snippet = { self.value != nil ? (self.value! ? "true" : "false") : "#" } 40 | } 41 | 42 | public init(_ futureValue: @escaping () -> (T)) { 43 | super.init(futureValue, type: SMBool.kType) 44 | } 45 | 46 | required public convenience init(booleanLiteral value: Bool) { 47 | self.init(value) 48 | } 49 | 50 | init(operation: SMOperation, snippet: @escaping () -> (String)) { 51 | super.init(operation: operation, snippet: snippet, type: SMBool.kType) 52 | } 53 | 54 | init(fromEntities: [SMEntity]) { 55 | super.init(type: SMBool.kType, fromEntities: fromEntities) 56 | } 57 | 58 | public static func == (lhs: SMBool, rhs: SMBool) -> SMBool { 59 | SMBool(operation: SMOperation(lhs: lhs, rhs: rhs), snippet: { "(\(lhs.snippet()) == \(rhs.snippet()))" }) 60 | } 61 | public static func != (lhs: SMBool, rhs: SMBool) -> SMBool { 62 | SMBool(operation: SMOperation(lhs: lhs, rhs: rhs), snippet: { "(\(lhs.snippet()) != \(rhs.snippet()))" }) 63 | } 64 | public static func && (lhs: SMBool, rhs: SMBool) -> SMBool { 65 | SMBool(operation: SMOperation(lhs: lhs, rhs: rhs), snippet: { "(\(lhs.snippet()) && \(rhs.snippet()))" }) 66 | } 67 | public static func || (lhs: SMBool, rhs: SMBool) -> SMBool { 68 | SMBool(operation: SMOperation(lhs: lhs, rhs: rhs), snippet: { "(\(lhs.snippet()) || \(rhs.snippet()))" }) 69 | } 70 | 71 | public static func (lhs: SMBool, rhs: (SMVector, SMVector)) -> SMVector { 72 | let float = SMVector(fromEntities: [lhs, rhs.0, rhs.1]) 73 | float.snippet = { "(\(lhs.snippet()) ? \(rhs.0.snippet()) : \(rhs.1.snippet()))" } 74 | return float 75 | } 76 | // public static func (lhs: SMBool, rhs: (SMFloat, SMFloat)) -> SMFloat { 77 | // let float = SMFloat(fromEntities: [lhs, rhs.0, rhs.1]) 78 | // float.snippet = { "(\(lhs.snippet()) ? \(rhs.0.snippet()) : \(rhs.1.snippet()))" } 79 | // return float 80 | // } 81 | // public static func (lhs: SMBool, rhs: (SMFloat2, SMFloat2)) -> SMFloat2 { 82 | // let float2 = SMFloat2(fromEntities: [lhs, rhs.0, rhs.1]) 83 | // float2.snippet = { "(\(lhs.snippet()) ? \(rhs.0.snippet()) : \(rhs.1.snippet()))" } 84 | // return float2 85 | // } 86 | // public static func (lhs: SMBool, rhs: (SMFloat3, SMFloat3)) -> SMFloat3 { 87 | // let float3 = SMFloat3(fromEntities: [lhs, rhs.0, rhs.1]) 88 | // float3.snippet = { "(\(lhs.snippet()) ? \(rhs.0.snippet()) : \(rhs.1.snippet()))" } 89 | // return float3 90 | // } 91 | // public static func (lhs: SMBool, rhs: (SMFloat4, SMFloat4)) -> SMFloat4 { 92 | // let float4 = SMFloat4(fromEntities: [lhs, rhs.0, rhs.1]) 93 | // float4.snippet = { "(\(lhs.snippet()) ? \(rhs.0.snippet()) : \(rhs.1.snippet()))" } 94 | // return float4 95 | // } 96 | 97 | public prefix static func ! (operand: SMBool) -> SMBool { 98 | let float = SMBool(fromEntities: [operand]) 99 | float.snippet = { "!\(operand.snippet())" } 100 | return float 101 | } 102 | 103 | } 104 | 105 | public class SMLiveBool: SMBool { 106 | var valueSink: AnyCancellable! 107 | public init(_ publisher: Published.Publisher) { 108 | var value: Bool! 109 | super.init { value } 110 | valueSink = publisher.sink { newValue in 111 | value = newValue 112 | self.sink?() 113 | } 114 | hasSink = true 115 | } 116 | public init(_ binding: Binding) { 117 | _ = CurrentValueSubject(binding.wrappedValue) 118 | // TODO: - Route values: 119 | // Currently the CurrentValueSubject triggers the SMView to update, 120 | // then the future values is read. 121 | super.init { binding.wrappedValue } 122 | } 123 | deinit { 124 | valueSink.cancel() 125 | } 126 | required public convenience init(booleanLiteral value: Bool) { 127 | fatalError("init(booleanLiteral:) has not been implemented") 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /Sources/SMShader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SMShader.swift 3 | // SwiftMetal 4 | // 5 | // Created by Anton Heestand on 2019-12-06. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Metal 11 | 12 | public class SMShader: Identifiable, Equatable { 13 | 14 | public let id = UUID() 15 | 16 | enum FuncError: Error { 17 | case shader 18 | case someUniformsAreNil 19 | } 20 | 21 | let textures: [SMTexture] 22 | 23 | let baseEntity: SMEntity 24 | 25 | var sinks: [() -> ()] = [] 26 | 27 | let smCode: SMCode 28 | public var code: String! 29 | 30 | var render: (() -> ())? 31 | 32 | public init(_ entityCallback: (SMUV) -> (SMFloat4)) { 33 | baseEntity = entityCallback(SMUV()) 34 | textures = SMBuilder.textures(for: baseEntity) 35 | smCode = SMBuilder.build(for: baseEntity) 36 | SMBuilder.connectSinks(for: baseEntity) { 37 | // print("SwiftMetal - Shader - Update") 38 | self.render?() 39 | } 40 | code = makeCode() 41 | print("SwiftMetal - Shader >>> >>> >>>", id.uuidString) 42 | print(code!) 43 | print("SwiftMetal - Shader <<< <<< <<<", id.uuidString) 44 | } 45 | 46 | fileprivate func makeCode() -> String { 47 | 48 | let code = smCode 49 | 50 | var lines: [Line] = [] 51 | 52 | lines.append(Line("//")) 53 | lines.append(Line("// SwiftMetal")) 54 | lines.append(Line("// Auto generated metal code")) 55 | lines.append(Line("//")) 56 | lines.append(Line()) 57 | 58 | lines.append(Line("#include ")) 59 | lines.append(Line("using namespace metal;")) 60 | lines.append(Line()) 61 | 62 | if !code.functions.isEmpty { 63 | for function in code.functions { 64 | lines.append(Line(function.code)) 65 | } 66 | } 67 | 68 | if !code.uniforms.isEmpty { 69 | lines.append(Line("struct Uniforms {")) 70 | for uniform in code.uniforms { 71 | lines.append(Line(in: 1, uniform.code)) 72 | } 73 | lines.append(Line("};")) 74 | lines.append(Line()) 75 | } 76 | 77 | lines.append(Line("kernel void swiftMetal(")) 78 | if !code.uniforms.isEmpty { 79 | lines.append(Line(in: 2, "constant Uniforms& us [[ buffer(0) ]],")) 80 | } 81 | lines.append(Line(in: 2, "texture2d tex [[ texture(0) ]],")) 82 | for (i, texture) in textures.enumerated() { 83 | // lines.append(Line(in: 2, "texture2d \(texture.name) [[ texture(\(i + 1)) ]],")) 84 | lines.append(Line(in: 2, "texture2d \(texture.name) [[ texture(\(i + 1)) ]],")) 85 | } 86 | lines.append(Line(in: 2, "uint2 pos [[ thread_position_in_grid ]],")) 87 | lines.append(Line(in: 2, "sampler smp [[ sampler(0) ]]")) 88 | lines.append(Line(in: 0, ") {")) 89 | lines.append(Line(in: 1)) 90 | 91 | lines.append(Line(in: 1, "int x = pos.x;")) 92 | lines.append(Line(in: 1, "int y = pos.y;")) 93 | lines.append(Line(in: 1, "int w = tex.get_width();")) 94 | lines.append(Line(in: 1, "int h = tex.get_height();")) 95 | lines.append(Line(in: 1)) 96 | 97 | lines.append(Line(in: 1, "if (x >= w || y >= h) { return; }")) 98 | lines.append(Line(in: 1)) 99 | 100 | lines.append(Line(in: 1, "float u = (float(x) + 0.5) / float(w);")) 101 | lines.append(Line(in: 1, "float v = (float(y) + 0.5) / float(h);")) 102 | lines.append(Line(in: 1, "float2 uv = float2(u, v);")) 103 | lines.append(Line(in: 1)) 104 | 105 | if !textures.isEmpty { 106 | for texture in textures { 107 | // lines.append(Line(in: 1, "float4 \(texture.snippet()) = \(texture.name).read(pos);")) 108 | lines.append(Line(in: 1, "float4 \(texture.snippet()) = \(texture.name).sample(smp, uv);")) 109 | } 110 | lines.append(Line(in: 1)) 111 | } 112 | 113 | if !code.variables.isEmpty { 114 | code.variables.forEach { variable in 115 | lines.append(Line(in: 1, variable.code)) 116 | } 117 | lines.append(Line(in: 1)) 118 | } 119 | 120 | lines.append(Line(in: 1, "\(baseEntity.type) out = \(code.snippet);")) 121 | lines.append(Line(in: 1)) 122 | 123 | lines.append(Line(in: 1, "tex.write(out, pos);")) 124 | lines.append(Line(in: 1)) 125 | 126 | lines.append(Line("}")) 127 | 128 | return Line.merge(lines) 129 | } 130 | 131 | public func make(with metalDevice: MTLDevice) throws -> MTLFunction { 132 | let lib: MTLLibrary = try metalDevice.makeLibrary(source: code, options: nil) 133 | guard let shader: MTLFunction = lib.makeFunction(name: "swiftMetal") else { 134 | throw FuncError.shader 135 | } 136 | return shader 137 | } 138 | 139 | func rawUniforms() throws -> [SMRawType] { 140 | var rawUniforms: [SMRawType] = [] 141 | for uniform in smCode.uniforms { 142 | guard let rawSubUniforms = uniform.entity.rawUniforms else { 143 | throw FuncError.someUniformsAreNil 144 | } 145 | for subUniform in rawSubUniforms { 146 | rawUniforms.append(subUniform) 147 | } 148 | } 149 | return rawUniforms 150 | } 151 | 152 | public static func == (lhs: SMShader, rhs: SMShader) -> Bool { 153 | lhs.id == rhs.id 154 | } 155 | 156 | } 157 | -------------------------------------------------------------------------------- /Sources/SMView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SMView.swift 3 | // SwiftMetal 4 | // 5 | // Created by Anton Heestand on 2019-12-10. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | import MetalKit 10 | #if os(macOS) 11 | import Cocoa 12 | #else 13 | import UIKit 14 | #endif 15 | import SwiftUI 16 | 17 | #if os(macOS) 18 | #else 19 | public struct SMView: UIViewRepresentable { 20 | let shader: () -> (SMShader) 21 | public init(_ shader: @escaping () -> (SMShader)) { 22 | self.shader = shader 23 | } 24 | public func makeUIView(context: Self.Context) -> SMUIView { 25 | let shader = self.shader() 26 | return SMUIView(shader: shader) 27 | } 28 | public func updateUIView(_ view: SMUIView, context: Self.Context) { 29 | #if os(macOS) 30 | view.setNeedsDisplay(view.frame) 31 | #else 32 | view.setNeedsDisplay() 33 | #endif 34 | } 35 | } 36 | //struct SMSubReView: UIViewRepresentable { 37 | // let view: () -> (Content) 38 | // let update: () -> () 39 | // init(view: @escaping () -> (Content), update: @escaping () -> ()) { 40 | // self.view = view 41 | // self.update = update 42 | // } 43 | // func makeUIView(context: Self.Context) -> UIView { 44 | // UIHostingController(rootView: view()).view! 45 | // } 46 | // func updateUIView(_ view: UIView, context: Self.Context) { 47 | // update() 48 | // } 49 | //} 50 | //public struct SMReView: UIViewRepresentable { 51 | // let shader: (SMTexture) -> (SMShader) 52 | // let view: () -> (Content) 53 | // public init(_ shader: @escaping (SMTexture) -> (SMShader), _ view: @escaping () -> (Content)) { 54 | // self.shader = shader 55 | // self.view = view 56 | // } 57 | // public func makeUIView(context: Self.Context) -> UIView { 58 | // 59 | // var texture: SMTexture! 60 | // let subReView = SMSubReView(view: view, update: { 61 | // print("Update......") 62 | // texture.update() 63 | // }) 64 | // let subView = UIHostingController(rootView: subReView).view! 65 | // texture = SMTexture(futureImage: { 66 | // guard subView.bounds.width > 0 else { 67 | // print("View Frame is Zero") 68 | // return nil 69 | // } 70 | // UIGraphicsBeginImageContextWithOptions(subView.bounds.size, false, 0) 71 | // subView.drawHierarchy(in: subView.bounds, afterScreenUpdates: true) 72 | // guard let image: UIImage = UIGraphicsGetImageFromCurrentImageContext() else { 73 | // print("View to Image Failed") 74 | // return nil 75 | // } 76 | // UIGraphicsEndImageContext() 77 | // return image 78 | // }) 79 | //// texture.update() 80 | // 81 | // let shader = self.shader(texture) 82 | // 83 | // let baseView = UIView() 84 | // 85 | // let smUiView = SMUIView(shader: shader) 86 | // baseView.addSubview(smUiView) 87 | // smUiView.translatesAutoresizingMaskIntoConstraints = false 88 | // smUiView.centerXAnchor.constraint(equalTo: baseView.centerXAnchor).isActive = true 89 | // smUiView.centerYAnchor.constraint(equalTo: baseView.centerYAnchor).isActive = true 90 | // smUiView.widthAnchor.constraint(equalTo: baseView.widthAnchor).isActive = true 91 | // smUiView.heightAnchor.constraint(equalTo: baseView.heightAnchor).isActive = true 92 | // 93 | // baseView.addSubview(subView) 94 | // subView.alpha = 0.1 95 | // subView.translatesAutoresizingMaskIntoConstraints = false 96 | // subView.centerXAnchor.constraint(equalTo: baseView.centerXAnchor).isActive = true 97 | // subView.centerYAnchor.constraint(equalTo: baseView.centerYAnchor).isActive = true 98 | // subView.widthAnchor.constraint(equalTo: baseView.widthAnchor).isActive = true 99 | // subView.heightAnchor.constraint(equalTo: baseView.heightAnchor).isActive = true 100 | // 101 | // return baseView 102 | // } 103 | // public func updateUIView(_ view: UIView, context: Self.Context) { 104 | // #if os(macOS) 105 | // view.subviews[0].setNeedsDisplay(view.frame) 106 | // #else 107 | // view.subviews[0].setNeedsDisplay() 108 | // #endif 109 | // } 110 | //} 111 | #endif 112 | 113 | // MTKViewDelegate... 114 | 115 | public class SMUIView: MTKView { 116 | 117 | var res: CGSize? 118 | 119 | var renderCallback: (() -> ())? 120 | 121 | let shader: SMShader 122 | 123 | public init(shader: SMShader) { 124 | 125 | self.shader = shader 126 | 127 | super.init(frame: .zero, device: SMRenderer.metalDevice) 128 | 129 | // colorPixelFormat = SMRenderer.defaultPixelFormat 130 | #if os(macOS) 131 | layer!.isOpaque = false 132 | #else 133 | isOpaque = false 134 | #endif 135 | framebufferOnly = false 136 | autoResizeDrawable = false 137 | enableSetNeedsDisplay = true 138 | // isPaused = true 139 | 140 | do { 141 | try SMRenderer.renderView(shader, in: self) 142 | } catch { 143 | fatalError("SwiftMetal - SMUIView - Render Setup Error: \(String(describing: error))") 144 | } 145 | 146 | } 147 | 148 | required init(coder: NSCoder) { 149 | fatalError("init(coder:) has not been implemented") 150 | } 151 | 152 | override public func draw(_ rect: CGRect) { 153 | super.draw(rect) 154 | // autoreleasepool { 155 | #if os(macOS) 156 | let scale: CGFloat = 1.0 157 | #else 158 | let scale: CGFloat = UIScreen.main.scale 159 | #endif 160 | res = CGSize(width: rect.size.width * scale, 161 | height: rect.size.height * scale) 162 | guard res!.width > 0 && res!.height > 0 else { return } 163 | renderCallback?() 164 | // } 165 | } 166 | 167 | #if !os(macOS) 168 | public override func layoutIfNeeded() { 169 | super.layoutIfNeeded() 170 | print("layoutIfNeeded") 171 | } 172 | #endif 173 | 174 | } 175 | -------------------------------------------------------------------------------- /Sources/Types/SMFloat.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SMFloat.swift 3 | // SwiftMetal 4 | // 5 | // Created by Hexagons on 2019-12-08. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Combine 11 | import SwiftUI 12 | import simd 13 | 14 | 15 | extension Float: SMRawType { 16 | public static let typeName: String = "float" 17 | } 18 | 19 | 20 | public class SMFloat: SMValue, ExpressibleByFloatLiteral, ExpressibleByIntegerLiteral { 21 | 22 | static let kType: String = "float" 23 | public typealias RT = Float 24 | 25 | override var rawUniforms: [SMRawType]? { value != nil ? [value!] : nil } 26 | 27 | init(entity: SMEntity, at index: Int) { 28 | super.init(type: SMFloat.kType) 29 | subscriptEntity = entity 30 | snippet = { "\(entity.snippet())[\(index)]" } 31 | } 32 | 33 | public init(_ value: RT) { 34 | super.init(value, type: SMFloat.kType) 35 | snippet = { self.value != nil ? String(describing: self.value!) : "#" } 36 | } 37 | 38 | public init(_ futureValue: @escaping () -> (RT)) { 39 | super.init(futureValue, type: SMFloat.kType) 40 | } 41 | 42 | required public convenience init(floatLiteral value: Float) { 43 | self.init(value) 44 | } 45 | required public convenience init(integerLiteral value: Int) { 46 | self.init(Float(value)) 47 | } 48 | 49 | init(operation: SMOperation, snippet: @escaping () -> (String)) { 50 | super.init(operation: operation, snippet: snippet, type: SMFloat.kType) 51 | } 52 | 53 | init(fromEntities: [SMEntity]) { 54 | super.init(type: SMFloat.kType, fromEntities: fromEntities) 55 | } 56 | 57 | public static func + (lhs: SMFloat, rhs: SMFloat) -> SMFloat { 58 | SMFloat(operation: SMOperation(lhs: lhs, rhs: rhs), snippet: { "(\(lhs.snippet()) + \(rhs.snippet()))" }) 59 | } 60 | public static func - (lhs: SMFloat, rhs: SMFloat) -> SMFloat { 61 | SMFloat(operation: SMOperation(lhs: lhs, rhs: rhs), snippet: { "(\(lhs.snippet()) - \(rhs.snippet()))" }) 62 | } 63 | public static func * (lhs: SMFloat, rhs: SMFloat) -> SMFloat { 64 | SMFloat(operation: SMOperation(lhs: lhs, rhs: rhs), snippet: { "(\(lhs.snippet()) * \(rhs.snippet()))" }) 65 | } 66 | public static func / (lhs: SMFloat, rhs: SMFloat) -> SMFloat { 67 | SMFloat(operation: SMOperation(lhs: lhs, rhs: rhs), snippet: { "(\(lhs.snippet()) / \(rhs.snippet()))" }) 68 | } 69 | 70 | public static func < (lhs: SMFloat, rhs: SMFloat) -> SMBool { 71 | SMBool(operation: SMOperation(lhs: lhs, rhs: rhs), snippet: { "(\(lhs.snippet()) < \(rhs.snippet()))" }) 72 | } 73 | public static func > (lhs: SMFloat, rhs: SMFloat) -> SMBool { 74 | SMBool(operation: SMOperation(lhs: lhs, rhs: rhs), snippet: { "(\(lhs.snippet()) > \(rhs.snippet()))" }) 75 | } 76 | public static func == (lhs: SMFloat, rhs: SMFloat) -> SMBool { 77 | SMBool(operation: SMOperation(lhs: lhs, rhs: rhs), snippet: { "(\(lhs.snippet()) == \(rhs.snippet()))" }) 78 | } 79 | public static func != (lhs: SMFloat, rhs: SMFloat) -> SMBool { 80 | SMBool(operation: SMOperation(lhs: lhs, rhs: rhs), snippet: { "(\(lhs.snippet()) != \(rhs.snippet()))" }) 81 | } 82 | 83 | public static func <=> (lhs: SMFloat, rhs: SMFloat) -> (SMFloat, SMFloat) { 84 | return (lhs, rhs) 85 | } 86 | 87 | public prefix static func - (operand: SMFloat) -> SMFloat { 88 | let float = SMFloat(fromEntities: [operand]) 89 | float.snippet = { "-\(operand.snippet())" } 90 | return float 91 | } 92 | 93 | } 94 | 95 | public class SMLiveFloat: SMFloat { 96 | var valueSink: AnyCancellable! 97 | public init(_ publisher: Published.Publisher) { 98 | var value: Float! 99 | super.init { value } 100 | valueSink = publisher.sink { newValue in 101 | value = newValue 102 | self.sink?() 103 | } 104 | hasSink = true 105 | } 106 | public init(_ binding: Binding) { 107 | _ = CurrentValueSubject(binding.wrappedValue) 108 | // TODO: - Route values: 109 | // Currently the CurrentValueSubject triggers the SMView to update, 110 | // then the future values is read. 111 | super.init { binding.wrappedValue } 112 | } 113 | deinit { 114 | valueSink.cancel() 115 | } 116 | required public convenience init(floatLiteral value: Float) { 117 | fatalError("init(floatLiteral:) has not been implemented") 118 | } 119 | required public convenience init(integerLiteral value: Int) { 120 | fatalError("init(integerLiteral:) has not been implemented") 121 | } 122 | } 123 | 124 | public typealias SMFloat2 = SMVector 125 | public typealias SMFloat3 = SMVector 126 | public typealias SMFloat4 = SMVector 127 | 128 | //extension SMFloat2: ExpressibleByFloatLiteral, ExpressibleByIntegerLiteral { 129 | // convenience public init(floatLiteral value: Float) { 130 | // self.init(SMFloat(value)) 131 | // } 132 | // convenience public init(integerLiteral value: Int) { 133 | // self.init(SMFloat(Float(value))) 134 | // } 135 | //} 136 | 137 | 138 | public func float(_ value: Float) -> SMFloat { 139 | SMFloat(value) 140 | } 141 | 142 | public func float2(_ value0: SMFloat, _ value1: SMFloat) -> SMFloat2 { 143 | SMFloat2([value0, value1]) 144 | } 145 | public func float2(_ value: SMFloat) -> SMFloat2 { 146 | SMFloat2(value) 147 | } 148 | 149 | public func float3(_ value0: SMFloat, _ value1: SMFloat, _ value2: SMFloat) -> SMFloat3 { 150 | SMFloat3([value0, value1, value2]) 151 | } 152 | public func float3(_ value: SMFloat) -> SMFloat3 { 153 | SMFloat3(value) 154 | } 155 | 156 | public func float4(_ value0: SMFloat, _ value1: SMFloat, _ value2: SMFloat, _ value3: SMFloat) -> SMFloat4 { 157 | SMFloat4([value0, value1, value2, value3]) 158 | } 159 | public func float4(_ value: SMFloat) -> SMFloat4 { 160 | SMFloat4(value) 161 | } 162 | 163 | 164 | public func sqrt(_ value: SMFloat) -> SMFloat { 165 | let float = SMFloat(fromEntities: [value]) 166 | float.snippet = { "sqrt(\(value.snippet()))" } 167 | return float 168 | } 169 | 170 | public func pow(_ value0: SMFloat, _ value1: SMFloat) -> SMFloat { 171 | let float = SMFloat(fromEntities: [value0, value1]) 172 | float.snippet = { "pow(\(value0.snippet()), \(value1.snippet()))" } 173 | return float 174 | } 175 | -------------------------------------------------------------------------------- /Sources/Types/SMVector.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SMVector.swift 3 | // SwiftMetal_iOS 4 | // 5 | // Created by Anton Heestand on 2019-12-13. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol SMVec { 12 | static var size: Int { get } 13 | } 14 | public struct SMVec2: SMVec { 15 | public static let size: Int = 2 16 | } 17 | public struct SMVec3: SMVec { 18 | public static let size: Int = 3 19 | } 20 | public struct SMVec4: SMVec { 21 | public static let size: Int = 4 22 | } 23 | 24 | public class SMVector: SMValue> { 25 | 26 | var constructor: String { 27 | "\(RT.typeName)\(VEC.size)" 28 | } 29 | 30 | public var x: SMFloat { self[0] } 31 | public var y: SMFloat { self[1] } 32 | public var z: SMFloat { self[2] } 33 | public var w: SMFloat { self[3] } 34 | public var r: SMFloat { self[0] } 35 | public var g: SMFloat { self[1] } 36 | public var b: SMFloat { self[2] } 37 | public var a: SMFloat { self[3] } 38 | 39 | 40 | override var rawUniforms: [SMRawType]? { 41 | guard let tuple: SMTuple = value else { return nil } 42 | var values: [SMRawType] = [] 43 | for value in tuple.values { 44 | guard let rawValue = value.value else { return nil } 45 | values.append(rawValue) 46 | } 47 | return values 48 | } 49 | 50 | public subscript(index: Int) -> SMFloat { 51 | guard (0..) { 59 | super.init(SMTuple([SMValue].init(repeating: value, count: VEC.size)), 60 | type: "\(RT.typeName)\(VEC.size)", fromEntities: [value]) 61 | snippet = { "\(self.constructor)(\(value.snippet()))" } 62 | } 63 | public init(_ values: [SMValue]) { 64 | guard values.count == VEC.size else { 65 | fatalError("SMVector of size \(VEC.size) can not be constructed with \(values.count) values.") 66 | } 67 | super.init(SMTuple(values), type: "\(RT.typeName)\(values.count)", fromEntities: values) 68 | snippet = { Snippet.functionSnippet(name: self.constructor, from: values) } 69 | } 70 | init(_ tuple: SMTuple) { 71 | super.init(tuple, type: "\(RT.typeName)\(tuple.count)", fromEntities: tuple.values) 72 | snippet = { Snippet.functionSnippet(name: self.constructor, from: tuple.values) } 73 | } 74 | public init(_ futureValue: @escaping () -> (SMTuple)) { 75 | super.init(futureValue, type: "\(RT.typeName)\(VEC.size)") 76 | } 77 | init(operation: SMOperation, snippet: @escaping () -> (String)) { 78 | super.init(operation: operation, snippet: snippet, type: "\(RT.typeName)\(VEC.size)") 79 | } 80 | init(fromEntities: [SMEntity] = []) { 81 | super.init(type: "\(RT.typeName)\(VEC.size)", fromEntities: fromEntities) 82 | } 83 | 84 | 85 | public static func + (lhs: SMVector, rhs: SMVector) -> SMVector { 86 | SMVector(operation: SMOperation(lhs: lhs, rhs: rhs), snippet: { "(\(lhs.snippet()) - \(rhs.snippet()))" }) 87 | } 88 | public static func + (lhs: SMVector, rhs: SMValue) -> SMVector { 89 | let vector = SMVector(rhs) 90 | return SMVector(operation: SMOperation(lhs: lhs, rhs: vector), snippet: { "(\(lhs.snippet()) - \(vector.snippet()))" }) 91 | } 92 | public static func + (lhs: SMValue, rhs: SMVector) -> SMVector { 93 | let vector = SMVector(lhs) 94 | return SMVector(operation: SMOperation(lhs: vector, rhs: rhs), snippet: { "(\(vector.snippet()) - \(rhs.snippet()))" }) 95 | } 96 | // public static func + (lhs: SMVector, rhs: RT) -> SMVector { 97 | // let vector = SMVector(SMValue(rhs)) 98 | // return SMVector(operation: SMOperation(lhs: lhs, rhs: vector), snippet: { "(\(lhs.snippet()) - \(vector.snippet()))" }) 99 | // } 100 | // public static func + (lhs: RT, rhs: SMVector) -> SMVector { 101 | // let vector = SMVector(SMValue(lhs)) 102 | // return SMVector(operation: SMOperation(lhs: vector, rhs: rhs), snippet: { "(\(vector.snippet()) - \(rhs.snippet()))" }) 103 | // } 104 | 105 | public static func - (lhs: SMVector, rhs: SMVector) -> SMVector { 106 | SMVector(operation: SMOperation(lhs: lhs, rhs: rhs), snippet: { "(\(lhs.snippet()) - \(rhs.snippet()))" }) 107 | } 108 | public static func - (lhs: SMVector, rhs: SMValue) -> SMVector { 109 | let vector = SMVector(rhs) 110 | return SMVector(operation: SMOperation(lhs: lhs, rhs: vector), snippet: { "(\(lhs.snippet()) - \(vector.snippet()))" }) 111 | } 112 | public static func - (lhs: SMValue, rhs: SMVector) -> SMVector { 113 | let vector = SMVector(lhs) 114 | return SMVector(operation: SMOperation(lhs: vector, rhs: rhs), snippet: { "(\(vector.snippet()) - \(rhs.snippet()))" }) 115 | } 116 | // public static func - (lhs: SMVector, rhs: RT) -> SMVector { 117 | // let vector = SMVector(SMValue(rhs)) 118 | // return SMVector(operation: SMOperation(lhs: lhs, rhs: vector), snippet: { "(\(lhs.snippet()) - \(vector.snippet()))" }) 119 | // } 120 | // public static func - (lhs: RT, rhs: SMVector) -> SMVector { 121 | // let vector = SMVector(SMValue(lhs)) 122 | // return SMVector(operation: SMOperation(lhs: vector, rhs: rhs), snippet: { "(\(vector.snippet()) - \(rhs.snippet()))" }) 123 | // } 124 | 125 | public static func * (lhs: SMVector, rhs: SMVector) -> SMVector { 126 | SMVector(operation: SMOperation(lhs: lhs, rhs: rhs), snippet: { "(\(lhs.snippet()) * \(rhs.snippet()))" }) 127 | } 128 | public static func * (lhs: SMVector, rhs: SMValue) -> SMVector { 129 | let vector = SMVector(rhs) 130 | return SMVector(operation: SMOperation(lhs: lhs, rhs: vector), snippet: { "(\(lhs.snippet()) * \(vector.snippet()))" }) 131 | } 132 | public static func * (lhs: SMValue, rhs: SMVector) -> SMVector { 133 | let vector = SMVector(lhs) 134 | return SMVector(operation: SMOperation(lhs: vector, rhs: rhs), snippet: { "(\(vector.snippet()) * \(rhs.snippet()))" }) 135 | } 136 | // public static func * (lhs: SMVector, rhs: RT) -> SMVector { 137 | // let vector = SMVector(SMValue(rhs)) 138 | // return SMVector(operation: SMOperation(lhs: lhs, rhs: vector), snippet: { "(\(lhs.snippet()) * \(vector.snippet()))" }) 139 | // } 140 | // public static func * (lhs: RT, rhs: SMVector) -> SMVector { 141 | // let vector = SMVector(SMValue(lhs)) 142 | // return SMVector(operation: SMOperation(lhs: vector, rhs: rhs), snippet: { "(\(vector.snippet()) * \(rhs.snippet()))" }) 143 | // } 144 | 145 | public static func / (lhs: SMVector, rhs: SMVector) -> SMVector { 146 | SMVector(operation: SMOperation(lhs: lhs, rhs: rhs), snippet: { "(\(lhs.snippet()) / \(rhs.snippet()))" }) 147 | } 148 | public static func / (lhs: SMVector, rhs: SMValue) -> SMVector { 149 | let vector = SMVector(rhs) 150 | return SMVector(operation: SMOperation(lhs: lhs, rhs: vector), snippet: { "(\(lhs.snippet()) / \(vector.snippet()))" }) 151 | } 152 | public static func / (lhs: SMValue, rhs: SMVector) -> SMVector { 153 | let vector = SMVector(lhs) 154 | return SMVector(operation: SMOperation(lhs: vector, rhs: rhs), snippet: { "(\(vector.snippet()) / \(rhs.snippet()))" }) 155 | } 156 | // public static func / (lhs: SMVector, rhs: RT) -> SMVector { 157 | // let vector = SMVector(SMValue(rhs)) 158 | // return SMVector(operation: SMOperation(lhs: lhs, rhs: vector), snippet: { "(\(lhs.snippet()) / \(vector.snippet()))" }) 159 | // } 160 | // public static func / (lhs: RT, rhs: SMVector) -> SMVector { 161 | // let vector = SMVector(SMValue(lhs)) 162 | // return SMVector(operation: SMOperation(lhs: vector, rhs: rhs), snippet: { "(\(vector.snippet()) / \(rhs.snippet()))" }) 163 | // } 164 | 165 | 166 | public static func <=> (lhs: SMVector, rhs: SMVector) -> (SMVector, SMVector) { 167 | return (lhs, rhs) 168 | } 169 | public static func <=> (lhs: SMVector, rhs: SMValue) -> (SMVector, SMVector) { 170 | return (lhs, SMVector(rhs)) 171 | } 172 | public static func <=> (lhs: SMValue, rhs: SMVector) -> (SMVector, SMVector) { 173 | return (SMVector(lhs), rhs) 174 | } 175 | // public static func <=> (lhs: SMVector, rhs: RT) -> (SMVector, SMVector) { 176 | // return (lhs, SMVector(SMValue(rhs))) 177 | // } 178 | // public static func <=> (lhs: RT, rhs: SMVector) -> (SMVector, SMVector) { 179 | // return (SMVector(SMValue(lhs)), rhs) 180 | // } 181 | 182 | 183 | public prefix static func - (operand: SMVector) -> SMVector { 184 | let tuple = SMVector(fromEntities: [operand]) 185 | tuple.snippet = { "-\(operand.snippet())" } 186 | return tuple 187 | } 188 | 189 | } 190 | 191 | public func min(_ values: SMVector...) -> SMVector { 192 | let float = SMVector(fromEntities: values) 193 | float.snippet = { Snippet.functionSnippet(name: "min", from: values) } 194 | return float 195 | } 196 | 197 | public func max(_ values: SMVector...) -> SMVector { 198 | let float = SMVector(fromEntities: values) 199 | float.snippet = { Snippet.functionSnippet(name: "max", from: values) } 200 | return float 201 | } 202 | 203 | public func fmod(_ value0: SMVector, _ value1: SMVector) -> SMVector { 204 | let float = SMVector(fromEntities: [value0, value1]) 205 | float.snippet = { "fmod(\(value0.snippet()), \(value1.snippet()))" } 206 | return float 207 | } 208 | 209 | public func abs(_ value: SMVector) -> SMVector { 210 | let float = SMVector(fromEntities: [value]) 211 | float.snippet = { "abs(\(value.snippet()))" } 212 | return float 213 | } 214 | -------------------------------------------------------------------------------- /Sources/SMBuilder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SMBuilder.swift 3 | // SwiftMetal 4 | // 5 | // Created by Anton Heestand on 2019-12-06. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct SMBuilder { 12 | 13 | class Branch: Equatable { 14 | var hitCount: Int = 0 15 | let entity: SMEntity 16 | var variable: SMVariablePack? 17 | var branches: [Branch] = [] 18 | init(entity: SMEntity) { 19 | self.entity = entity 20 | branches = entity.children.map { child in 21 | Branch(entity: child) 22 | } 23 | } 24 | func scanLeafs(_ index: Int = 0) -> Branch? { 25 | guard hitCount < index + 1 else { return nil } 26 | for branch in branches { 27 | if let hitEntity = branch.scanLeafs(index) { 28 | return hitEntity 29 | } 30 | } 31 | hitCount += 1 32 | return self 33 | } 34 | func leafEntity(_ index: Int = 0) -> SMEntity? { 35 | guard hitCount < index + 1 else { return nil } 36 | for branch in branches { 37 | if let hitEntity = branch.leafEntity(index) { 38 | return hitEntity 39 | } 40 | } 41 | hitCount += 1 42 | return entity 43 | } 44 | func funcBranches() -> [Branch] { 45 | var funcBranches: [Branch] = [] 46 | if let branch = funcRootBranch() { 47 | funcBranches.append(branch) 48 | return funcBranches 49 | } 50 | for branch in self.branches { 51 | let subBranches = branch.funcBranches() 52 | funcBranches.append(contentsOf: subBranches) 53 | } 54 | return funcBranches 55 | } 56 | func funcRootBranch() -> Branch? { 57 | guard entity.isReturn else { return nil } 58 | return funcLeafBranch() 59 | } 60 | func funcLeafBranch() -> Branch? { 61 | let root = Branch(entity: entity) 62 | guard !entity.isArg else { return root } 63 | var leafs: [Branch] = [] 64 | for branch in self.branches { 65 | if let leaf = branch.funcLeafBranch() { 66 | leafs.append(leaf) 67 | } 68 | } 69 | root.branches = leafs 70 | return root 71 | } 72 | func leafs() -> [Branch] { 73 | guard !isLeaf() else { 74 | return [self] 75 | } 76 | var leafs: [Branch] = [] 77 | for branch in self.branches { 78 | if branch.isLeaf() { 79 | leafs.append(branch) 80 | } else { 81 | let subLeafs = branch.leafs() 82 | leafs.append(contentsOf: subLeafs) 83 | } 84 | } 85 | return leafs 86 | } 87 | func isLeaf() -> Bool { 88 | branches.isEmpty 89 | } 90 | func argLeafs() -> [Branch] { 91 | guard !isArgLeaf() else { 92 | return [self] 93 | } 94 | var leafs: [Branch] = [] 95 | for branch in self.branches { 96 | if branch.isArgLeaf() { 97 | leafs.append(branch) 98 | } else { 99 | let subLeafs = branch.argLeafs() 100 | leafs.append(contentsOf: subLeafs) 101 | } 102 | } 103 | return leafs 104 | } 105 | func isArgLeaf() -> Bool { 106 | entity.isArg 107 | } 108 | static func sameSignature(lhs: Branch, rhs: Branch) -> Bool { 109 | guard lhs.entity.isReturn && rhs.entity.isReturn else { return false } 110 | guard lhs.entity.returnId! == rhs.entity.returnId! else { return false } 111 | // TODO: - The ID is all we need... 112 | // guard lhs.entity.type == rhs.entity.type else { return false } 113 | // let lhsLeafs = lhs.leafs().filter({ $0.entity.isArg }) 114 | // let rhsLeafs = rhs.leafs().filter({ $0.entity.isArg }) 115 | // guard lhsLeafs.count == rhsLeafs.count else { return false } 116 | // guard zip(lhs.leafs(), rhs.leafs()).filter({ arg -> Bool in 117 | // let (lhsLeaf, rhsLeaf) = arg 118 | // return lhsLeaf.entity.type == rhsLeaf.entity.type 119 | // }).count == lhsLeafs.count else { return false } 120 | return true 121 | } 122 | static func == (lhs: Branch, rhs: Branch) -> Bool { 123 | lhs.entity == rhs.entity 124 | } 125 | } 126 | 127 | static func connectSinks(for baseEntity: SMEntity, sinked: @escaping () -> ()) { 128 | 129 | let tree: Branch = Branch(entity: baseEntity) 130 | 131 | while let leafEntity = tree.leafEntity() { 132 | if leafEntity.hasSink { 133 | leafEntity.sink = { 134 | sinked() 135 | } 136 | } 137 | } 138 | 139 | } 140 | 141 | static func textures(for baseEntity: SMEntity) -> [SMTexture] { 142 | 143 | var textures: [SMTexture] = [] 144 | 145 | let tree: Branch = Branch(entity: baseEntity) 146 | 147 | while let leafEntity = tree.leafEntity() { 148 | if let texture = leafEntity as? SMTexture { 149 | if !textures.contains(texture) { 150 | textures.append(texture) 151 | } 152 | } 153 | } 154 | 155 | for (i, texture) in textures.enumerated() { 156 | texture.index = i 157 | } 158 | 159 | return textures 160 | 161 | } 162 | 163 | static func build(for baseEntity: SMEntity) -> SMCode { 164 | 165 | let tree: Branch = Branch(entity: baseEntity) 166 | 167 | // Uniforms 168 | 169 | var uniforms: [SMUniformPack] = [] 170 | while let leafEntity = tree.leafEntity(0) { 171 | if leafEntity.isFuture && !(leafEntity is SMTexture) { 172 | if !uniforms.contains(where: { $0.entity == leafEntity }) { 173 | leafEntity.futureIndex = uniforms.count 174 | let uniform = SMUniformPack(entity: leafEntity, index: uniforms.count) 175 | uniforms.append(uniform) 176 | } 177 | } 178 | } 179 | 180 | var lastSnippet: String = baseEntity.snippet() 181 | 182 | /// Functions 183 | 184 | var functions: [SMFunction] = [] 185 | let funcBranchs: [Branch] = tree.funcBranches() 186 | var uniqueFuncBranchs: [Branch] = [] 187 | for funcBranch in funcBranchs { 188 | var exists = false 189 | for uniqueFuncBranch in uniqueFuncBranchs { 190 | if Branch.sameSignature(lhs: funcBranch, rhs: uniqueFuncBranch) { 191 | exists = true 192 | break 193 | } 194 | } 195 | if !exists { 196 | uniqueFuncBranchs.append(funcBranch) 197 | } 198 | } 199 | for uniqueFuncBranch in uniqueFuncBranchs { 200 | // let leafs = uniqueFuncBranch.leafs() 201 | // let argLeafs = leafs.filter({ $0.entity.isArg }) 202 | let argLeafs = uniqueFuncBranch.argLeafs() 203 | let argEntities = argLeafs.map({ $0.entity }) 204 | let returnEntity = uniqueFuncBranch.entity 205 | let function = SMFunction(argEntities: argEntities, returnEntity: returnEntity, index: functions.count) 206 | functions.append(function) 207 | } 208 | for funcBranch in funcBranchs { 209 | var function: SMFunction! 210 | for (i, uniqueFuncBranch) in uniqueFuncBranchs.enumerated() { 211 | if Branch.sameSignature(lhs: funcBranch, rhs: uniqueFuncBranch) { 212 | function = functions[i] 213 | break 214 | } 215 | } 216 | // let leafs = funcBranch.leafs() 217 | // let argLeafs = leafs.filter({ $0.entity.isArg }) 218 | let argLeafs = funcBranch.argLeafs() 219 | let argEntities = argLeafs.map({ $0.entity }) 220 | let returnEntity = funcBranch.entity 221 | lastSnippet = lastSnippet.replacingOccurrences(of: returnEntity.snippet(), with: function.snippet(with: argEntities)) 222 | } 223 | 224 | // Variables 225 | 226 | var variableBranchCopies: [Branch] = [] 227 | var variables: [SMVariablePack] = [] 228 | while let leaf = tree.scanLeafs(1) { 229 | if variableBranchCopies.contains(leaf) { 230 | if !variables.contains(where: { variable -> Bool in 231 | variable.entity == leaf.entity 232 | }) { 233 | let index = variables.count 234 | let variable = SMVariablePack(for: leaf.entity, at: index, with: { 235 | var snippet: String = leaf.entity.snippet() 236 | for subVariable in variables { 237 | guard subVariable.entity != leaf.entity else { continue } 238 | snippet = snippet.replacingOccurrences(of: subVariable.entity.snippet(), with: subVariable.name) 239 | } 240 | return snippet 241 | }()) 242 | leaf.variable = variable 243 | variables.append(variable) 244 | lastSnippet = lastSnippet.replacingOccurrences(of: leaf.entity.snippet(), with: variable.name) 245 | } 246 | } else { 247 | variableBranchCopies.append(leaf) 248 | } 249 | } 250 | while let leaf = tree.scanLeafs(2) { 251 | if let variable = leaf.variable { 252 | guard !variable.snippet.starts(with: "v") else { continue } 253 | lastSnippet = lastSnippet.replacingOccurrences(of: variable.snippet, with: variable.name) 254 | } 255 | } 256 | /// Clean 257 | // TODO - Fix case where v10 is mistaken for v1, as we get unused variables in metal code. 258 | let count = variables.count 259 | for i in 0.. SMTexture { 52 | let function: MTLFunction = try shader.make(with: SMRenderer.metalDevice) 53 | let textures: [MTLTexture] = shader.textures.compactMap({ $0.texture }) 54 | guard textures.count == shader.textures.count else { 55 | throw RenderError.someTextureIsNil 56 | } 57 | let rawUniforms: [SMRawType] = try shader.rawUniforms() 58 | guard let drawableTexture: MTLTexture = texture ?? SMTexture.emptyTexture(at: size, as: pixelFormat) else { 59 | throw RenderError.emptyTextureFailed 60 | } 61 | return try render(function: function, 62 | size: size, 63 | rawUniforms: rawUniforms, 64 | drawableTexture: drawableTexture, 65 | textures: textures, 66 | pixelFormat: pixelFormat) 67 | } 68 | 69 | public static func renderLive(_ shader: SMShader, at size: CGSize, as pixelFormat: MTLPixelFormat = defaultPixelFormat, rendered: @escaping (SMTexture) -> (), failed: @escaping (Error) -> ()) throws { 70 | let function: MTLFunction = try shader.make(with: SMRenderer.metalDevice) 71 | let preTextures: [MTLTexture?] = shader.textures.map({ !$0.isFuture ? $0.texture! : nil }) 72 | guard let drawableTexture: MTLTexture = SMTexture.emptyTexture(at: size, as: pixelFormat) else { 73 | throw RenderError.emptyTextureFailed 74 | } 75 | var rendering: Bool = false 76 | shader.render = { 77 | guard !rendering else { 78 | failed(RenderError.renderInProgress) 79 | return 80 | } 81 | rendering = true 82 | do { 83 | let rawUniforms: [SMRawType] = try shader.rawUniforms() 84 | let postTextures: [MTLTexture?] = shader.textures.map({ $0.isFuture ? $0.texture : nil }) 85 | let textures: [MTLTexture] = zip(preTextures, postTextures).compactMap { textureAB -> MTLTexture? in 86 | textureAB.0 ?? textureAB.1 87 | } 88 | guard textures.count == shader.textures.count else { 89 | failed(RenderError.someTextureIsNil) 90 | return 91 | } 92 | DispatchQueue.global(qos: .background).async { 93 | do { 94 | let texture = try self.render(function: function, 95 | size: size, rawUniforms: rawUniforms, 96 | drawableTexture: drawableTexture, 97 | textures: textures, 98 | pixelFormat: pixelFormat) 99 | rendering = false 100 | DispatchQueue.main.async { 101 | rendered(texture) 102 | } 103 | } catch { 104 | rendering = false 105 | DispatchQueue.main.async { 106 | failed(error) 107 | } 108 | } 109 | } 110 | } catch { 111 | rendering = false 112 | DispatchQueue.main.async { 113 | failed(error) 114 | } 115 | } 116 | } 117 | shader.render!() 118 | } 119 | 120 | public static func renderView(_ shader: SMShader, in view: SMUIView) throws { 121 | print("SwiftMetal - Render View") 122 | let function: MTLFunction = try shader.make(with: SMRenderer.metalDevice) 123 | let preTextures: [MTLTexture?] = shader.textures.map({ !$0.isFuture ? $0.texture! : nil }) 124 | var rendering: Bool = false 125 | shader.render = { 126 | guard let size = view.res else { 127 | print("SwiftMetal - Render View - No Res.") 128 | return 129 | } 130 | guard let drawable: CAMetalDrawable = view.currentDrawable else { 131 | print("SwiftMetal - Render View - No Drawable Texture.") 132 | return 133 | } 134 | guard !rendering else { 135 | print("SwiftMetal - Render View - Render In Progress...") 136 | return 137 | } 138 | rendering = true 139 | print("SwiftMetal - Render View - Render...") 140 | do { 141 | let rawUniforms: [SMRawType] = try shader.rawUniforms() 142 | let postTextures: [MTLTexture?] = shader.textures.map({ $0.isFuture ? $0.texture : nil }) 143 | let textures: [MTLTexture] = zip(preTextures, postTextures).compactMap { textureAB -> MTLTexture? in 144 | textureAB.0 ?? textureAB.1 145 | } 146 | guard textures.count == shader.textures.count else { 147 | print("SwiftMetal - Render View - Render Error:", RenderError.someTextureIsNil) 148 | rendering = false 149 | return 150 | } 151 | DispatchQueue.global(qos: .background).async { 152 | do { 153 | _ = try self.render(function: function, 154 | size: size, rawUniforms: rawUniforms, 155 | drawableTexture: drawable.texture, 156 | drawable: drawable, 157 | textures: textures, 158 | pixelFormat: view.colorPixelFormat) 159 | print("SwiftMetal - Render View - Rendered!") 160 | } catch { 161 | print("SwiftMetal - Render View - Render Error:", error) 162 | } 163 | rendering = false 164 | } 165 | } catch { 166 | print("SwiftMetal - Render View - Render Setup Error:", error) 167 | rendering = false 168 | } 169 | } 170 | view.renderCallback = { 171 | shader.render!() 172 | } 173 | // shader.render!() 174 | } 175 | 176 | static func render(function: MTLFunction, size: CGSize, rawUniforms: [SMRawType], drawableTexture: MTLTexture, drawable: CAMetalDrawable? = nil, textures: [MTLTexture], pixelFormat: MTLPixelFormat) throws -> SMTexture { 177 | 178 | guard let commandBuffer: MTLCommandBuffer = commandQueue.makeCommandBuffer() else { 179 | throw RenderError.commandBuffer 180 | } 181 | 182 | let commandEncoder: MTLComputeCommandEncoder! = commandBuffer.makeComputeCommandEncoder() 183 | guard commandEncoder != nil else { 184 | throw RenderError.commandEncoder 185 | } 186 | 187 | let pipelineState: MTLComputePipelineState = try SMRenderer.metalDevice.makeComputePipelineState(function: function) 188 | commandEncoder.setComputePipelineState(pipelineState) 189 | 190 | // FIXME: - Vector's are currently flat mapped... 191 | var rawUniforms: [SMRawType] = rawUniforms 192 | if !rawUniforms.isEmpty { 193 | var size: Int = 0 194 | for rawUniform in rawUniforms { 195 | if rawUniform is Float { 196 | size += MemoryLayout.size 197 | } else if rawUniform is Bool { 198 | size += MemoryLayout.size 199 | } 200 | } 201 | guard let uniformBuffer = SMRenderer.metalDevice.makeBuffer(length: size, options: []) else { 202 | commandEncoder.endEncoding() 203 | // commandEncoder = nil 204 | throw RenderError.uniformBuffer 205 | } 206 | let bufferPointer = uniformBuffer.contents() 207 | memcpy(bufferPointer, &rawUniforms, size) 208 | commandEncoder.setBuffer(uniformBuffer, offset: 0, index: 0) 209 | } 210 | 211 | let samplerDescriptor = MTLSamplerDescriptor() 212 | samplerDescriptor.minFilter = .linear 213 | samplerDescriptor.magFilter = .linear 214 | samplerDescriptor.mipFilter = .linear 215 | samplerDescriptor.sAddressMode = .clampToZero 216 | samplerDescriptor.tAddressMode = .clampToZero 217 | samplerDescriptor.compareFunction = .never 218 | guard let sampler: MTLSamplerState = SMRenderer.metalDevice.makeSamplerState(descriptor: samplerDescriptor) else { 219 | throw RenderError.sampler 220 | } 221 | commandEncoder.setSamplerState(sampler, index: 0) 222 | 223 | commandEncoder.setTexture(drawableTexture, index: 0) 224 | for (i, texture) in textures.enumerated() { 225 | commandEncoder.setTexture(texture, index: i + 1) 226 | } 227 | 228 | #if !os(tvOS) 229 | let tw = Int(size.width) 230 | let th = Int(size.height) 231 | let threadsPerGrid = MTLSize(width: tw, height: th, depth: 1) 232 | let threadsPerThreadgroup = MTLSize(width: 8, height: 8, depth: 1) 233 | // let w: Int = pipelineState.threadExecutionWidth 234 | // let h: Int = pipelineState.maxTotalThreadsPerThreadgroup / w 235 | //// let w2: Int = (tw + w - 1) / w 236 | //// let h2: Int = (th + h - 1) / h 237 | // let threadsPerThreadgroup: MTLSize = MTLSizeMake(w, h, 1) 238 | commandEncoder.dispatchThreads(threadsPerGrid, threadsPerThreadgroup: threadsPerThreadgroup) 239 | #endif 240 | 241 | commandEncoder.endEncoding() 242 | 243 | if drawable != nil { 244 | commandBuffer.present(drawable!) 245 | } 246 | // commandBuffer.addCompletedHandler { _ in } 247 | commandBuffer.commit() 248 | commandBuffer.waitUntilCompleted() 249 | 250 | // commandEncoder = nil 251 | 252 | return SMTexture(texture: drawableTexture) 253 | } 254 | 255 | } 256 | -------------------------------------------------------------------------------- /Sources/Types/SMTexture.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SMTexture.swift 3 | // SwiftMetal 4 | // 5 | // Created by Anton Heestand on 2019-12-06. 6 | // Copyright © 2019 Hexagons. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | #if os(macOS) 11 | import Cocoa 12 | #else 13 | import UIKit 14 | #endif 15 | import MetalKit 16 | import Combine 17 | import SwiftUI 18 | 19 | public class SMTexture: SMFloat4 { 20 | 21 | var futureTexture: (() -> (MTLTexture?))? 22 | var _texture: MTLTexture? 23 | public var texture: MTLTexture? { _texture ?? futureTexture?() } 24 | 25 | var index: Int? 26 | var name: String { 27 | "tex\(index ?? -1)" 28 | } 29 | 30 | var size: CGSize { 31 | CGSize(width: texture?.width ?? -1, height: texture?.height ?? -1) 32 | } 33 | 34 | enum TextureError: Error { 35 | case noTexture 36 | case badPixelFormat(target: [MTLPixelFormat]) 37 | case imageFailed(String) 38 | case copyTextureFailed(String) 39 | } 40 | 41 | public convenience init?(image: _Image) { 42 | guard let texture = SMTexture.convertFrom(image: image) else { return nil } 43 | self.init(texture: texture) 44 | } 45 | 46 | public convenience init(futureImage: @escaping () -> (_Image?)) { 47 | self.init(futureTexture: { 48 | guard let image: _Image = futureImage() else { return nil } 49 | guard let texture = SMTexture.convertFrom(image: image) else { 50 | fatalError("Future Image to MTLTexture conversion failed.") 51 | } 52 | return texture 53 | }) 54 | } 55 | 56 | public convenience init?(pixelBuffer: CVPixelBuffer) { 57 | guard let texture: MTLTexture = SMTexture.convertFrom(pixelBuffer: pixelBuffer) else { return nil } 58 | self.init(texture: texture) 59 | } 60 | 61 | public convenience init(futurePixelBuffer: @escaping () -> (CVPixelBuffer?)) { 62 | self.init(futureTexture: { 63 | guard let pixelBuffer: CVPixelBuffer = futurePixelBuffer() else { return nil } 64 | guard let texture: MTLTexture = SMTexture.convertFrom(pixelBuffer: pixelBuffer) else { 65 | fatalError("Future Pixel Buffer to MTLTexture conversion failed.") 66 | } 67 | return texture 68 | }) 69 | } 70 | 71 | public init(texture: MTLTexture) { 72 | self._texture = texture 73 | super.init() 74 | self.snippet = { "t\(self.index ?? -1)" } 75 | } 76 | 77 | public init(futureTexture: @escaping () -> (MTLTexture?)) { 78 | self.futureTexture = futureTexture 79 | super.init({ SMTuple([SMFloat(-1.0), SMFloat(-1.0), SMFloat(-1.0), SMFloat(-1.0)]) }) 80 | hasSink = true 81 | self.snippet = { "t\(self.index ?? -1)" } 82 | } 83 | 84 | required public convenience init(floatLiteral value: Float) { 85 | fatalError("init(floatLiteral:) has not been implemented") 86 | } 87 | required public convenience init(integerLiteral value: Int) { 88 | fatalError("init(integerLiteral:) has not been implemented") 89 | } 90 | 91 | public func update() { 92 | sink?() 93 | } 94 | 95 | public func sample(at uv: SMFloat2) -> SMFloat4 { 96 | SMFloat4(sample: self, at: uv) 97 | } 98 | 99 | // public func sample(rel offest: SMFloat2) -> SMFloat4 { 100 | // SMFloat4(sample: self, at: SMUV() + offest) 101 | // } 102 | // 103 | // public func sample() -> SMFloat4 { 104 | // SMFloat4(sample: self, at: SMUV()) 105 | // } 106 | 107 | // MARK: - Export 108 | 109 | public func image() throws -> _Image { 110 | guard let texture: MTLTexture = texture else { 111 | throw TextureError.noTexture 112 | } 113 | let colorSpace = CGColorSpace(name: CGColorSpace.sRGB)! 114 | guard let ciImage = CIImage(mtlTexture: texture, options: [.colorSpace: colorSpace]) else { 115 | throw TextureError.imageFailed("CIImage") 116 | } 117 | let ciFormat: CIFormat 118 | switch texture.pixelFormat { 119 | case .rgba8Unorm: ciFormat = .RGBA8 120 | case .rgba16Float: ciFormat = .RGBA16 121 | case .rgba32Float: ciFormat = .RGBAf 122 | default: 123 | throw TextureError.badPixelFormat(target: [.rgba8Unorm, .rgba16Float, .rgba32Float]) 124 | } 125 | guard let cgImage = CIContext(options: nil).createCGImage(ciImage, from: ciImage.extent, format: ciFormat, colorSpace: colorSpace) else { 126 | throw TextureError.imageFailed("CGImage") 127 | } 128 | #if os(macOS) 129 | return NSImage(cgImage: cgImage, size: CGSize(width: texture.width, height: texture.height)) 130 | #else 131 | return UIImage(cgImage: cgImage) 132 | #endif 133 | } 134 | 135 | func raw(fill: T) -> [T] { 136 | guard let texture: MTLTexture = texture else { return [] } 137 | let region = MTLRegionMake2D(0, 0, texture.width, texture.height) 138 | var raw = Array(repeating: fill, count: texture.width * texture.height * 4) 139 | raw.withUnsafeMutableBytes { 140 | let bytesPerRow: Int = MemoryLayout.size * texture.width * 4 141 | texture.getBytes($0.baseAddress!, bytesPerRow: bytesPerRow, from: region, mipmapLevel: 0) 142 | } 143 | return raw 144 | } 145 | 146 | public func raw8() throws -> [UInt8] { 147 | guard let texture: MTLTexture = texture else { return [] } 148 | guard texture.pixelFormat == .rgba8Unorm else { 149 | throw TextureError.badPixelFormat(target: [.rgba8Unorm]) 150 | } 151 | return raw(fill: 0) 152 | } 153 | 154 | public func raw16() throws -> [Float] { 155 | guard let texture: MTLTexture = texture else { return [] } 156 | guard texture.pixelFormat == .rgba16Float else { 157 | throw TextureError.badPixelFormat(target: [.rgba16Float]) 158 | } 159 | var raw16: [Float16] = raw(fill: 0) 160 | return float16to32(&raw16, count: raw16.count) 161 | } 162 | 163 | public func raw32() throws -> [Float] { 164 | guard let texture: MTLTexture = texture else { return [] } 165 | guard texture.pixelFormat == .rgba32Float else { 166 | throw TextureError.badPixelFormat(target: [.rgba32Float]) 167 | } 168 | return raw(fill: 0.0) 169 | } 170 | 171 | public func values() throws -> [[[Float]]] { 172 | guard let texture: MTLTexture = texture else { return [] } 173 | let rawFloats: [Float] 174 | switch texture.pixelFormat { 175 | case .rgba8Unorm: 176 | let raw = try raw8() 177 | rawFloats = raw.map({ Float($0) / 255 }) 178 | case .rgba16Float: 179 | rawFloats = try raw16() 180 | case .rgba32Float: 181 | rawFloats = try raw32() 182 | default: 183 | throw TextureError.badPixelFormat(target: [.rgba8Unorm, .rgba16Float, .rgba32Float]) 184 | } 185 | var pixels: [[[Float]]] = [] 186 | var row: [[Float]]! 187 | var pixel: [Float]! 188 | for (i, rawFloat) in rawFloats.enumerated() { 189 | if i % (texture.width * 4) == 0 { 190 | row = [] 191 | } 192 | if i % 4 == 0 { 193 | pixel = [] 194 | } 195 | pixel.append(rawFloat) 196 | if i % 4 == 3 { 197 | row.append(pixel) 198 | } 199 | if i % (texture.width * 4) == (texture.width * 4) - 1 { 200 | pixels.append(row) 201 | } 202 | } 203 | return pixels 204 | } 205 | 206 | public func pixels() throws -> [[(r: Float, g: Float, b: Float, a: Float)]] { 207 | try values().map({ $0.map({ (r: $0[0], 208 | g: $0[1], 209 | b: $0[2], 210 | a: $0[3]) }) }) 211 | } 212 | 213 | public func colors() throws -> [[_Color]] { 214 | try values().map({ $0.map({ color in 215 | #if os(macOS) 216 | return NSColor(deviceRed: CGFloat(color[0]), 217 | green: CGFloat(color[1]), 218 | blue: CGFloat(color[2]), 219 | alpha: CGFloat(color[3])) 220 | #else 221 | return UIColor(red: CGFloat(color[0]), 222 | green: CGFloat(color[1]), 223 | blue: CGFloat(color[2]), 224 | alpha: CGFloat(color[3])) 225 | #endif 226 | }) }) 227 | } 228 | 229 | public func copyTexture() throws -> MTLTexture { 230 | guard let texture: MTLTexture = texture else { 231 | throw TextureError.noTexture 232 | } 233 | guard let textureCopy = SMTexture.emptyTexture(at: size, as: texture.pixelFormat) else { 234 | throw TextureError.copyTextureFailed("Empty Texture Failed") 235 | } 236 | guard let commandBuffer = SMRenderer.commandQueue.makeCommandBuffer() else { 237 | throw TextureError.copyTextureFailed("Make Command Buffer Failed") 238 | } 239 | guard let blitEncoder = commandBuffer.makeBlitCommandEncoder() else { 240 | throw TextureError.copyTextureFailed("Make Blit Command Encoder Failed") 241 | } 242 | blitEncoder.copy(from: texture, sourceSlice: 0, sourceLevel: 0, sourceOrigin: MTLOrigin(x: 0, y: 0, z: 0), sourceSize: MTLSize(width: texture.width, height: texture.height, depth: 1), to: textureCopy, destinationSlice: 0, destinationLevel: 0, destinationOrigin: MTLOrigin(x: 0, y: 0, z: 0)) 243 | blitEncoder.endEncoding() 244 | commandBuffer.commit() 245 | return textureCopy 246 | } 247 | 248 | // MARK: - Formats 249 | 250 | static func convertFrom(pixelBuffer: CVPixelBuffer) -> MTLTexture? { 251 | let width = CVPixelBufferGetWidth(pixelBuffer) 252 | let height = CVPixelBufferGetHeight(pixelBuffer) 253 | var imageTexture: CVMetalTexture? 254 | let result = CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, SMRenderer.textureCache, pixelBuffer, nil, .bgra8Unorm, width, height, 0, &imageTexture) 255 | guard let unwrappedImageTexture = imageTexture, 256 | let texture = CVMetalTextureGetTexture(unwrappedImageTexture), 257 | result == kCVReturnSuccess else { 258 | return nil 259 | } 260 | return texture 261 | } 262 | 263 | static func convertFrom(image: _Image) -> MTLTexture? { 264 | #if os(macOS) 265 | guard let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil) else { return nil } 266 | #else 267 | guard let cgImage = image.cgImage else { return nil } 268 | #endif 269 | let textureLoader = MTKTextureLoader(device: SMRenderer.metalDevice) 270 | guard let texture: MTLTexture = try? textureLoader.newTexture(cgImage: cgImage, options: [ 271 | .origin: MTKTextureLoader.Origin.topLeft as NSObject 272 | ]) else { return nil } 273 | return texture 274 | } 275 | 276 | public static func emptyTexture(at size: CGSize, as pixelFormat: MTLPixelFormat) -> MTLTexture? { 277 | guard size.width > 0 && size.height > 0 else { return nil } 278 | let descriptor = MTLTextureDescriptor.texture2DDescriptor(pixelFormat: pixelFormat, width: Int(size.width), height: Int(size.height), mipmapped: true) 279 | descriptor.usage = MTLTextureUsage(rawValue: MTLTextureUsage.shaderWrite.rawValue | MTLTextureUsage.shaderRead.rawValue) 280 | guard let texture = SMRenderer.metalDevice.makeTexture(descriptor: descriptor) else { return nil } 281 | return texture 282 | } 283 | 284 | } 285 | 286 | public class SMLiveTexture: SMTexture { 287 | var valueSink: AnyCancellable! 288 | public init(_ publisher: Published<_Image?>.Publisher) { 289 | var value: MTLTexture? 290 | super.init { value } 291 | valueSink = publisher.sink { newValue in 292 | guard newValue != nil else { 293 | value = nil 294 | self.sink?() 295 | return 296 | } 297 | guard let texture = SMTexture.convertFrom(image: newValue!) else { 298 | fatalError("Live Texture with Image to MTLTexture conversion failed.") 299 | } 300 | value = texture 301 | self.sink?() 302 | } 303 | hasSink = true 304 | } 305 | public init(_ publisher: Published.Publisher) { 306 | var value: MTLTexture? 307 | super.init { value } 308 | valueSink = publisher.sink { newValue in 309 | guard newValue != nil else { 310 | value = nil 311 | self.sink?() 312 | return 313 | } 314 | guard let texture: MTLTexture = SMTexture.convertFrom(pixelBuffer: newValue!) else { 315 | fatalError("Live Texture with Pixel Buffer to MTLTexture conversion failed.") 316 | } 317 | value = texture 318 | self.sink?() 319 | } 320 | hasSink = true 321 | } 322 | public init(_ publisher: Published.Publisher) { 323 | var value: MTLTexture? 324 | super.init { value } 325 | valueSink = publisher.sink { newValue in 326 | value = newValue 327 | self.sink?() 328 | } 329 | hasSink = true 330 | } 331 | public init(_ binding: Binding<_Image?>) { 332 | _ = CurrentValueSubject<_Image?, Never>(binding.wrappedValue) 333 | // TODO: - Route values: 334 | // Currently the CurrentValueSubject triggers the SMView to update, 335 | // then the future values is read. 336 | super.init(futureTexture: { 337 | guard binding.wrappedValue != nil else { return nil } 338 | guard let texture = SMTexture.convertFrom(image: binding.wrappedValue!) else { 339 | fatalError("Live Texture with Image to MTLTexture conversion failed.") 340 | } 341 | return texture 342 | }) 343 | } 344 | public init(_ binding: Binding) { 345 | _ = CurrentValueSubject(binding.wrappedValue) 346 | // TODO: - Route values: 347 | // Currently the CurrentValueSubject triggers the SMView to update, 348 | // then the future values is read. 349 | super.init(futureTexture: { 350 | guard binding.wrappedValue != nil else { return nil } 351 | guard let texture: MTLTexture = SMTexture.convertFrom(pixelBuffer: binding.wrappedValue!) else { 352 | fatalError("Live Texture with Pixel Buffer to MTLTexture conversion failed.") 353 | } 354 | return texture 355 | }) 356 | } 357 | public init(_ binding: Binding) { 358 | _ = CurrentValueSubject(binding.wrappedValue) 359 | // TODO: - Route values: 360 | // Currently the CurrentValueSubject triggers the SMView to update, 361 | // then the future values is read. 362 | super.init { binding.wrappedValue } 363 | } 364 | deinit { 365 | valueSink.cancel() 366 | } 367 | required public convenience init(floatLiteral value: Float) { 368 | fatalError("init(floatLiteral:) has not been implemented") 369 | } 370 | required public convenience init(integerLiteral value: Int) { 371 | fatalError("init(integerLiteral:) has not been implemented") 372 | } 373 | } 374 | 375 | extension SMFloat4 { 376 | 377 | convenience init(sample texture: SMTexture, at uv: SMFloat2) { 378 | self.init() 379 | sampleTexture = texture 380 | sampleUV = uv 381 | self.snippet = { 382 | "\(texture.name).sample(smp, \(uv.snippet()))" 383 | } 384 | } 385 | 386 | } 387 | -------------------------------------------------------------------------------- /SwiftMetal.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 3A15240A239F9D3D003E6333 /* Template.metal in Sources */ = {isa = PBXBuildFile; fileRef = 3A670694239A9D9600E23C87 /* Template.metal */; }; 11 | 3A15240B239F9D3D003E6333 /* Template.metal in Sources */ = {isa = PBXBuildFile; fileRef = 3A670694239A9D9600E23C87 /* Template.metal */; }; 12 | 3A159FDC23A28DE700D202FD /* Photos.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A159FDA23A28DE300D202FD /* Photos.swift */; }; 13 | 3A159FDF23A2921000D202FD /* Camera.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A159FDD23A291D000D202FD /* Camera.swift */; }; 14 | 3A1A9D67239F9E500030EE35 /* SMView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A1A9D66239F9E500030EE35 /* SMView.swift */; }; 15 | 3A1A9D68239F9E5E0030EE35 /* SMView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A1A9D66239F9E500030EE35 /* SMView.swift */; }; 16 | 3A1A9D69239F9E5E0030EE35 /* SMView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A1A9D66239F9E500030EE35 /* SMView.swift */; }; 17 | 3A478A05239E556B009AE4D4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A478A04239E556B009AE4D4 /* AppDelegate.swift */; }; 18 | 3A478A07239E556B009AE4D4 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A478A06239E556B009AE4D4 /* SceneDelegate.swift */; }; 19 | 3A478A09239E556B009AE4D4 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A478A08239E556B009AE4D4 /* ContentView.swift */; }; 20 | 3A478A0B239E556D009AE4D4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3A478A0A239E556D009AE4D4 /* Assets.xcassets */; }; 21 | 3A478A0E239E556D009AE4D4 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3A478A0D239E556D009AE4D4 /* Preview Assets.xcassets */; }; 22 | 3A478A11239E556D009AE4D4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3A478A0F239E556D009AE4D4 /* LaunchScreen.storyboard */; }; 23 | 3A478A17239E557F009AE4D4 /* SwiftMetal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A99C5F7239A4B20005BE419 /* SwiftMetal.framework */; }; 24 | 3A478A18239E557F009AE4D4 /* SwiftMetal.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3A99C5F7239A4B20005BE419 /* SwiftMetal.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 25 | 3A478A1C239E55A8009AE4D4 /* TestMedia.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 74512F24239BE34D008F5FCE /* TestMedia.xcassets */; }; 26 | 3A670681239A61BB00E23C87 /* SMEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A670680239A61BB00E23C87 /* SMEntity.swift */; }; 27 | 3A670689239A666300E23C87 /* SMTexture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A670688239A666300E23C87 /* SMTexture.swift */; }; 28 | 3A67068B239A687E00E23C87 /* SMBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A67068A239A687E00E23C87 /* SMBuilder.swift */; }; 29 | 3A67068D239A6CCB00E23C87 /* SMCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A67068C239A6CCB00E23C87 /* SMCode.swift */; }; 30 | 3A670691239A93D400E23C87 /* SMRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A670690239A93D400E23C87 /* SMRenderer.swift */; }; 31 | 3A670695239A9D9600E23C87 /* Template.metal in Sources */ = {isa = PBXBuildFile; fileRef = 3A670694239A9D9600E23C87 /* Template.metal */; }; 32 | 3A7344E023A25014003BEF66 /* SMBool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A7344DF23A25014003BEF66 /* SMBool.swift */; }; 33 | 3A7344E123A25014003BEF66 /* SMBool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A7344DF23A25014003BEF66 /* SMBool.swift */; }; 34 | 3A7344E223A25014003BEF66 /* SMBool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A7344DF23A25014003BEF66 /* SMBool.swift */; }; 35 | 3A7344E523A27778003BEF66 /* Logo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A7344E423A27778003BEF66 /* Logo.swift */; }; 36 | 3A99C601239A4B20005BE419 /* SwiftMetal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A99C5F7239A4B20005BE419 /* SwiftMetal.framework */; }; 37 | 3A99C606239A4B20005BE419 /* SwiftMetalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A99C605239A4B20005BE419 /* SwiftMetalTests.swift */; }; 38 | 3A99C608239A4B20005BE419 /* SwiftMetal.h in Headers */ = {isa = PBXBuildFile; fileRef = 3A99C5FA239A4B20005BE419 /* SwiftMetal.h */; settings = {ATTRIBUTES = (Public, ); }; }; 39 | 3A99C613239A4B61005BE419 /* SMShader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A99C612239A4B61005BE419 /* SMShader.swift */; }; 40 | 3A99C616239A4B8E005BE419 /* SMValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A99C615239A4B8E005BE419 /* SMValue.swift */; }; 41 | 3AB01E2623A38DAE003738D1 /* Main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AB01E2523A38DAE003738D1 /* Main.swift */; }; 42 | 3AB01E2A23A3CF32003738D1 /* SMVector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AB01E2923A3CF32003738D1 /* SMVector.swift */; }; 43 | 7422A264239D31F0003FEA65 /* SMFloat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7422A263239D31F0003FEA65 /* SMFloat.swift */; }; 44 | 7422A268239D3438003FEA65 /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7422A267239D3438003FEA65 /* Types.swift */; }; 45 | 744F60B2239EDCF200C51A63 /* Float16.swift in Sources */ = {isa = PBXBuildFile; fileRef = 744F60B1239EDCF200C51A63 /* Float16.swift */; }; 46 | 744F60BC239EE2A200C51A63 /* SwiftMetal_macOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 744F60BA239EE2A200C51A63 /* SwiftMetal_macOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; 47 | 744F60C9239EE2D100C51A63 /* SwiftMetal_tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 744F60C7239EE2D100C51A63 /* SwiftMetal_tvOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; 48 | 744F60DA239EE2FA00C51A63 /* Template.metal in Sources */ = {isa = PBXBuildFile; fileRef = 3A670694239A9D9600E23C87 /* Template.metal */; }; 49 | 744F60DB239EE2FA00C51A63 /* Template.metal in Sources */ = {isa = PBXBuildFile; fileRef = 3A670694239A9D9600E23C87 /* Template.metal */; }; 50 | 744F60DD239EE30000C51A63 /* SMRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A670690239A93D400E23C87 /* SMRenderer.swift */; }; 51 | 744F60DE239EE30000C51A63 /* SMShader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A99C612239A4B61005BE419 /* SMShader.swift */; }; 52 | 744F60DF239EE30000C51A63 /* SMCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A67068C239A6CCB00E23C87 /* SMCode.swift */; }; 53 | 744F60E0239EE30000C51A63 /* SMBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A67068A239A687E00E23C87 /* SMBuilder.swift */; }; 54 | 744F60E1239EE30000C51A63 /* SMFunction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74E5B8FC239C547E00492280 /* SMFunction.swift */; }; 55 | 744F60E2239EE30000C51A63 /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7422A267239D3438003FEA65 /* Types.swift */; }; 56 | 744F60E3239EE30100C51A63 /* SMRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A670690239A93D400E23C87 /* SMRenderer.swift */; }; 57 | 744F60E4239EE30100C51A63 /* SMShader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A99C612239A4B61005BE419 /* SMShader.swift */; }; 58 | 744F60E5239EE30100C51A63 /* SMCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A67068C239A6CCB00E23C87 /* SMCode.swift */; }; 59 | 744F60E6239EE30100C51A63 /* SMBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A67068A239A687E00E23C87 /* SMBuilder.swift */; }; 60 | 744F60E7239EE30100C51A63 /* SMFunction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74E5B8FC239C547E00492280 /* SMFunction.swift */; }; 61 | 744F60E8239EE30100C51A63 /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7422A267239D3438003FEA65 /* Types.swift */; }; 62 | 744F60EF239EE30400C51A63 /* SMEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A670680239A61BB00E23C87 /* SMEntity.swift */; }; 63 | 744F60F0239EE30400C51A63 /* SMValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A99C615239A4B8E005BE419 /* SMValue.swift */; }; 64 | 744F60F1239EE30400C51A63 /* SMFloat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7422A263239D31F0003FEA65 /* SMFloat.swift */; }; 65 | 744F60F2239EE30400C51A63 /* SMTexture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A670688239A666300E23C87 /* SMTexture.swift */; }; 66 | 744F60F3239EE30500C51A63 /* SMEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A670680239A61BB00E23C87 /* SMEntity.swift */; }; 67 | 744F60F4239EE30500C51A63 /* SMValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A99C615239A4B8E005BE419 /* SMValue.swift */; }; 68 | 744F60F5239EE30500C51A63 /* SMFloat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7422A263239D31F0003FEA65 /* SMFloat.swift */; }; 69 | 744F60F6239EE30500C51A63 /* SMTexture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A670688239A666300E23C87 /* SMTexture.swift */; }; 70 | 744F60FB239EE30700C51A63 /* Float16.swift in Sources */ = {isa = PBXBuildFile; fileRef = 744F60B1239EDCF200C51A63 /* Float16.swift */; }; 71 | 744F60FC239EE30800C51A63 /* Float16.swift in Sources */ = {isa = PBXBuildFile; fileRef = 744F60B1239EDCF200C51A63 /* Float16.swift */; }; 72 | 744F60FF239EEB0300C51A63 /* TestMedia.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 74512F24239BE34D008F5FCE /* TestMedia.xcassets */; }; 73 | 744F6100239EEB0300C51A63 /* TestMedia.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 74512F24239BE34D008F5FCE /* TestMedia.xcassets */; }; 74 | 744F6108239EEC4E00C51A63 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 744F6107239EEC4E00C51A63 /* main.swift */; }; 75 | 744F610C239EEC5A00C51A63 /* SwiftMetal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 744F60B8239EE2A200C51A63 /* SwiftMetal.framework */; }; 76 | 744F610D239EEC5A00C51A63 /* SwiftMetal.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 744F60B8239EE2A200C51A63 /* SwiftMetal.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 77 | 74512F25239BE34D008F5FCE /* TestMedia.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 74512F24239BE34D008F5FCE /* TestMedia.xcassets */; }; 78 | 74512F26239BE39D008F5FCE /* TestMedia.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 74512F24239BE34D008F5FCE /* TestMedia.xcassets */; }; 79 | 74E5B8FD239C547E00492280 /* SMFunction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74E5B8FC239C547E00492280 /* SMFunction.swift */; }; 80 | /* End PBXBuildFile section */ 81 | 82 | /* Begin PBXContainerItemProxy section */ 83 | 3A478A19239E557F009AE4D4 /* PBXContainerItemProxy */ = { 84 | isa = PBXContainerItemProxy; 85 | containerPortal = 3A99C5EE239A4B20005BE419 /* Project object */; 86 | proxyType = 1; 87 | remoteGlobalIDString = 3A99C5F6239A4B20005BE419; 88 | remoteInfo = SwiftMetal; 89 | }; 90 | 3A99C602239A4B20005BE419 /* PBXContainerItemProxy */ = { 91 | isa = PBXContainerItemProxy; 92 | containerPortal = 3A99C5EE239A4B20005BE419 /* Project object */; 93 | proxyType = 1; 94 | remoteGlobalIDString = 3A99C5F6239A4B20005BE419; 95 | remoteInfo = SwiftMetal; 96 | }; 97 | 744F610E239EEC5A00C51A63 /* PBXContainerItemProxy */ = { 98 | isa = PBXContainerItemProxy; 99 | containerPortal = 3A99C5EE239A4B20005BE419 /* Project object */; 100 | proxyType = 1; 101 | remoteGlobalIDString = 744F60B7239EE2A200C51A63; 102 | remoteInfo = SwiftMetal_macOS; 103 | }; 104 | /* End PBXContainerItemProxy section */ 105 | 106 | /* Begin PBXCopyFilesBuildPhase section */ 107 | 3A478A1B239E557F009AE4D4 /* Embed Frameworks */ = { 108 | isa = PBXCopyFilesBuildPhase; 109 | buildActionMask = 2147483647; 110 | dstPath = ""; 111 | dstSubfolderSpec = 10; 112 | files = ( 113 | 3A478A18239E557F009AE4D4 /* SwiftMetal.framework in Embed Frameworks */, 114 | ); 115 | name = "Embed Frameworks"; 116 | runOnlyForDeploymentPostprocessing = 0; 117 | }; 118 | 744F6103239EEC4E00C51A63 /* CopyFiles */ = { 119 | isa = PBXCopyFilesBuildPhase; 120 | buildActionMask = 2147483647; 121 | dstPath = /usr/share/man/man1/; 122 | dstSubfolderSpec = 0; 123 | files = ( 124 | ); 125 | runOnlyForDeploymentPostprocessing = 1; 126 | }; 127 | 744F6110239EEC5A00C51A63 /* Embed Frameworks */ = { 128 | isa = PBXCopyFilesBuildPhase; 129 | buildActionMask = 2147483647; 130 | dstPath = ""; 131 | dstSubfolderSpec = 10; 132 | files = ( 133 | 744F610D239EEC5A00C51A63 /* SwiftMetal.framework in Embed Frameworks */, 134 | ); 135 | name = "Embed Frameworks"; 136 | runOnlyForDeploymentPostprocessing = 0; 137 | }; 138 | /* End PBXCopyFilesBuildPhase section */ 139 | 140 | /* Begin PBXFileReference section */ 141 | 3A159FDA23A28DE300D202FD /* Photos.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Photos.swift; sourceTree = ""; }; 142 | 3A159FDD23A291D000D202FD /* Camera.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Camera.swift; sourceTree = ""; }; 143 | 3A159FE023A2998300D202FD /* SwiftMetal.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = SwiftMetal.podspec; sourceTree = ""; }; 144 | 3A1A9D66239F9E500030EE35 /* SMView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMView.swift; sourceTree = ""; }; 145 | 3A478A02239E556B009AE4D4 /* Swift Metal.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Swift Metal.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 146 | 3A478A04239E556B009AE4D4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 147 | 3A478A06239E556B009AE4D4 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 148 | 3A478A08239E556B009AE4D4 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 149 | 3A478A0A239E556D009AE4D4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 150 | 3A478A0D239E556D009AE4D4 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 151 | 3A478A10239E556D009AE4D4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 152 | 3A478A12239E556D009AE4D4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 153 | 3A670680239A61BB00E23C87 /* SMEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMEntity.swift; sourceTree = ""; }; 154 | 3A670688239A666300E23C87 /* SMTexture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMTexture.swift; sourceTree = ""; }; 155 | 3A67068A239A687E00E23C87 /* SMBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMBuilder.swift; sourceTree = ""; }; 156 | 3A67068C239A6CCB00E23C87 /* SMCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMCode.swift; sourceTree = ""; }; 157 | 3A670690239A93D400E23C87 /* SMRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMRenderer.swift; sourceTree = ""; }; 158 | 3A670694239A9D9600E23C87 /* Template.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = Template.metal; sourceTree = ""; }; 159 | 3A7344DF23A25014003BEF66 /* SMBool.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMBool.swift; sourceTree = ""; }; 160 | 3A7344E423A27778003BEF66 /* Logo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logo.swift; sourceTree = ""; }; 161 | 3A9455DA239FD8D500668AE3 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 162 | 3A99C5F7239A4B20005BE419 /* SwiftMetal.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftMetal.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 163 | 3A99C5FA239A4B20005BE419 /* SwiftMetal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftMetal.h; sourceTree = ""; }; 164 | 3A99C5FB239A4B20005BE419 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 165 | 3A99C600239A4B20005BE419 /* SwiftMetalTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftMetalTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 166 | 3A99C605239A4B20005BE419 /* SwiftMetalTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftMetalTests.swift; sourceTree = ""; }; 167 | 3A99C607239A4B20005BE419 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 168 | 3A99C612239A4B61005BE419 /* SMShader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMShader.swift; sourceTree = ""; }; 169 | 3A99C615239A4B8E005BE419 /* SMValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMValue.swift; sourceTree = ""; }; 170 | 3AB01E2523A38DAE003738D1 /* Main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Main.swift; sourceTree = ""; }; 171 | 3AB01E2923A3CF32003738D1 /* SMVector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMVector.swift; sourceTree = ""; }; 172 | 3AB82E10239FDC2700651B10 /* Package.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; 173 | 7422A263239D31F0003FEA65 /* SMFloat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMFloat.swift; sourceTree = ""; }; 174 | 7422A267239D3438003FEA65 /* Types.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Types.swift; sourceTree = ""; }; 175 | 744F60B1239EDCF200C51A63 /* Float16.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Float16.swift; sourceTree = ""; }; 176 | 744F60B8239EE2A200C51A63 /* SwiftMetal.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftMetal.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 177 | 744F60BA239EE2A200C51A63 /* SwiftMetal_macOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftMetal_macOS.h; sourceTree = ""; }; 178 | 744F60C5239EE2D100C51A63 /* SwiftMetal.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftMetal.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 179 | 744F60C7239EE2D100C51A63 /* SwiftMetal_tvOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftMetal_tvOS.h; sourceTree = ""; }; 180 | 744F6105239EEC4E00C51A63 /* SwiftMetalTool */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = SwiftMetalTool; sourceTree = BUILT_PRODUCTS_DIR; }; 181 | 744F6107239EEC4E00C51A63 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 182 | 74512F24239BE34D008F5FCE /* TestMedia.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = TestMedia.xcassets; sourceTree = ""; }; 183 | 74E5B8FC239C547E00492280 /* SMFunction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMFunction.swift; sourceTree = ""; }; 184 | /* End PBXFileReference section */ 185 | 186 | /* Begin PBXFrameworksBuildPhase section */ 187 | 3A4789FF239E556B009AE4D4 /* Frameworks */ = { 188 | isa = PBXFrameworksBuildPhase; 189 | buildActionMask = 2147483647; 190 | files = ( 191 | 3A478A17239E557F009AE4D4 /* SwiftMetal.framework in Frameworks */, 192 | ); 193 | runOnlyForDeploymentPostprocessing = 0; 194 | }; 195 | 3A99C5F4239A4B20005BE419 /* Frameworks */ = { 196 | isa = PBXFrameworksBuildPhase; 197 | buildActionMask = 2147483647; 198 | files = ( 199 | ); 200 | runOnlyForDeploymentPostprocessing = 0; 201 | }; 202 | 3A99C5FD239A4B20005BE419 /* Frameworks */ = { 203 | isa = PBXFrameworksBuildPhase; 204 | buildActionMask = 2147483647; 205 | files = ( 206 | 3A99C601239A4B20005BE419 /* SwiftMetal.framework in Frameworks */, 207 | ); 208 | runOnlyForDeploymentPostprocessing = 0; 209 | }; 210 | 744F60B5239EE2A200C51A63 /* Frameworks */ = { 211 | isa = PBXFrameworksBuildPhase; 212 | buildActionMask = 2147483647; 213 | files = ( 214 | ); 215 | runOnlyForDeploymentPostprocessing = 0; 216 | }; 217 | 744F60C2239EE2D100C51A63 /* Frameworks */ = { 218 | isa = PBXFrameworksBuildPhase; 219 | buildActionMask = 2147483647; 220 | files = ( 221 | ); 222 | runOnlyForDeploymentPostprocessing = 0; 223 | }; 224 | 744F6102239EEC4E00C51A63 /* Frameworks */ = { 225 | isa = PBXFrameworksBuildPhase; 226 | buildActionMask = 2147483647; 227 | files = ( 228 | 744F610C239EEC5A00C51A63 /* SwiftMetal.framework in Frameworks */, 229 | ); 230 | runOnlyForDeploymentPostprocessing = 0; 231 | }; 232 | /* End PBXFrameworksBuildPhase section */ 233 | 234 | /* Begin PBXGroup section */ 235 | 3A478A03239E556B009AE4D4 /* SwiftMetalDemo */ = { 236 | isa = PBXGroup; 237 | children = ( 238 | 3A478A04239E556B009AE4D4 /* AppDelegate.swift */, 239 | 3A478A06239E556B009AE4D4 /* SceneDelegate.swift */, 240 | 3A478A08239E556B009AE4D4 /* ContentView.swift */, 241 | 3AB01E2523A38DAE003738D1 /* Main.swift */, 242 | 3A478A0A239E556D009AE4D4 /* Assets.xcassets */, 243 | 3A478A0F239E556D009AE4D4 /* LaunchScreen.storyboard */, 244 | 3A478A12239E556D009AE4D4 /* Info.plist */, 245 | 3A478A0C239E556D009AE4D4 /* Preview Content */, 246 | ); 247 | path = SwiftMetalDemo; 248 | sourceTree = ""; 249 | }; 250 | 3A478A0C239E556D009AE4D4 /* Preview Content */ = { 251 | isa = PBXGroup; 252 | children = ( 253 | 3A478A0D239E556D009AE4D4 /* Preview Assets.xcassets */, 254 | ); 255 | path = "Preview Content"; 256 | sourceTree = ""; 257 | }; 258 | 3A478A16239E557F009AE4D4 /* Frameworks */ = { 259 | isa = PBXGroup; 260 | children = ( 261 | ); 262 | name = Frameworks; 263 | sourceTree = ""; 264 | }; 265 | 3A67067F239A61A900E23C87 /* Types */ = { 266 | isa = PBXGroup; 267 | children = ( 268 | 3A670680239A61BB00E23C87 /* SMEntity.swift */, 269 | 3A99C615239A4B8E005BE419 /* SMValue.swift */, 270 | 3AB01E2923A3CF32003738D1 /* SMVector.swift */, 271 | 7422A263239D31F0003FEA65 /* SMFloat.swift */, 272 | 3A7344DF23A25014003BEF66 /* SMBool.swift */, 273 | 3A670688239A666300E23C87 /* SMTexture.swift */, 274 | ); 275 | path = Types; 276 | sourceTree = ""; 277 | }; 278 | 3A7344E723A27872003BEF66 /* ExampleShaders */ = { 279 | isa = PBXGroup; 280 | children = ( 281 | 3A7344E423A27778003BEF66 /* Logo.swift */, 282 | 3A159FDA23A28DE300D202FD /* Photos.swift */, 283 | 3A159FDD23A291D000D202FD /* Camera.swift */, 284 | ); 285 | path = ExampleShaders; 286 | sourceTree = ""; 287 | }; 288 | 3A99C5ED239A4B20005BE419 = { 289 | isa = PBXGroup; 290 | children = ( 291 | 3AB82E10239FDC2700651B10 /* Package.swift */, 292 | 3A9455DA239FD8D500668AE3 /* README.md */, 293 | 3A159FE023A2998300D202FD /* SwiftMetal.podspec */, 294 | 3A99C5F9239A4B20005BE419 /* Sources */, 295 | 3A99C611239A4B37005BE419 /* Resources */, 296 | 3A99C604239A4B20005BE419 /* SwiftMetalTests */, 297 | 3A478A03239E556B009AE4D4 /* SwiftMetalDemo */, 298 | 744F6106239EEC4E00C51A63 /* SwiftMetalTool */, 299 | 3A7344E723A27872003BEF66 /* ExampleShaders */, 300 | 3A99C5F8239A4B20005BE419 /* Products */, 301 | 3A478A16239E557F009AE4D4 /* Frameworks */, 302 | ); 303 | sourceTree = ""; 304 | }; 305 | 3A99C5F8239A4B20005BE419 /* Products */ = { 306 | isa = PBXGroup; 307 | children = ( 308 | 3A99C5F7239A4B20005BE419 /* SwiftMetal.framework */, 309 | 3A99C600239A4B20005BE419 /* SwiftMetalTests.xctest */, 310 | 3A478A02239E556B009AE4D4 /* Swift Metal.app */, 311 | 744F60B8239EE2A200C51A63 /* SwiftMetal.framework */, 312 | 744F60C5239EE2D100C51A63 /* SwiftMetal.framework */, 313 | 744F6105239EEC4E00C51A63 /* SwiftMetalTool */, 314 | ); 315 | name = Products; 316 | sourceTree = ""; 317 | }; 318 | 3A99C5F9239A4B20005BE419 /* Sources */ = { 319 | isa = PBXGroup; 320 | children = ( 321 | 3A670690239A93D400E23C87 /* SMRenderer.swift */, 322 | 3A99C612239A4B61005BE419 /* SMShader.swift */, 323 | 3A67068C239A6CCB00E23C87 /* SMCode.swift */, 324 | 3A67068A239A687E00E23C87 /* SMBuilder.swift */, 325 | 74E5B8FC239C547E00492280 /* SMFunction.swift */, 326 | 3A1A9D66239F9E500030EE35 /* SMView.swift */, 327 | 3A67067F239A61A900E23C87 /* Types */, 328 | 7422A267239D3438003FEA65 /* Types.swift */, 329 | 744F60B0239EDCE600C51A63 /* Other */, 330 | ); 331 | path = Sources; 332 | sourceTree = ""; 333 | }; 334 | 3A99C604239A4B20005BE419 /* SwiftMetalTests */ = { 335 | isa = PBXGroup; 336 | children = ( 337 | 3A99C605239A4B20005BE419 /* SwiftMetalTests.swift */, 338 | 3A99C607239A4B20005BE419 /* Info.plist */, 339 | ); 340 | path = SwiftMetalTests; 341 | sourceTree = ""; 342 | }; 343 | 3A99C611239A4B37005BE419 /* Resources */ = { 344 | isa = PBXGroup; 345 | children = ( 346 | 3A99C5FB239A4B20005BE419 /* Info.plist */, 347 | 74512F24239BE34D008F5FCE /* TestMedia.xcassets */, 348 | 3A670694239A9D9600E23C87 /* Template.metal */, 349 | 744F60FE239EE43100C51A63 /* Headers */, 350 | ); 351 | path = Resources; 352 | sourceTree = ""; 353 | }; 354 | 744F60B0239EDCE600C51A63 /* Other */ = { 355 | isa = PBXGroup; 356 | children = ( 357 | 744F60B1239EDCF200C51A63 /* Float16.swift */, 358 | ); 359 | path = Other; 360 | sourceTree = ""; 361 | }; 362 | 744F60FE239EE43100C51A63 /* Headers */ = { 363 | isa = PBXGroup; 364 | children = ( 365 | 3A99C5FA239A4B20005BE419 /* SwiftMetal.h */, 366 | 744F60BA239EE2A200C51A63 /* SwiftMetal_macOS.h */, 367 | 744F60C7239EE2D100C51A63 /* SwiftMetal_tvOS.h */, 368 | ); 369 | path = Headers; 370 | sourceTree = ""; 371 | }; 372 | 744F6106239EEC4E00C51A63 /* SwiftMetalTool */ = { 373 | isa = PBXGroup; 374 | children = ( 375 | 744F6107239EEC4E00C51A63 /* main.swift */, 376 | ); 377 | path = SwiftMetalTool; 378 | sourceTree = ""; 379 | }; 380 | /* End PBXGroup section */ 381 | 382 | /* Begin PBXHeadersBuildPhase section */ 383 | 3A99C5F2239A4B20005BE419 /* Headers */ = { 384 | isa = PBXHeadersBuildPhase; 385 | buildActionMask = 2147483647; 386 | files = ( 387 | 3A99C608239A4B20005BE419 /* SwiftMetal.h in Headers */, 388 | ); 389 | runOnlyForDeploymentPostprocessing = 0; 390 | }; 391 | 744F60B3239EE2A200C51A63 /* Headers */ = { 392 | isa = PBXHeadersBuildPhase; 393 | buildActionMask = 2147483647; 394 | files = ( 395 | 744F60BC239EE2A200C51A63 /* SwiftMetal_macOS.h in Headers */, 396 | ); 397 | runOnlyForDeploymentPostprocessing = 0; 398 | }; 399 | 744F60C0239EE2D100C51A63 /* Headers */ = { 400 | isa = PBXHeadersBuildPhase; 401 | buildActionMask = 2147483647; 402 | files = ( 403 | 744F60C9239EE2D100C51A63 /* SwiftMetal_tvOS.h in Headers */, 404 | ); 405 | runOnlyForDeploymentPostprocessing = 0; 406 | }; 407 | /* End PBXHeadersBuildPhase section */ 408 | 409 | /* Begin PBXNativeTarget section */ 410 | 3A478A01239E556B009AE4D4 /* SwiftMetalDemo */ = { 411 | isa = PBXNativeTarget; 412 | buildConfigurationList = 3A478A13239E556D009AE4D4 /* Build configuration list for PBXNativeTarget "SwiftMetalDemo" */; 413 | buildPhases = ( 414 | 3A4789FE239E556B009AE4D4 /* Sources */, 415 | 3A4789FF239E556B009AE4D4 /* Frameworks */, 416 | 3A478A00239E556B009AE4D4 /* Resources */, 417 | 3A478A1B239E557F009AE4D4 /* Embed Frameworks */, 418 | ); 419 | buildRules = ( 420 | ); 421 | dependencies = ( 422 | 3A478A1A239E557F009AE4D4 /* PBXTargetDependency */, 423 | ); 424 | name = SwiftMetalDemo; 425 | productName = SwiftMetalDemo; 426 | productReference = 3A478A02239E556B009AE4D4 /* Swift Metal.app */; 427 | productType = "com.apple.product-type.application"; 428 | }; 429 | 3A99C5F6239A4B20005BE419 /* SwiftMetal_iOS */ = { 430 | isa = PBXNativeTarget; 431 | buildConfigurationList = 3A99C60B239A4B20005BE419 /* Build configuration list for PBXNativeTarget "SwiftMetal_iOS" */; 432 | buildPhases = ( 433 | 3A99C5F2239A4B20005BE419 /* Headers */, 434 | 3A99C5F3239A4B20005BE419 /* Sources */, 435 | 3A99C5F4239A4B20005BE419 /* Frameworks */, 436 | 3A99C5F5239A4B20005BE419 /* Resources */, 437 | ); 438 | buildRules = ( 439 | ); 440 | dependencies = ( 441 | ); 442 | name = SwiftMetal_iOS; 443 | productName = SwiftMetal; 444 | productReference = 3A99C5F7239A4B20005BE419 /* SwiftMetal.framework */; 445 | productType = "com.apple.product-type.framework"; 446 | }; 447 | 3A99C5FF239A4B20005BE419 /* SwiftMetalTests */ = { 448 | isa = PBXNativeTarget; 449 | buildConfigurationList = 3A99C60E239A4B20005BE419 /* Build configuration list for PBXNativeTarget "SwiftMetalTests" */; 450 | buildPhases = ( 451 | 3A99C5FC239A4B20005BE419 /* Sources */, 452 | 3A99C5FD239A4B20005BE419 /* Frameworks */, 453 | 3A99C5FE239A4B20005BE419 /* Resources */, 454 | ); 455 | buildRules = ( 456 | ); 457 | dependencies = ( 458 | 3A99C603239A4B20005BE419 /* PBXTargetDependency */, 459 | ); 460 | name = SwiftMetalTests; 461 | productName = SwiftMetalTests; 462 | productReference = 3A99C600239A4B20005BE419 /* SwiftMetalTests.xctest */; 463 | productType = "com.apple.product-type.bundle.unit-test"; 464 | }; 465 | 744F60B7239EE2A200C51A63 /* SwiftMetal_macOS */ = { 466 | isa = PBXNativeTarget; 467 | buildConfigurationList = 744F60BD239EE2A200C51A63 /* Build configuration list for PBXNativeTarget "SwiftMetal_macOS" */; 468 | buildPhases = ( 469 | 744F60B3239EE2A200C51A63 /* Headers */, 470 | 744F60B4239EE2A200C51A63 /* Sources */, 471 | 744F60B5239EE2A200C51A63 /* Frameworks */, 472 | 744F60B6239EE2A200C51A63 /* Resources */, 473 | ); 474 | buildRules = ( 475 | ); 476 | dependencies = ( 477 | ); 478 | name = SwiftMetal_macOS; 479 | productName = SwiftMetal_macOS; 480 | productReference = 744F60B8239EE2A200C51A63 /* SwiftMetal.framework */; 481 | productType = "com.apple.product-type.framework"; 482 | }; 483 | 744F60C4239EE2D100C51A63 /* SwiftMetal_tvOS */ = { 484 | isa = PBXNativeTarget; 485 | buildConfigurationList = 744F60CA239EE2D100C51A63 /* Build configuration list for PBXNativeTarget "SwiftMetal_tvOS" */; 486 | buildPhases = ( 487 | 744F60C0239EE2D100C51A63 /* Headers */, 488 | 744F60C1239EE2D100C51A63 /* Sources */, 489 | 744F60C2239EE2D100C51A63 /* Frameworks */, 490 | 744F60C3239EE2D100C51A63 /* Resources */, 491 | ); 492 | buildRules = ( 493 | ); 494 | dependencies = ( 495 | ); 496 | name = SwiftMetal_tvOS; 497 | productName = SwiftMetal_tvOS; 498 | productReference = 744F60C5239EE2D100C51A63 /* SwiftMetal.framework */; 499 | productType = "com.apple.product-type.framework"; 500 | }; 501 | 744F6104239EEC4E00C51A63 /* SwiftMetalTool */ = { 502 | isa = PBXNativeTarget; 503 | buildConfigurationList = 744F6109239EEC4E00C51A63 /* Build configuration list for PBXNativeTarget "SwiftMetalTool" */; 504 | buildPhases = ( 505 | 744F6101239EEC4E00C51A63 /* Sources */, 506 | 744F6102239EEC4E00C51A63 /* Frameworks */, 507 | 744F6103239EEC4E00C51A63 /* CopyFiles */, 508 | 744F6110239EEC5A00C51A63 /* Embed Frameworks */, 509 | ); 510 | buildRules = ( 511 | ); 512 | dependencies = ( 513 | 744F610F239EEC5A00C51A63 /* PBXTargetDependency */, 514 | ); 515 | name = SwiftMetalTool; 516 | productName = SwiftMetalTool; 517 | productReference = 744F6105239EEC4E00C51A63 /* SwiftMetalTool */; 518 | productType = "com.apple.product-type.tool"; 519 | }; 520 | /* End PBXNativeTarget section */ 521 | 522 | /* Begin PBXProject section */ 523 | 3A99C5EE239A4B20005BE419 /* Project object */ = { 524 | isa = PBXProject; 525 | attributes = { 526 | LastSwiftUpdateCheck = 1130; 527 | LastUpgradeCheck = 1120; 528 | ORGANIZATIONNAME = Hexagons; 529 | TargetAttributes = { 530 | 3A478A01239E556B009AE4D4 = { 531 | CreatedOnToolsVersion = 11.2.1; 532 | }; 533 | 3A99C5F6239A4B20005BE419 = { 534 | CreatedOnToolsVersion = 11.2.1; 535 | LastSwiftMigration = 1120; 536 | }; 537 | 3A99C5FF239A4B20005BE419 = { 538 | CreatedOnToolsVersion = 11.2.1; 539 | }; 540 | 744F60B7239EE2A200C51A63 = { 541 | CreatedOnToolsVersion = 11.3; 542 | }; 543 | 744F60C4239EE2D100C51A63 = { 544 | CreatedOnToolsVersion = 11.3; 545 | }; 546 | 744F6104239EEC4E00C51A63 = { 547 | CreatedOnToolsVersion = 11.3; 548 | }; 549 | }; 550 | }; 551 | buildConfigurationList = 3A99C5F1239A4B20005BE419 /* Build configuration list for PBXProject "SwiftMetal" */; 552 | compatibilityVersion = "Xcode 9.3"; 553 | developmentRegion = en; 554 | hasScannedForEncodings = 0; 555 | knownRegions = ( 556 | en, 557 | Base, 558 | ); 559 | mainGroup = 3A99C5ED239A4B20005BE419; 560 | productRefGroup = 3A99C5F8239A4B20005BE419 /* Products */; 561 | projectDirPath = ""; 562 | projectRoot = ""; 563 | targets = ( 564 | 3A99C5F6239A4B20005BE419 /* SwiftMetal_iOS */, 565 | 744F60B7239EE2A200C51A63 /* SwiftMetal_macOS */, 566 | 744F60C4239EE2D100C51A63 /* SwiftMetal_tvOS */, 567 | 3A99C5FF239A4B20005BE419 /* SwiftMetalTests */, 568 | 3A478A01239E556B009AE4D4 /* SwiftMetalDemo */, 569 | 744F6104239EEC4E00C51A63 /* SwiftMetalTool */, 570 | ); 571 | }; 572 | /* End PBXProject section */ 573 | 574 | /* Begin PBXResourcesBuildPhase section */ 575 | 3A478A00239E556B009AE4D4 /* Resources */ = { 576 | isa = PBXResourcesBuildPhase; 577 | buildActionMask = 2147483647; 578 | files = ( 579 | 3A478A11239E556D009AE4D4 /* LaunchScreen.storyboard in Resources */, 580 | 3A478A0E239E556D009AE4D4 /* Preview Assets.xcassets in Resources */, 581 | 3A478A1C239E55A8009AE4D4 /* TestMedia.xcassets in Resources */, 582 | 3A478A0B239E556D009AE4D4 /* Assets.xcassets in Resources */, 583 | ); 584 | runOnlyForDeploymentPostprocessing = 0; 585 | }; 586 | 3A99C5F5239A4B20005BE419 /* Resources */ = { 587 | isa = PBXResourcesBuildPhase; 588 | buildActionMask = 2147483647; 589 | files = ( 590 | 74512F25239BE34D008F5FCE /* TestMedia.xcassets in Resources */, 591 | ); 592 | runOnlyForDeploymentPostprocessing = 0; 593 | }; 594 | 3A99C5FE239A4B20005BE419 /* Resources */ = { 595 | isa = PBXResourcesBuildPhase; 596 | buildActionMask = 2147483647; 597 | files = ( 598 | 74512F26239BE39D008F5FCE /* TestMedia.xcassets in Resources */, 599 | ); 600 | runOnlyForDeploymentPostprocessing = 0; 601 | }; 602 | 744F60B6239EE2A200C51A63 /* Resources */ = { 603 | isa = PBXResourcesBuildPhase; 604 | buildActionMask = 2147483647; 605 | files = ( 606 | 744F60FF239EEB0300C51A63 /* TestMedia.xcassets in Resources */, 607 | ); 608 | runOnlyForDeploymentPostprocessing = 0; 609 | }; 610 | 744F60C3239EE2D100C51A63 /* Resources */ = { 611 | isa = PBXResourcesBuildPhase; 612 | buildActionMask = 2147483647; 613 | files = ( 614 | 744F6100239EEB0300C51A63 /* TestMedia.xcassets in Resources */, 615 | ); 616 | runOnlyForDeploymentPostprocessing = 0; 617 | }; 618 | /* End PBXResourcesBuildPhase section */ 619 | 620 | /* Begin PBXSourcesBuildPhase section */ 621 | 3A4789FE239E556B009AE4D4 /* Sources */ = { 622 | isa = PBXSourcesBuildPhase; 623 | buildActionMask = 2147483647; 624 | files = ( 625 | 3A159FDF23A2921000D202FD /* Camera.swift in Sources */, 626 | 3A15240B239F9D3D003E6333 /* Template.metal in Sources */, 627 | 3AB01E2623A38DAE003738D1 /* Main.swift in Sources */, 628 | 3A478A05239E556B009AE4D4 /* AppDelegate.swift in Sources */, 629 | 3A478A07239E556B009AE4D4 /* SceneDelegate.swift in Sources */, 630 | 3A159FDC23A28DE700D202FD /* Photos.swift in Sources */, 631 | 3A7344E523A27778003BEF66 /* Logo.swift in Sources */, 632 | 3A478A09239E556B009AE4D4 /* ContentView.swift in Sources */, 633 | ); 634 | runOnlyForDeploymentPostprocessing = 0; 635 | }; 636 | 3A99C5F3239A4B20005BE419 /* Sources */ = { 637 | isa = PBXSourcesBuildPhase; 638 | buildActionMask = 2147483647; 639 | files = ( 640 | 3A67068D239A6CCB00E23C87 /* SMCode.swift in Sources */, 641 | 744F60B2239EDCF200C51A63 /* Float16.swift in Sources */, 642 | 3A67068B239A687E00E23C87 /* SMBuilder.swift in Sources */, 643 | 3A670691239A93D400E23C87 /* SMRenderer.swift in Sources */, 644 | 3A99C616239A4B8E005BE419 /* SMValue.swift in Sources */, 645 | 74E5B8FD239C547E00492280 /* SMFunction.swift in Sources */, 646 | 7422A264239D31F0003FEA65 /* SMFloat.swift in Sources */, 647 | 3A7344E023A25014003BEF66 /* SMBool.swift in Sources */, 648 | 3A670689239A666300E23C87 /* SMTexture.swift in Sources */, 649 | 3A99C613239A4B61005BE419 /* SMShader.swift in Sources */, 650 | 3AB01E2A23A3CF32003738D1 /* SMVector.swift in Sources */, 651 | 7422A268239D3438003FEA65 /* Types.swift in Sources */, 652 | 3A670681239A61BB00E23C87 /* SMEntity.swift in Sources */, 653 | 3A1A9D67239F9E500030EE35 /* SMView.swift in Sources */, 654 | 3A670695239A9D9600E23C87 /* Template.metal in Sources */, 655 | ); 656 | runOnlyForDeploymentPostprocessing = 0; 657 | }; 658 | 3A99C5FC239A4B20005BE419 /* Sources */ = { 659 | isa = PBXSourcesBuildPhase; 660 | buildActionMask = 2147483647; 661 | files = ( 662 | 3A99C606239A4B20005BE419 /* SwiftMetalTests.swift in Sources */, 663 | 3A15240A239F9D3D003E6333 /* Template.metal in Sources */, 664 | ); 665 | runOnlyForDeploymentPostprocessing = 0; 666 | }; 667 | 744F60B4239EE2A200C51A63 /* Sources */ = { 668 | isa = PBXSourcesBuildPhase; 669 | buildActionMask = 2147483647; 670 | files = ( 671 | 744F60DD239EE30000C51A63 /* SMRenderer.swift in Sources */, 672 | 744F60FB239EE30700C51A63 /* Float16.swift in Sources */, 673 | 744F60E1239EE30000C51A63 /* SMFunction.swift in Sources */, 674 | 744F60DA239EE2FA00C51A63 /* Template.metal in Sources */, 675 | 744F60F0239EE30400C51A63 /* SMValue.swift in Sources */, 676 | 744F60F1239EE30400C51A63 /* SMFloat.swift in Sources */, 677 | 744F60E2239EE30000C51A63 /* Types.swift in Sources */, 678 | 3A7344E123A25014003BEF66 /* SMBool.swift in Sources */, 679 | 744F60F2239EE30400C51A63 /* SMTexture.swift in Sources */, 680 | 744F60DF239EE30000C51A63 /* SMCode.swift in Sources */, 681 | 744F60DE239EE30000C51A63 /* SMShader.swift in Sources */, 682 | 3A1A9D68239F9E5E0030EE35 /* SMView.swift in Sources */, 683 | 744F60EF239EE30400C51A63 /* SMEntity.swift in Sources */, 684 | 744F60E0239EE30000C51A63 /* SMBuilder.swift in Sources */, 685 | ); 686 | runOnlyForDeploymentPostprocessing = 0; 687 | }; 688 | 744F60C1239EE2D100C51A63 /* Sources */ = { 689 | isa = PBXSourcesBuildPhase; 690 | buildActionMask = 2147483647; 691 | files = ( 692 | 744F60E3239EE30100C51A63 /* SMRenderer.swift in Sources */, 693 | 744F60FC239EE30800C51A63 /* Float16.swift in Sources */, 694 | 744F60E7239EE30100C51A63 /* SMFunction.swift in Sources */, 695 | 744F60DB239EE2FA00C51A63 /* Template.metal in Sources */, 696 | 744F60F4239EE30500C51A63 /* SMValue.swift in Sources */, 697 | 744F60F5239EE30500C51A63 /* SMFloat.swift in Sources */, 698 | 744F60E8239EE30100C51A63 /* Types.swift in Sources */, 699 | 3A7344E223A25014003BEF66 /* SMBool.swift in Sources */, 700 | 744F60F6239EE30500C51A63 /* SMTexture.swift in Sources */, 701 | 744F60E5239EE30100C51A63 /* SMCode.swift in Sources */, 702 | 744F60E4239EE30100C51A63 /* SMShader.swift in Sources */, 703 | 3A1A9D69239F9E5E0030EE35 /* SMView.swift in Sources */, 704 | 744F60F3239EE30500C51A63 /* SMEntity.swift in Sources */, 705 | 744F60E6239EE30100C51A63 /* SMBuilder.swift in Sources */, 706 | ); 707 | runOnlyForDeploymentPostprocessing = 0; 708 | }; 709 | 744F6101239EEC4E00C51A63 /* Sources */ = { 710 | isa = PBXSourcesBuildPhase; 711 | buildActionMask = 2147483647; 712 | files = ( 713 | 744F6108239EEC4E00C51A63 /* main.swift in Sources */, 714 | ); 715 | runOnlyForDeploymentPostprocessing = 0; 716 | }; 717 | /* End PBXSourcesBuildPhase section */ 718 | 719 | /* Begin PBXTargetDependency section */ 720 | 3A478A1A239E557F009AE4D4 /* PBXTargetDependency */ = { 721 | isa = PBXTargetDependency; 722 | target = 3A99C5F6239A4B20005BE419 /* SwiftMetal_iOS */; 723 | targetProxy = 3A478A19239E557F009AE4D4 /* PBXContainerItemProxy */; 724 | }; 725 | 3A99C603239A4B20005BE419 /* PBXTargetDependency */ = { 726 | isa = PBXTargetDependency; 727 | target = 3A99C5F6239A4B20005BE419 /* SwiftMetal_iOS */; 728 | targetProxy = 3A99C602239A4B20005BE419 /* PBXContainerItemProxy */; 729 | }; 730 | 744F610F239EEC5A00C51A63 /* PBXTargetDependency */ = { 731 | isa = PBXTargetDependency; 732 | target = 744F60B7239EE2A200C51A63 /* SwiftMetal_macOS */; 733 | targetProxy = 744F610E239EEC5A00C51A63 /* PBXContainerItemProxy */; 734 | }; 735 | /* End PBXTargetDependency section */ 736 | 737 | /* Begin PBXVariantGroup section */ 738 | 3A478A0F239E556D009AE4D4 /* LaunchScreen.storyboard */ = { 739 | isa = PBXVariantGroup; 740 | children = ( 741 | 3A478A10239E556D009AE4D4 /* Base */, 742 | ); 743 | name = LaunchScreen.storyboard; 744 | sourceTree = ""; 745 | }; 746 | /* End PBXVariantGroup section */ 747 | 748 | /* Begin XCBuildConfiguration section */ 749 | 3A478A14239E556D009AE4D4 /* Debug */ = { 750 | isa = XCBuildConfiguration; 751 | buildSettings = { 752 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 753 | CODE_SIGN_STYLE = Automatic; 754 | DEVELOPMENT_ASSET_PATHS = "\"SwiftMetalDemo/Preview Content\""; 755 | DEVELOPMENT_TEAM = 2QHTY6FMW2; 756 | ENABLE_PREVIEWS = YES; 757 | INFOPLIST_FILE = SwiftMetalDemo/Info.plist; 758 | LD_RUNPATH_SEARCH_PATHS = ( 759 | "$(inherited)", 760 | "@executable_path/Frameworks", 761 | ); 762 | PRODUCT_BUNDLE_IDENTIFIER = se.hexagons.SwiftMetalDemo; 763 | PRODUCT_NAME = "Swift Metal"; 764 | SWIFT_VERSION = 5.0; 765 | TARGETED_DEVICE_FAMILY = 1; 766 | }; 767 | name = Debug; 768 | }; 769 | 3A478A15239E556D009AE4D4 /* Release */ = { 770 | isa = XCBuildConfiguration; 771 | buildSettings = { 772 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 773 | CODE_SIGN_STYLE = Automatic; 774 | DEVELOPMENT_ASSET_PATHS = "\"SwiftMetalDemo/Preview Content\""; 775 | DEVELOPMENT_TEAM = 2QHTY6FMW2; 776 | ENABLE_PREVIEWS = YES; 777 | INFOPLIST_FILE = SwiftMetalDemo/Info.plist; 778 | LD_RUNPATH_SEARCH_PATHS = ( 779 | "$(inherited)", 780 | "@executable_path/Frameworks", 781 | ); 782 | PRODUCT_BUNDLE_IDENTIFIER = se.hexagons.SwiftMetalDemo; 783 | PRODUCT_NAME = "Swift Metal"; 784 | SWIFT_VERSION = 5.0; 785 | TARGETED_DEVICE_FAMILY = 1; 786 | }; 787 | name = Release; 788 | }; 789 | 3A99C609239A4B20005BE419 /* Debug */ = { 790 | isa = XCBuildConfiguration; 791 | buildSettings = { 792 | ALWAYS_SEARCH_USER_PATHS = NO; 793 | CLANG_ANALYZER_NONNULL = YES; 794 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 795 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 796 | CLANG_CXX_LIBRARY = "libc++"; 797 | CLANG_ENABLE_MODULES = YES; 798 | CLANG_ENABLE_OBJC_ARC = YES; 799 | CLANG_ENABLE_OBJC_WEAK = YES; 800 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 801 | CLANG_WARN_BOOL_CONVERSION = YES; 802 | CLANG_WARN_COMMA = YES; 803 | CLANG_WARN_CONSTANT_CONVERSION = YES; 804 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 805 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 806 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 807 | CLANG_WARN_EMPTY_BODY = YES; 808 | CLANG_WARN_ENUM_CONVERSION = YES; 809 | CLANG_WARN_INFINITE_RECURSION = YES; 810 | CLANG_WARN_INT_CONVERSION = YES; 811 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 812 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 813 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 814 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 815 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 816 | CLANG_WARN_STRICT_PROTOTYPES = YES; 817 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 818 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 819 | CLANG_WARN_UNREACHABLE_CODE = YES; 820 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 821 | COPY_PHASE_STRIP = NO; 822 | CURRENT_PROJECT_VERSION = 1; 823 | DEBUG_INFORMATION_FORMAT = dwarf; 824 | ENABLE_STRICT_OBJC_MSGSEND = YES; 825 | ENABLE_TESTABILITY = YES; 826 | GCC_C_LANGUAGE_STANDARD = gnu11; 827 | GCC_DYNAMIC_NO_PIC = NO; 828 | GCC_NO_COMMON_BLOCKS = YES; 829 | GCC_OPTIMIZATION_LEVEL = 0; 830 | GCC_PREPROCESSOR_DEFINITIONS = ( 831 | "DEBUG=1", 832 | "$(inherited)", 833 | ); 834 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 835 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 836 | GCC_WARN_UNDECLARED_SELECTOR = YES; 837 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 838 | GCC_WARN_UNUSED_FUNCTION = YES; 839 | GCC_WARN_UNUSED_VARIABLE = YES; 840 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 841 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 842 | MTL_FAST_MATH = YES; 843 | ONLY_ACTIVE_ARCH = YES; 844 | SDKROOT = iphoneos; 845 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 846 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 847 | VERSIONING_SYSTEM = "apple-generic"; 848 | VERSION_INFO_PREFIX = ""; 849 | }; 850 | name = Debug; 851 | }; 852 | 3A99C60A239A4B20005BE419 /* Release */ = { 853 | isa = XCBuildConfiguration; 854 | buildSettings = { 855 | ALWAYS_SEARCH_USER_PATHS = NO; 856 | CLANG_ANALYZER_NONNULL = YES; 857 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 858 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 859 | CLANG_CXX_LIBRARY = "libc++"; 860 | CLANG_ENABLE_MODULES = YES; 861 | CLANG_ENABLE_OBJC_ARC = YES; 862 | CLANG_ENABLE_OBJC_WEAK = YES; 863 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 864 | CLANG_WARN_BOOL_CONVERSION = YES; 865 | CLANG_WARN_COMMA = YES; 866 | CLANG_WARN_CONSTANT_CONVERSION = YES; 867 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 868 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 869 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 870 | CLANG_WARN_EMPTY_BODY = YES; 871 | CLANG_WARN_ENUM_CONVERSION = YES; 872 | CLANG_WARN_INFINITE_RECURSION = YES; 873 | CLANG_WARN_INT_CONVERSION = YES; 874 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 875 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 876 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 877 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 878 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 879 | CLANG_WARN_STRICT_PROTOTYPES = YES; 880 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 881 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 882 | CLANG_WARN_UNREACHABLE_CODE = YES; 883 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 884 | COPY_PHASE_STRIP = NO; 885 | CURRENT_PROJECT_VERSION = 1; 886 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 887 | ENABLE_NS_ASSERTIONS = NO; 888 | ENABLE_STRICT_OBJC_MSGSEND = YES; 889 | GCC_C_LANGUAGE_STANDARD = gnu11; 890 | GCC_NO_COMMON_BLOCKS = YES; 891 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 892 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 893 | GCC_WARN_UNDECLARED_SELECTOR = YES; 894 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 895 | GCC_WARN_UNUSED_FUNCTION = YES; 896 | GCC_WARN_UNUSED_VARIABLE = YES; 897 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 898 | MTL_ENABLE_DEBUG_INFO = NO; 899 | MTL_FAST_MATH = YES; 900 | SDKROOT = iphoneos; 901 | SWIFT_COMPILATION_MODE = wholemodule; 902 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 903 | VALIDATE_PRODUCT = YES; 904 | VERSIONING_SYSTEM = "apple-generic"; 905 | VERSION_INFO_PREFIX = ""; 906 | }; 907 | name = Release; 908 | }; 909 | 3A99C60C239A4B20005BE419 /* Debug */ = { 910 | isa = XCBuildConfiguration; 911 | buildSettings = { 912 | CLANG_ENABLE_MODULES = YES; 913 | CODE_SIGN_STYLE = Automatic; 914 | CURRENT_PROJECT_VERSION = 2; 915 | DEFINES_MODULE = YES; 916 | DEVELOPMENT_TEAM = 2QHTY6FMW2; 917 | DYLIB_COMPATIBILITY_VERSION = 1; 918 | DYLIB_CURRENT_VERSION = 1; 919 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 920 | INFOPLIST_FILE = Resources/Info.plist; 921 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 922 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 923 | LD_RUNPATH_SEARCH_PATHS = ( 924 | "$(inherited)", 925 | "@executable_path/Frameworks", 926 | "@loader_path/Frameworks", 927 | ); 928 | MARKETING_VERSION = 0.1.3; 929 | PRODUCT_BUNDLE_IDENTIFIER = se.hexagons.swift.metal.ios; 930 | PRODUCT_NAME = SwiftMetal; 931 | SKIP_INSTALL = YES; 932 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 933 | SWIFT_VERSION = 5.0; 934 | TARGETED_DEVICE_FAMILY = "1,2"; 935 | }; 936 | name = Debug; 937 | }; 938 | 3A99C60D239A4B20005BE419 /* Release */ = { 939 | isa = XCBuildConfiguration; 940 | buildSettings = { 941 | CLANG_ENABLE_MODULES = YES; 942 | CODE_SIGN_STYLE = Automatic; 943 | CURRENT_PROJECT_VERSION = 2; 944 | DEFINES_MODULE = YES; 945 | DEVELOPMENT_TEAM = 2QHTY6FMW2; 946 | DYLIB_COMPATIBILITY_VERSION = 1; 947 | DYLIB_CURRENT_VERSION = 1; 948 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 949 | INFOPLIST_FILE = Resources/Info.plist; 950 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 951 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 952 | LD_RUNPATH_SEARCH_PATHS = ( 953 | "$(inherited)", 954 | "@executable_path/Frameworks", 955 | "@loader_path/Frameworks", 956 | ); 957 | MARKETING_VERSION = 0.1.3; 958 | PRODUCT_BUNDLE_IDENTIFIER = se.hexagons.swift.metal.ios; 959 | PRODUCT_NAME = SwiftMetal; 960 | SKIP_INSTALL = YES; 961 | SWIFT_VERSION = 5.0; 962 | TARGETED_DEVICE_FAMILY = "1,2"; 963 | }; 964 | name = Release; 965 | }; 966 | 3A99C60F239A4B20005BE419 /* Debug */ = { 967 | isa = XCBuildConfiguration; 968 | buildSettings = { 969 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 970 | CODE_SIGN_STYLE = Automatic; 971 | DEVELOPMENT_TEAM = 2QHTY6FMW2; 972 | INFOPLIST_FILE = SwiftMetalTests/Info.plist; 973 | LD_RUNPATH_SEARCH_PATHS = ( 974 | "$(inherited)", 975 | "@executable_path/Frameworks", 976 | "@loader_path/Frameworks", 977 | ); 978 | PRODUCT_BUNDLE_IDENTIFIER = se.hexagons.SwiftMetalTests; 979 | PRODUCT_NAME = "$(TARGET_NAME)"; 980 | SWIFT_VERSION = 5.0; 981 | TARGETED_DEVICE_FAMILY = "1,2"; 982 | }; 983 | name = Debug; 984 | }; 985 | 3A99C610239A4B20005BE419 /* Release */ = { 986 | isa = XCBuildConfiguration; 987 | buildSettings = { 988 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 989 | CODE_SIGN_STYLE = Automatic; 990 | DEVELOPMENT_TEAM = 2QHTY6FMW2; 991 | INFOPLIST_FILE = SwiftMetalTests/Info.plist; 992 | LD_RUNPATH_SEARCH_PATHS = ( 993 | "$(inherited)", 994 | "@executable_path/Frameworks", 995 | "@loader_path/Frameworks", 996 | ); 997 | PRODUCT_BUNDLE_IDENTIFIER = se.hexagons.SwiftMetalTests; 998 | PRODUCT_NAME = "$(TARGET_NAME)"; 999 | SWIFT_VERSION = 5.0; 1000 | TARGETED_DEVICE_FAMILY = "1,2"; 1001 | }; 1002 | name = Release; 1003 | }; 1004 | 744F60BE239EE2A200C51A63 /* Debug */ = { 1005 | isa = XCBuildConfiguration; 1006 | buildSettings = { 1007 | CODE_SIGN_STYLE = Automatic; 1008 | COMBINE_HIDPI_IMAGES = YES; 1009 | CURRENT_PROJECT_VERSION = 2; 1010 | DEFINES_MODULE = YES; 1011 | DEVELOPMENT_TEAM = 2QHTY6FMW2; 1012 | DYLIB_COMPATIBILITY_VERSION = 1; 1013 | DYLIB_CURRENT_VERSION = 1; 1014 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 1015 | INFOPLIST_FILE = Resources/Info.plist; 1016 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 1017 | LD_RUNPATH_SEARCH_PATHS = ( 1018 | "$(inherited)", 1019 | "@executable_path/../Frameworks", 1020 | "@loader_path/Frameworks", 1021 | ); 1022 | MACOSX_DEPLOYMENT_TARGET = 10.15; 1023 | MARKETING_VERSION = 0.1.3; 1024 | PRODUCT_BUNDLE_IDENTIFIER = se.hexagons.swift.metal.macos; 1025 | PRODUCT_NAME = SwiftMetal; 1026 | SDKROOT = macosx; 1027 | SKIP_INSTALL = YES; 1028 | SWIFT_VERSION = 5.0; 1029 | }; 1030 | name = Debug; 1031 | }; 1032 | 744F60BF239EE2A200C51A63 /* Release */ = { 1033 | isa = XCBuildConfiguration; 1034 | buildSettings = { 1035 | CODE_SIGN_STYLE = Automatic; 1036 | COMBINE_HIDPI_IMAGES = YES; 1037 | CURRENT_PROJECT_VERSION = 2; 1038 | DEFINES_MODULE = YES; 1039 | DEVELOPMENT_TEAM = 2QHTY6FMW2; 1040 | DYLIB_COMPATIBILITY_VERSION = 1; 1041 | DYLIB_CURRENT_VERSION = 1; 1042 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 1043 | INFOPLIST_FILE = Resources/Info.plist; 1044 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 1045 | LD_RUNPATH_SEARCH_PATHS = ( 1046 | "$(inherited)", 1047 | "@executable_path/../Frameworks", 1048 | "@loader_path/Frameworks", 1049 | ); 1050 | MACOSX_DEPLOYMENT_TARGET = 10.15; 1051 | MARKETING_VERSION = 0.1.3; 1052 | PRODUCT_BUNDLE_IDENTIFIER = se.hexagons.swift.metal.macos; 1053 | PRODUCT_NAME = SwiftMetal; 1054 | SDKROOT = macosx; 1055 | SKIP_INSTALL = YES; 1056 | SWIFT_VERSION = 5.0; 1057 | }; 1058 | name = Release; 1059 | }; 1060 | 744F60CB239EE2D100C51A63 /* Debug */ = { 1061 | isa = XCBuildConfiguration; 1062 | buildSettings = { 1063 | CODE_SIGN_STYLE = Automatic; 1064 | CURRENT_PROJECT_VERSION = 2; 1065 | DEFINES_MODULE = YES; 1066 | DEVELOPMENT_TEAM = 2QHTY6FMW2; 1067 | DYLIB_COMPATIBILITY_VERSION = 1; 1068 | DYLIB_CURRENT_VERSION = 1; 1069 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 1070 | INFOPLIST_FILE = Resources/Info.plist; 1071 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 1072 | LD_RUNPATH_SEARCH_PATHS = ( 1073 | "$(inherited)", 1074 | "@executable_path/Frameworks", 1075 | "@loader_path/Frameworks", 1076 | ); 1077 | MARKETING_VERSION = 0.1.3; 1078 | PRODUCT_BUNDLE_IDENTIFIER = se.hexagons.swift.metal.tvos; 1079 | PRODUCT_NAME = SwiftMetal; 1080 | SDKROOT = appletvos; 1081 | SKIP_INSTALL = YES; 1082 | SWIFT_VERSION = 5.0; 1083 | TARGETED_DEVICE_FAMILY = 3; 1084 | TVOS_DEPLOYMENT_TARGET = 13.2; 1085 | }; 1086 | name = Debug; 1087 | }; 1088 | 744F60CC239EE2D100C51A63 /* Release */ = { 1089 | isa = XCBuildConfiguration; 1090 | buildSettings = { 1091 | CODE_SIGN_STYLE = Automatic; 1092 | CURRENT_PROJECT_VERSION = 2; 1093 | DEFINES_MODULE = YES; 1094 | DEVELOPMENT_TEAM = 2QHTY6FMW2; 1095 | DYLIB_COMPATIBILITY_VERSION = 1; 1096 | DYLIB_CURRENT_VERSION = 1; 1097 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 1098 | INFOPLIST_FILE = Resources/Info.plist; 1099 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 1100 | LD_RUNPATH_SEARCH_PATHS = ( 1101 | "$(inherited)", 1102 | "@executable_path/Frameworks", 1103 | "@loader_path/Frameworks", 1104 | ); 1105 | MARKETING_VERSION = 0.1.3; 1106 | PRODUCT_BUNDLE_IDENTIFIER = se.hexagons.swift.metal.tvos; 1107 | PRODUCT_NAME = SwiftMetal; 1108 | SDKROOT = appletvos; 1109 | SKIP_INSTALL = YES; 1110 | SWIFT_VERSION = 5.0; 1111 | TARGETED_DEVICE_FAMILY = 3; 1112 | TVOS_DEPLOYMENT_TARGET = 13.2; 1113 | }; 1114 | name = Release; 1115 | }; 1116 | 744F610A239EEC4E00C51A63 /* Debug */ = { 1117 | isa = XCBuildConfiguration; 1118 | buildSettings = { 1119 | CODE_SIGN_STYLE = Automatic; 1120 | DEVELOPMENT_TEAM = 2QHTY6FMW2; 1121 | ENABLE_HARDENED_RUNTIME = YES; 1122 | MACOSX_DEPLOYMENT_TARGET = 10.15; 1123 | PRODUCT_NAME = "$(TARGET_NAME)"; 1124 | SDKROOT = macosx; 1125 | SWIFT_VERSION = 5.0; 1126 | }; 1127 | name = Debug; 1128 | }; 1129 | 744F610B239EEC4E00C51A63 /* Release */ = { 1130 | isa = XCBuildConfiguration; 1131 | buildSettings = { 1132 | CODE_SIGN_STYLE = Automatic; 1133 | DEVELOPMENT_TEAM = 2QHTY6FMW2; 1134 | ENABLE_HARDENED_RUNTIME = YES; 1135 | MACOSX_DEPLOYMENT_TARGET = 10.15; 1136 | PRODUCT_NAME = "$(TARGET_NAME)"; 1137 | SDKROOT = macosx; 1138 | SWIFT_VERSION = 5.0; 1139 | }; 1140 | name = Release; 1141 | }; 1142 | /* End XCBuildConfiguration section */ 1143 | 1144 | /* Begin XCConfigurationList section */ 1145 | 3A478A13239E556D009AE4D4 /* Build configuration list for PBXNativeTarget "SwiftMetalDemo" */ = { 1146 | isa = XCConfigurationList; 1147 | buildConfigurations = ( 1148 | 3A478A14239E556D009AE4D4 /* Debug */, 1149 | 3A478A15239E556D009AE4D4 /* Release */, 1150 | ); 1151 | defaultConfigurationIsVisible = 0; 1152 | defaultConfigurationName = Release; 1153 | }; 1154 | 3A99C5F1239A4B20005BE419 /* Build configuration list for PBXProject "SwiftMetal" */ = { 1155 | isa = XCConfigurationList; 1156 | buildConfigurations = ( 1157 | 3A99C609239A4B20005BE419 /* Debug */, 1158 | 3A99C60A239A4B20005BE419 /* Release */, 1159 | ); 1160 | defaultConfigurationIsVisible = 0; 1161 | defaultConfigurationName = Release; 1162 | }; 1163 | 3A99C60B239A4B20005BE419 /* Build configuration list for PBXNativeTarget "SwiftMetal_iOS" */ = { 1164 | isa = XCConfigurationList; 1165 | buildConfigurations = ( 1166 | 3A99C60C239A4B20005BE419 /* Debug */, 1167 | 3A99C60D239A4B20005BE419 /* Release */, 1168 | ); 1169 | defaultConfigurationIsVisible = 0; 1170 | defaultConfigurationName = Release; 1171 | }; 1172 | 3A99C60E239A4B20005BE419 /* Build configuration list for PBXNativeTarget "SwiftMetalTests" */ = { 1173 | isa = XCConfigurationList; 1174 | buildConfigurations = ( 1175 | 3A99C60F239A4B20005BE419 /* Debug */, 1176 | 3A99C610239A4B20005BE419 /* Release */, 1177 | ); 1178 | defaultConfigurationIsVisible = 0; 1179 | defaultConfigurationName = Release; 1180 | }; 1181 | 744F60BD239EE2A200C51A63 /* Build configuration list for PBXNativeTarget "SwiftMetal_macOS" */ = { 1182 | isa = XCConfigurationList; 1183 | buildConfigurations = ( 1184 | 744F60BE239EE2A200C51A63 /* Debug */, 1185 | 744F60BF239EE2A200C51A63 /* Release */, 1186 | ); 1187 | defaultConfigurationIsVisible = 0; 1188 | defaultConfigurationName = Release; 1189 | }; 1190 | 744F60CA239EE2D100C51A63 /* Build configuration list for PBXNativeTarget "SwiftMetal_tvOS" */ = { 1191 | isa = XCConfigurationList; 1192 | buildConfigurations = ( 1193 | 744F60CB239EE2D100C51A63 /* Debug */, 1194 | 744F60CC239EE2D100C51A63 /* Release */, 1195 | ); 1196 | defaultConfigurationIsVisible = 0; 1197 | defaultConfigurationName = Release; 1198 | }; 1199 | 744F6109239EEC4E00C51A63 /* Build configuration list for PBXNativeTarget "SwiftMetalTool" */ = { 1200 | isa = XCConfigurationList; 1201 | buildConfigurations = ( 1202 | 744F610A239EEC4E00C51A63 /* Debug */, 1203 | 744F610B239EEC4E00C51A63 /* Release */, 1204 | ); 1205 | defaultConfigurationIsVisible = 0; 1206 | defaultConfigurationName = Release; 1207 | }; 1208 | /* End XCConfigurationList section */ 1209 | }; 1210 | rootObject = 3A99C5EE239A4B20005BE419 /* Project object */; 1211 | } 1212 | --------------------------------------------------------------------------------