diff --git a/Terrain.xcodeproj/project.pbxproj b/Terrain.xcodeproj/project.pbxproj index 5a82fac..4b1ee0d 100644 --- a/Terrain.xcodeproj/project.pbxproj +++ b/Terrain.xcodeproj/project.pbxproj @@ -11,6 +11,8 @@ C0C15A90218DDD87007494E2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C0C15A8F218DDD87007494E2 /* Assets.xcassets */; }; C0C15A93218DDD87007494E2 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = C0C15A91218DDD87007494E2 /* MainMenu.xib */; }; C0C15A9D218DDDC3007494E2 /* TerrainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0C15A9B218DDDC3007494E2 /* TerrainViewController.swift */; }; + C0C15AA0218DE0B2007494E2 /* Renderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0C15A9F218DE0B2007494E2 /* Renderer.swift */; }; + C0C15AA2218DE21E007494E2 /* Math.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0C15AA1218DE21E007494E2 /* Math.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -21,6 +23,8 @@ C0C15A94218DDD87007494E2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; C0C15A95218DDD87007494E2 /* Terrain.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Terrain.entitlements; sourceTree = ""; }; C0C15A9B218DDDC3007494E2 /* TerrainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerrainViewController.swift; sourceTree = ""; }; + C0C15A9F218DE0B2007494E2 /* Renderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Renderer.swift; sourceTree = ""; }; + C0C15AA1218DE21E007494E2 /* Math.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Math.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -55,6 +59,8 @@ children = ( C0C15A8D218DDD85007494E2 /* AppDelegate.swift */, C0C15A9B218DDDC3007494E2 /* TerrainViewController.swift */, + C0C15A9F218DE0B2007494E2 /* Renderer.swift */, + C0C15AA1218DE21E007494E2 /* Math.swift */, C0C15A8F218DDD87007494E2 /* Assets.xcassets */, C0C15A91218DDD87007494E2 /* MainMenu.xib */, C0C15A94218DDD87007494E2 /* Info.plist */, @@ -134,7 +140,9 @@ buildActionMask = 2147483647; files = ( C0C15A9D218DDDC3007494E2 /* TerrainViewController.swift in Sources */, + C0C15AA0218DE0B2007494E2 /* Renderer.swift in Sources */, C0C15A8E218DDD85007494E2 /* AppDelegate.swift in Sources */, + C0C15AA2218DE21E007494E2 /* Math.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Terrain/Math.swift b/Terrain/Math.swift new file mode 100644 index 0000000..66c016e --- /dev/null +++ b/Terrain/Math.swift @@ -0,0 +1,122 @@ +// +// Math.swift +// Metaballs +// +// Created by Eryn Wells on 9/22/18. +// Copyright © 2018 Eryn Wells. All rights reserved. +// + +import Cocoa +import Foundation +import simd + +public typealias Float2 = packed_float2 +public typealias Float3 = float3 +public typealias Float4 = float4 +public typealias Matrix2x2 = float2x2 +public typealias Matrix3x3 = float3x3 +public typealias Matrix4x4 = float4x4 + +extension Float2 { + var CGPoint: CGPoint { + return CoreGraphics.CGPoint(x: CGFloat(x), y: CGFloat(y)) + } +} + +extension Float2: CustomStringConvertible { + public var description: String { + return "(\(x), \(y))" + } +} + +extension Float3 { + func dot(other: Float3) -> Float3 { + return Float3(x * other.x, y * other.y, z * other.z) + } +} + +extension Float4 { + public init(r: Float, g: Float, b: Float, a: Float) { + self.init(r, g, b, a) + } + + public init(color: NSColor) { + if let convertedColor = color.usingColorSpace(NSColorSpace.deviceRGB) { + self.init(Float(convertedColor.redComponent), Float(convertedColor.greenComponent), Float(convertedColor.blueComponent), Float(convertedColor.alphaComponent)) + } else { + self.init() + } + } +} + +extension Matrix3x3 { + static func rotation(angle theta: Float) -> Matrix3x3 { + return self.init(rows: [ + Float3(cos(theta), -sin(theta), 0.0), + Float3(sin(theta), cos(theta), 0.0), + Float3(0, 0, 1), + ]) + } + + static func translation(dx: Float, dy: Float) -> Matrix3x3 { + var mat = self.init(1.0) + mat.columns.2.x = dx + mat.columns.2.y = dy + return mat + } + + static func scale(x: Float, y: Float) -> Matrix3x3 { + var mat = self.init(1.0) + mat.columns.0.x = x + mat.columns.1.y = y + return mat + } +} + +extension Matrix3x3 { + static func *(left: Matrix3x3, right: Matrix3x3) -> Matrix3x3 { + return matrix_multiply(left, right) + } +} + +extension Matrix4x4 { + /// Create a 4x4 orthographic projection matrix with the provided 6-tuple. + /// @see https://en.wikipedia.org/wiki/Orthographic_projection + static func orthographicProjection(top: Float32, left: Float32, bottom: Float32, right: Float32, near: Float32, far: Float32) -> Matrix4x4 { + let rows = [ + Float4(2.0 / (right - left), 0.0, 0.0, -(right + left) / (right - left)), + Float4(0.0, 2.0 / (top - bottom), 0.0, -(top + bottom) / (top - bottom)), + Float4(0.0, 0.0, -2.0 / (far - near), -(far + near) / (far - near)), + Float4(0.0, 0.0, 0.0, 1.0) + ] + return Matrix4x4(rows: rows) + } + + static func translation(dx: Float, dy: Float, dz: Float) -> Matrix4x4 { + var mat = self.init(1.0) + mat.columns.3.x = dx + mat.columns.3.y = dy + mat.columns.3.z = dz + return mat + } + + static func scale(x: Float, y: Float, z: Float) -> Matrix4x4 { + var mat = self.init(1.0) + mat.columns.0.x = x + mat.columns.1.y = y + mat.columns.2.z = z + return mat + } +} + +extension Matrix4x4 { + static func *(left: Matrix4x4, right: Matrix4x4) -> Matrix4x4 { + return matrix_multiply(left, right) + } +} + +extension CGSize { + init(size: Size) { + self.init(width: CGFloat(size.x), height: CGFloat(size.y)) + } +} diff --git a/Terrain/Renderer.swift b/Terrain/Renderer.swift new file mode 100644 index 0000000..d0de237 --- /dev/null +++ b/Terrain/Renderer.swift @@ -0,0 +1,23 @@ +// +// Renderer.swift +// Terrain +// +// Created by Eryn Wells on 11/3/18. +// Copyright © 2018 Eryn Wells. All rights reserved. +// + +import Cocoa +import Metal +import MetalKit + +class Renderer: NSObject, MTKViewDelegate { + + func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) { + print("Size of \(view.debugDescription) will change to \(size)") + } + + func draw(in view: MTKView) { + // TODO. + } + +} diff --git a/Terrain/TerrainViewController.swift b/Terrain/TerrainViewController.swift index 6e7cc22..a00e139 100644 --- a/Terrain/TerrainViewController.swift +++ b/Terrain/TerrainViewController.swift @@ -11,6 +11,8 @@ import MetalKit class TerrainViewController: NSViewController { + let renderer = Renderer() + private var metalView: MTKView! { return view as? MTKView } @@ -23,6 +25,7 @@ class TerrainViewController: NSViewController { v.translatesAutoresizingMaskIntoConstraints = false v.widthAnchor.constraint(greaterThanOrEqualToConstant: 640).isActive = true v.heightAnchor.constraint(greaterThanOrEqualToConstant: 480).isActive = true + v.delegate = renderer view = v }