diff --git a/README.md b/README.md index 4bf80c5..f025e1c 100644 --- a/README.md +++ b/README.md @@ -15,4 +15,5 @@ Repository to accompany the following blog posts: - [Using MetalKit part 11](http://mhorga.org/2016/05/10/using-metalkit-part-11.html) - [Using MetalKit part 12](http://mhorga.org/2016/05/18/using-metalkit-part-12.html) - [Using MetalKit part 13](http://mhorga.org/2016/05/25/using-metalkit-part-13.html) -- [Using MetalKit part 14](http://mhorga.org/2016/06/01/using-metalkit-part-14.html) \ No newline at end of file +- [Using MetalKit part 14](http://mhorga.org/2016/06/01/using-metalkit-part-14.html) +- [Using MetalKit part 15](http://mhorga.org/2016/06/23/using-metalkit-part-15.html) \ No newline at end of file diff --git a/ch15/chapter15.playground/Contents.swift b/ch15/chapter15.playground/Contents.swift new file mode 100755 index 0000000..366d424 --- /dev/null +++ b/ch15/chapter15.playground/Contents.swift @@ -0,0 +1,8 @@ + +import Cocoa +import XCPlayground + +let device = MTLCreateSystemDefaultDevice()! +let frame = NSRect(x:0, y:0, width:400, height:400) +let view = MetalView(frame: frame, device: device) +XCPlaygroundPage.currentPage.liveView = view diff --git a/ch15/chapter15.playground/Resources/Shaders.metal b/ch15/chapter15.playground/Resources/Shaders.metal new file mode 100755 index 0000000..83af2b1 --- /dev/null +++ b/ch15/chapter15.playground/Resources/Shaders.metal @@ -0,0 +1,30 @@ + +#include + +using namespace metal; + +kernel void compute(texture2d output [[texture(0)]], + texture2d input [[texture(1)]], + constant float &timer [[buffer(0)]], + uint2 gid [[thread_position_in_grid]]) +{ + int width = input.get_width(); + int height = input.get_height(); + float2 uv = float2(gid) / float2(width, height); + uv = uv * 2.0 - 1.0; + uv = uv * 2; + float radius = 1; + float distance = length(uv) - radius; + constexpr sampler textureSampler(coord::normalized, + address::repeat, + min_filter::linear, + mag_filter::linear, + mip_filter::linear ); + float3 norm = float3(uv, sqrt(1.0 - dot(uv, uv))); + float pi = 3.14; + float s = atan2( norm.z, norm.x ) / (2 * pi); + float t = asin( norm.y ) / (2 * pi); + t += 0.5; + float4 color = input.sample(textureSampler, float2(s + timer * 0.1, t)); + output.write(distance < 0 ? color : float4(0), gid); +} diff --git a/ch15/chapter15.playground/Resources/texture.jpg b/ch15/chapter15.playground/Resources/texture.jpg new file mode 100644 index 0000000..00075c9 Binary files /dev/null and b/ch15/chapter15.playground/Resources/texture.jpg differ diff --git a/ch15/chapter15.playground/Sources/MetalView.swift b/ch15/chapter15.playground/Sources/MetalView.swift new file mode 100755 index 0000000..fd4ce12 --- /dev/null +++ b/ch15/chapter15.playground/Sources/MetalView.swift @@ -0,0 +1,66 @@ + +import MetalKit + +public class MetalView: MTKView, NSWindowDelegate { + + var queue: MTLCommandQueue! = nil + var cps: MTLComputePipelineState! = nil + var timer: Float = 0 + var timerBuffer: MTLBuffer! + var texture: MTLTexture! + + required public init(coder: NSCoder) { + super.init(coder: coder) + } + + override public init(frame frameRect: CGRect, device: MTLDevice?) { + super.init(frame: frameRect, device: device) + registerShaders() + setUpTexture() + } + + func setUpTexture() { + let path = NSBundle.mainBundle().pathForResource("texture", ofType: "jpg") + let textureLoader = MTKTextureLoader(device: device!) + texture = try! textureLoader.newTextureWithContentsOfURL(NSURL(fileURLWithPath: path!), options: nil) + } + + override public func drawRect(dirtyRect: NSRect) { + if let drawable = currentDrawable { + let commandBuffer = queue.commandBuffer() + let commandEncoder = commandBuffer.computeCommandEncoder() + commandEncoder.setComputePipelineState(cps) + commandEncoder.setTexture(drawable.texture, atIndex: 0) + commandEncoder.setTexture(texture, atIndex: 1) + commandEncoder.setBuffer(timerBuffer, offset: 0, atIndex: 0) + update() + let threadGroupCount = MTLSizeMake(8, 8, 1) + let threadGroups = MTLSizeMake(drawable.texture.width / threadGroupCount.width, drawable.texture.height / threadGroupCount.height, 1) + commandEncoder.dispatchThreadgroups(threadGroups, threadsPerThreadgroup: threadGroupCount) + commandEncoder.endEncoding() + commandBuffer.presentDrawable(drawable) + commandBuffer.commit() + } + + } + + func update() { + timer += 0.01 + let bufferPointer = timerBuffer.contents() + memcpy(bufferPointer, &timer, sizeof(Float)) + } + + func registerShaders() { + queue = device!.newCommandQueue() + let path = NSBundle.mainBundle().pathForResource("Shaders", ofType: "metal") + do { + let input = try String(contentsOfFile: path!, encoding: NSUTF8StringEncoding) + let library = try device!.newLibraryWithSource(input, options: nil) + let kernel = library.newFunctionWithName("compute")! + cps = try device!.newComputePipelineStateWithFunction(kernel) + } catch let e { + Swift.print("\(e)") + } + timerBuffer = device!.newBufferWithLength(sizeof(Float), options: []) + } +} diff --git a/ch15/chapter15.playground/contents.xcplayground b/ch15/chapter15.playground/contents.xcplayground new file mode 100755 index 0000000..06828af --- /dev/null +++ b/ch15/chapter15.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/ch15/chapter15.playground/playground.xcworkspace/contents.xcworkspacedata b/ch15/chapter15.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100755 index 0000000..919434a --- /dev/null +++ b/ch15/chapter15.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ch15/chapter15.playground/playground.xcworkspace/xcuserdata/marius.xcuserdatad/UserInterfaceState.xcuserstate b/ch15/chapter15.playground/playground.xcworkspace/xcuserdata/marius.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100755 index 0000000..14e3d06 Binary files /dev/null and b/ch15/chapter15.playground/playground.xcworkspace/xcuserdata/marius.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/ch15/chapter15.playground/timeline.xctimeline b/ch15/chapter15.playground/timeline.xctimeline new file mode 100755 index 0000000..bf468af --- /dev/null +++ b/ch15/chapter15.playground/timeline.xctimeline @@ -0,0 +1,6 @@ + + + + +