Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
0xLeif committed Dec 9, 2020
1 parent 042b1fa commit 5d01607
Show file tree
Hide file tree
Showing 9 changed files with 231 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "MetalUI",
platforms: [
.iOS(.v13),
.macOS(.v10_15)
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "MetalUI",
targets: ["MetalUI"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "MetalUI",
dependencies: []),
.testTarget(
name: "MetalUITests",
dependencies: ["MetalUI"]),
]
)
14 changes: 14 additions & 0 deletions Sources/MetalUI/Data/MetalRenderingVertex.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import MetalKit

public struct MetalRenderingVertex {
public var position: SIMD3<Float>
public var color: SIMD4<Float>

public init(
position: SIMD3<Float>,
color: SIMD4<Float>
) {
self.position = position
self.color = color
}
}
26 changes: 26 additions & 0 deletions Sources/MetalUI/MTKView/MetalPresenting.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import MetalKit

public protocol MetalPresenting: MTKView {
var renderer: MetalRendering! { get set }

init()

func configure(device: MTLDevice?)

func configureMTKView()
func renderer(forDevice device: MTLDevice) -> MetalRendering
}

public extension MetalPresenting {

func configure(device: MTLDevice? = MTLCreateSystemDefaultDevice()) {
// Make sure we are on a device that can run metal!
guard let defaultDevice = device else {
fatalError("Device loading error")
}

self.renderer = renderer(forDevice: defaultDevice)
self.delegate = renderer
self.configureMTKView()
}
}
38 changes: 38 additions & 0 deletions Sources/MetalUI/MTKViewDelegate/MetalRendering.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import MetalKit

public protocol MetalRendering: NSObject, MTKViewDelegate {
var commandQueue: MTLCommandQueue? { get set }
var renderPipelineState: MTLRenderPipelineState? { get set }
var vertexBuffer: MTLBuffer? { get set }

var vertices: [MetalRenderingVertex] { get set }

init()
init(
vertices: [MetalRenderingVertex],
device: MTLDevice
)

func createCommandQueue(device: MTLDevice)
func createPipelineState(
withLibrary library: MTLLibrary?,
forDevice device: MTLDevice
)
func createBuffers(device: MTLDevice)

// MARK: MTKViewDelegate
func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize)
func draw(in view: MTKView)
}

public extension MetalRendering {
init(vertices: [MetalRenderingVertex], device: MTLDevice) {
self.init()

self.vertices = vertices

createCommandQueue(device: device)
createPipelineState(withLibrary: device.makeDefaultLibrary(), forDevice: device)
createBuffers(device: device)
}
}
83 changes: 83 additions & 0 deletions Sources/MetalUI/SwiftUI/MetalView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import SwiftUI
import MetalKit

#if os(iOS)
public struct MetalView<Content>: UIViewRepresentable where Content: MetalPresenting {
public var wrappedView: Content

private var handleUpdateUIView: ((Content, Context) -> Void)?
private var handleMakeUIView: ((Context) -> Content)?

public init(closure: () -> Content) {
wrappedView = closure()
}

public func makeUIView(context: Context) -> Content {
guard let handler = handleMakeUIView else {
return wrappedView
}

return handler(context)
}

public func updateUIView(_ uiView: Content, context: Context) {
handleUpdateUIView?(uiView, context)
}
}

public extension MetalView {
mutating func setMakeUIView(handler: @escaping (Context) -> Content) -> Self {
handleMakeUIView = handler

return self
}

mutating func setUpdateUIView(handler: @escaping (Content, Context) -> Void) -> Self {
handleUpdateUIView = handler

return self
}
}
#elseif os(macOS)
public struct MetalView<Content>: NSViewRepresentable where Content: MetalPresenting {
public typealias NSViewType = Content

public var wrappedView: Content

private var handleUpdateNSView: ((Content, Context) -> Void)?
private var handleMakeNSView: ((Context) -> Content)?

public init(closure: () -> Content) {
wrappedView = closure()
}

public func makeNSView(context: Context) -> Content {
guard let handler = handleMakeNSView else {
return wrappedView
}

return handler(context)
}

public func updateNSView(_ nsView: Content, context: Context) {
handleUpdateNSView?(nsView, context)
}
}

public extension MetalView {
mutating func setMakeNSView(handler: @escaping (Context) -> Content) -> Self {
handleMakeNSView = handler

return self
}

mutating func setUpdateNSView(handler: @escaping (Content, Context) -> Void) -> Self {
handleUpdateNSView = handler

return self
}
}

#endif


7 changes: 7 additions & 0 deletions Tests/LinuxMain.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import XCTest

import MetalUITests

var tests = [XCTestCaseEntry]()
tests += MetalUITests.allTests()
XCTMain(tests)
15 changes: 15 additions & 0 deletions Tests/MetalUITests/MetalUITests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import XCTest
@testable import MetalUI

final class MetalUITests: XCTestCase {
func testExample() {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct
// results.
XCTAssertEqual("MetalUI().text", "Hello, World!")
}

static var allTests = [
("testExample", testExample),
]
}
9 changes: 9 additions & 0 deletions Tests/MetalUITests/XCTestManifests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import XCTest

#if !canImport(ObjectiveC)
public func allTests() -> [XCTestCaseEntry] {
return [
testCase(MetalUITests.allTests),
]
}
#endif

0 comments on commit 5d01607

Please sign in to comment.