diff --git a/.gitignore b/.gitignore index bda6654..2678d02 100644 --- a/.gitignore +++ b/.gitignore @@ -89,3 +89,4 @@ fastlane/test_output iOSInjectionProject/ *.DS_Store +*.swiftpm diff --git a/Sources/SIMDTools/Angle.swift b/Sources/SIMDTools/Angle.swift index a3afe12..f65792c 100644 --- a/Sources/SIMDTools/Angle.swift +++ b/Sources/SIMDTools/Angle.swift @@ -13,15 +13,19 @@ public struct Angle { } /// Creates an instance using the value in radians + /// - Parameter radians: The angle value in radians public init(radians val: Float32) { degrees = val / Float32.pi * 180.0 } /// Creates an instance using the value in degrees + /// - Parameter degrees: The angle value in degrees public init(degrees val: Float32) { degrees = val } + /// Creates an instance using an internal value + /// - Parameter val: The angle value internal init(_ val: Float32) { degrees = val } @@ -66,56 +70,105 @@ extension Angle { // MARK: multiplication (scaling) + /// Multiplies the angle by a scalar value + /// - Parameters: + /// - lhs: The angle to be multiplied + /// - rhs: The scalar value public static func *=(lhs: inout Angle, rhs: Float32) { lhs = Angle(lhs.degrees * rhs) } + /// Multiplies the angle by a scalar value + /// - Parameters: + /// - lhs: The angle to be multiplied + /// - rhs: The scalar value + /// - Returns: The resulting angle after multiplication public static func *(lhs: Angle, rhs: Float32) -> Angle { return Angle(lhs.degrees * rhs) } + /// Multiplies a scalar value by an angle + /// - Parameters: + /// - lhs: The scalar value + /// - rhs: The angle to be multiplied + /// - Returns: The resulting angle after multiplication public static func *(lhs: Float32, rhs: Angle) -> Angle { return Angle(rhs.degrees * lhs) } // MARK: division (scaling) + /// Divides the angle by a scalar value + /// - Parameters: + /// - lhs: The angle to be divided + /// - rhs: The scalar value public static func /=(lhs: inout Angle, rhs: Float32) { lhs = Angle(lhs.degrees / rhs) } + /// Divides the angle by a scalar value + /// - Parameters: + /// - lhs: The angle to be divided + /// - rhs: The scalar value + /// - Returns: The resulting angle after division public static func /(lhs: Angle, rhs: Float32) -> Angle { return Angle(lhs.degrees / rhs) } // MARK: addition + /// Adds two angles together + /// - Parameters: + /// - lhs: The first angle + /// - rhs: The second angle public static func +=(lhs: inout Angle, rhs: Angle) { lhs = Angle(lhs.degrees + rhs.degrees) } + /// Adds two angles together + /// - Parameters: + /// - lhs: The first angle + /// - rhs: The second angle + /// - Returns: The resulting angle after addition public static func +(lhs: Angle, rhs: Angle) -> Angle { return Angle(lhs.degrees + rhs.degrees) } // MARK: subtraction + /// Subtracts one angle from another + /// - Parameters: + /// - lhs: The first angle + /// - rhs: The second angle public static func -=(lhs: inout Angle, rhs: Angle) { lhs = Angle(lhs.degrees - rhs.degrees) } + /// Subtracts one angle from another + /// - Parameters: + /// - lhs: The first angle + /// - rhs: The second angle + /// - Returns: The resulting angle after subtraction public static func -(lhs: Angle, rhs: Angle) -> Angle { return Angle(lhs.degrees - rhs.degrees) } // MARK: Modulus + /// Returns the remainder of one angle divided by another + /// - Parameters: + /// - lhs: The first angle + /// - rhs: The second angle + /// - Returns: The remainder angle after division public static func %(lhs: Angle, rhs: Angle) -> Angle { return Angle(lhs.degrees.truncatingRemainder(dividingBy: rhs.degrees)) } // MARK: Unary + /// Returns the negation of the angle + /// - Parameter lhs: The angle to be negated + /// - Returns: The negated angle public static prefix func -(lhs: Angle) -> Angle { return Angle(-lhs.degrees) } @@ -149,10 +202,18 @@ extension Angle: Comparable { } } +/// Computes the sine and cosine of the given angle +/// - Parameters: +/// - a: The angle +/// - sina: A reference to a variable to store the sine of the angle +/// - cosa: A reference to a variable to store the cosine of the angle public func sincos(_ a: Angle, _ sina: inout Float, _ cosa: inout Float) { __sincospif(a.degrees / 180.0, &sina, &cosa) } +/// Computes the sine and cosine of the given angle +/// - Parameter a: The angle +/// - Returns: A tuple containing the sine and cosine of the angle public func sincos(_ a: Angle) -> (sin: Float, cos: Float) { var s: Float = 0.0 var c: Float = 0.0 @@ -161,14 +222,23 @@ public func sincos(_ a: Angle) -> (sin: Float, cos: Float) { return (sin: s, cos: c) } +/// Computes the sine of the given angle +/// - Parameter a: The angle +/// - Returns: The sine of the angle public func sin(_ a: Angle) -> Float { return __sinpif(a.degrees / 180.0) } +/// Computes the cosine of the given angle +/// - Parameter a: The angle +/// - Returns: The cosine of the angle public func cos(_ a: Angle) -> Float { return __cospif(a.degrees / 180.0) } +/// Computes the tangent of the given angle +/// - Parameter a: The angle +/// - Returns: The tangent of the angle public func tan(_ a: Angle) -> Float { return __tanpif(a.degrees / 180.0) } diff --git a/Sources/SIMDTools/Helpers.swift b/Sources/SIMDTools/Helpers.swift index bdb7149..c0880e6 100644 --- a/Sources/SIMDTools/Helpers.swift +++ b/Sources/SIMDTools/Helpers.swift @@ -1,24 +1,26 @@ -/// Returns x, such that min ≤ x ≤ max -/// -/// - parameter x: value to be clamped -/// - parameter min: minimum -/// - parameter max: maximum +/// Clamps a value to the specified range +/// - Parameters: +/// - x: The value to be clamped +/// - min: The minimum value +/// - max: The maximum value +/// - Returns: The clamped value public func clamp(_ x: T, min _min: T, max _max: T) -> T where T: Comparable { return min(max(x, _min), _max) } -/// Returns x, where 0.0 ≤ x ≤ 1.0 +/// Clamps a value to the range [0.0, 1.0] +/// - Parameter x: The value to be clamped +/// - Returns: The clamped value public func saturate(_ x: T) -> T where T: BinaryFloatingPoint { return clamp(x, min: 0.0, max: 1.0) } -/// Performs a linear interpolation between a and b by the interpolant t -/// -/// - parameter a: start value -/// - parameter b: end value -/// - parameter t: interpolant -/// -/// - returns: a value interpolated from a to b -public func interpolate(a: T, b: T, t: T) -> T where T: BinaryFloatingPoint { +/// Performs a linear interpolation between two values +/// - Parameters: +/// - a: The start value +/// - b: The end value +/// - t: The interpolant +/// - Returns: A value interpolated from a to b +public func interpolate(a: T, b: T, t: T) -> T where T: BinaryFloatingPoint { return a + (b - a) * t } diff --git a/Sources/SIMDTools/SIMDTools.docc/HelperFunctions.md b/Sources/SIMDTools/SIMDTools.docc/HelperFunctions.md new file mode 100644 index 0000000..dc29538 --- /dev/null +++ b/Sources/SIMDTools/SIMDTools.docc/HelperFunctions.md @@ -0,0 +1,30 @@ +# Helper Functions + +## Clamping Values + +Clamp a value to a specified range: + +```swift +let clampedValue = clamp(5, min: 1, max: 10) // 5 +let clampedValue2 = clamp(15, min: 1, max: 10) // 10 +``` + +## Saturating Values + +Saturate a value to the range [0.0, 1.0]: + +```swift +let saturatedValue = saturate(1.5) // 1.0 +let saturatedValue2 = saturate(-0.5) // 0.0 +``` + +## Linear Interpolation + +Perform a linear interpolation between two values: + +```swift +let start: Float = 0.0 +let end: Float = 10.0 +let t: Float = 0.5 +let interpolatedValue = interpolate(a: start, b: end, t: t) // 5.0 +``` diff --git a/Sources/SIMDTools/SIMDTools.docc/Resources/documentation-art/simd-tools@2x.png b/Sources/SIMDTools/SIMDTools.docc/Resources/documentation-art/simd-tools@2x.png new file mode 100644 index 0000000..077b6f0 Binary files /dev/null and b/Sources/SIMDTools/SIMDTools.docc/Resources/documentation-art/simd-tools@2x.png differ diff --git a/Sources/SIMDTools/SIMDTools.docc/Resources/rotate-image-art/preview-01-creating-code-04-06@2x.png b/Sources/SIMDTools/SIMDTools.docc/Resources/rotate-image-art/preview-01-creating-code-04-06@2x.png new file mode 100644 index 0000000..f05b29f Binary files /dev/null and b/Sources/SIMDTools/SIMDTools.docc/Resources/rotate-image-art/preview-01-creating-code-04-06@2x.png differ diff --git a/Sources/SIMDTools/SIMDTools.docc/Resources/rotate-image-art/preview-01-creating-code-04-06~dark@2x.png b/Sources/SIMDTools/SIMDTools.docc/Resources/rotate-image-art/preview-01-creating-code-04-06~dark@2x.png new file mode 100644 index 0000000..befbb15 Binary files /dev/null and b/Sources/SIMDTools/SIMDTools.docc/Resources/rotate-image-art/preview-01-creating-code-04-06~dark@2x.png differ diff --git a/Sources/SIMDTools/SIMDTools.docc/Resources/rotate-image-art/select-interface-type~dark@2x.png b/Sources/SIMDTools/SIMDTools.docc/Resources/rotate-image-art/select-interface-type~dark@2x.png index 15c5177..7f11602 100644 Binary files a/Sources/SIMDTools/SIMDTools.docc/Resources/rotate-image-art/select-interface-type~dark@2x.png and b/Sources/SIMDTools/SIMDTools.docc/Resources/rotate-image-art/select-interface-type~dark@2x.png differ diff --git a/Sources/SIMDTools/SIMDTools.docc/SIMDTools.md b/Sources/SIMDTools/SIMDTools.docc/SIMDTools.md index ddbb762..0b681bd 100644 --- a/Sources/SIMDTools/SIMDTools.docc/SIMDTools.md +++ b/Sources/SIMDTools/SIMDTools.docc/SIMDTools.md @@ -1,6 +1,8 @@ # ``SIMDTools`` -Welcome to the documentation for the `simd-tools` Swift package. This package provides utility functions and extensions for working with SIMD matrices and vectors in Swift. +![SIMDTools](simd-tools.png) + +Welcome to the documentation for the `SIMDTools` Swift package. This package provides utility functions and extensions for working with SIMD matrices and vectors in Swift. ## Overview @@ -11,11 +13,14 @@ The `simd-tools` package includes: ## Topics -### Getting Started +### Essentials -- +- -### Reference +### Usage -- ``Angle`` +- +- +- +- diff --git a/Sources/SIMDTools/SIMDTools.docc/Tutorials/RotatingImageInSwiftUI.tutorial b/Sources/SIMDTools/SIMDTools.docc/Tutorials/ApplyingAffineTransformsToSwiftUIViewsWithMetal.tutorial similarity index 83% rename from Sources/SIMDTools/SIMDTools.docc/Tutorials/RotatingImageInSwiftUI.tutorial rename to Sources/SIMDTools/SIMDTools.docc/Tutorials/ApplyingAffineTransformsToSwiftUIViewsWithMetal.tutorial index 73da006..3d28d32 100644 --- a/Sources/SIMDTools/SIMDTools.docc/Tutorials/RotatingImageInSwiftUI.tutorial +++ b/Sources/SIMDTools/SIMDTools.docc/Tutorials/ApplyingAffineTransformsToSwiftUIViewsWithMetal.tutorial @@ -1,6 +1,6 @@ @Tutorial(time: 30) { - @Intro(title: "Rotating images in SwiftUI") { - This tutorial guides you through building a simple SwiftUI demo app that will demostrate you how to use SwiftUI layer effects to apply affine transform to images. You'll start by building the content view. + @Intro(title: "Applying Affine Transforms To SwiftUI Views With Metal") { + This tutorial guides you through building a simple SwiftUI demo app that will demostrate you how to use SwiftUI layer effects to apply affine transform to a view. You'll start by building the content view. @Image(source: creating-intro.png, alt: "") } @@ -197,37 +197,51 @@ @Step { Now its time to create the transform that will rotate the image. Let's start with adding a dedicated function. - @Code(name: "ContentView.swift", file: 01-creating-code-04-01.swift) + @Code(name: "ContentView.swift", file: 01-creating-code-04-01.swift) { + @Image(source: preview-01-creating-code-02-08.png, alt: "A screenshot from the Xcode preview as it would appear on iPhone, with colored gear image and a rotatio degrees label, centered in the middle of the display.") + } } @Step { Create the `angle` variable of `Angle` type from `SIMDTools`. - @Code(name: "ContentView.swift", file: 01-creating-code-04-02.swift) + @Code(name: "ContentView.swift", file: 01-creating-code-04-02.swift) { + @Image(source: preview-01-creating-code-02-08.png, alt: "A screenshot from the Xcode preview as it would appear on iPhone, with colored gear image and a rotatio degrees label, centered in the middle of the display.") + } } @Step { Calculate an offset that will be used in the pre- post-transforms. - @Code(name: "ContentView.swift", file: 01-creating-code-04-03.swift) + @Code(name: "ContentView.swift", file: 01-creating-code-04-03.swift) { + @Image(source: preview-01-creating-code-02-08.png, alt: "A screenshot from the Xcode preview as it would appear on iPhone, with colored gear image and a rotatio degrees label, centered in the middle of the display.") + } } @Step { Create the transform by multiplying pre-, rotation and post-transform using convenience functions from `SIMDTools`. - @Code(name: "ContentView.swift", file: 01-creating-code-04-04.swift) + The transforms are applied from right to left: `.translate(value: -offset)` is the translation to the center, `.rotate(angle: angle)` is the rotation around the center, `.translate(value: offset)` is the translation back to the original position. + + @Code(name: "ContentView.swift", file: 01-creating-code-04-04.swift) { + @Image(source: preview-01-creating-code-02-08.png, alt: "A screenshot from the Xcode preview as it would appear on iPhone, with colored gear image and a rotatio degrees label, centered in the middle of the display.") + } } @Step { Decompose the transform into the array of floats. - @Code(name: "ContentView.swift", file: 01-creating-code-04-05.swift) + @Code(name: "ContentView.swift", file: 01-creating-code-04-05.swift) { + @Image(source: preview-01-creating-code-02-08.png, alt: "A screenshot from the Xcode preview as it would appear on iPhone, with colored gear image and a rotatio degrees label, centered in the middle of the display.") + } } @Step { - Apply layerEffect to the image. + Apply layerEffect to the image view. - @Code(name: "ContentView.swift", file: 01-creating-code-04-06.swift) + @Code(name: "ContentView.swift", file: 01-creating-code-04-06.swift) { + @Image(source: preview-01-creating-code-04-06.png, alt: "A screenshot from the Xcode preview as it would appear on iPhone, with colored gear image and a rotatio degrees label, centered in the middle of the display.") + } } } } diff --git a/Sources/SIMDTools/SIMDTools.docc/Tutorials/SIMDTools.tutorial b/Sources/SIMDTools/SIMDTools.docc/Tutorials/SIMDTools.tutorial index ca615bb..66b6c56 100644 --- a/Sources/SIMDTools/SIMDTools.docc/Tutorials/SIMDTools.tutorial +++ b/Sources/SIMDTools/SIMDTools.docc/Tutorials/SIMDTools.tutorial @@ -1,15 +1,15 @@ @Tutorials(name: "SIMDTools") { @Intro(title: "Meet SIMDTools") { - Learn how to use SIMD matrices to calculate affine transform for rotating images. Get started with SIMDTools by buildiong the demo app _RotateImage_. + Learn how to use SIMD matrices to calculate affine transform for rotating SwiftUI views. Get started with SIMDTools by building the demo app _RotateImage_. @Image(source: simd-tools.png, alt: "SIMDTools icon.") }  - @Chapter(name: "Rotating Image In SwiftUI") { + @Chapter(name: "SIMDTools Essentials") { @Image(source: chapter1-rotate-image.png, alt: "Rotate Image app main sceen.") Construct a rotation affine transform using SIMDTools and apply it to rotate an image. - @TutorialReference(tutorial: "doc:RotatingImageInSwiftUI") + @TutorialReference(tutorial: "doc:ApplyingAffineTransformsToSwiftUIViewsWithMetal") } } diff --git a/Sources/SIMDTools/SIMDTools.docc/UsingAngle.md b/Sources/SIMDTools/SIMDTools.docc/UsingAngle.md deleted file mode 100644 index 432c03d..0000000 --- a/Sources/SIMDTools/SIMDTools.docc/UsingAngle.md +++ /dev/null @@ -1,12 +0,0 @@ -# Using Angle - -The `Angle` struct provides a convenient way to represent and manipulate angles in both degrees and radians. - -## Creating an Angle - -You can create an angle using degrees or radians: - -```swift -let angleInDegrees = Angle(degrees: 45) -let angleInRadians = Angle(radians: .pi / 4) - diff --git a/Sources/SIMDTools/SIMDTools.docc/WorkingWith3x3Matrices.md b/Sources/SIMDTools/SIMDTools.docc/WorkingWith3x3Matrices.md new file mode 100644 index 0000000..28ba362 --- /dev/null +++ b/Sources/SIMDTools/SIMDTools.docc/WorkingWith3x3Matrices.md @@ -0,0 +1,49 @@ +# Working with 3x3 Matrices + +## Identity Matrix + +Get the identity matrix: + +```swift +let identityMatrix = float3x3.identity +``` + +## Translation Matrix + +Create a translation matrix: + +```swift +let translation = float3x3.translate(value: SIMD2(x: 10, y: 5)) +``` + +## Rotation Matrix + +Create a rotation matrix: + +```swift +let rotation = float3x3.rotate(angle: Angle(degrees: 45)) +``` + +## Scaling Matrix + +Create a scaling matrix: + +```swift +let scaling = float3x3.scale(value: SIMD2(x: 2, y: 3)) +``` + +## Codable Support + +Encode and decode float3x3 matrices: + +```swift +let matrix = float3x3.identity + +// Encoding +let encoder = JSONEncoder() +let encodedData = try encoder.encode(matrix) + +// Decoding +let decoder = JSONDecoder() +let decodedMatrix = try decoder.decode(float3x3.self, from: encodedData) +``` diff --git a/Sources/SIMDTools/SIMDTools.docc/WorkingWith4x4Matrices.md b/Sources/SIMDTools/SIMDTools.docc/WorkingWith4x4Matrices.md new file mode 100644 index 0000000..db6119d --- /dev/null +++ b/Sources/SIMDTools/SIMDTools.docc/WorkingWith4x4Matrices.md @@ -0,0 +1,85 @@ +# Working with 4x4 Matrices + +## Identity Matrix + +Get the identity matrix: + +```swift +let identityMatrix = float4x4.identity +``` + +## Translation Matrix + +Create a translation matrix: + +```swift +let translation = float4x4.translate(value: SIMD3(x: 10, y: 5, z: 3)) +``` + +## Rotation Matrix + +Create a rotation matrix: + +```swift +let rotationX = float4x4.rotate(x: Angle(degrees: 45)) +let rotationY = float4x4.rotate(y: Angle(degrees: 45)) +let rotationZ = float4x4.rotate(z: Angle(degrees: 45)) +let rotationXYZ = float4x4.rotate( + x: Angle(degrees: 45), + y: Angle(degrees: 45), + z: Angle(degrees: 45) +) +``` + +## Scaling Matrix + +Create a scaling matrix: + +```swift +let scaling = float4x4.scale(value: SIMD3(x: 2, y: 3, z: 4)) +``` + +## Shearing Matrix + +Create shearing matrices: + +```swift +let shearXY = float4x4.shear(xy: SIMD2(x: 1, y: 0.5)) +let shearXZ = float4x4.shear(xz: SIMD2(x: 1, y: 0.5)) +let shearYZ = float4x4.shear(yz: SIMD2(x: 1, y: 0.5)) +``` + +## Matrix Operations + +Create view and projection matrices: + +```swift +let eye = SIMD3(x: 0, y: 0, z: 5) +let center = SIMD3(x: 0, y: 0, z: 0) +let up = SIMD3(x: 0, y: 1, z: 0) +let viewMatrix = float4x4.lookAt(eye: eye, at: center, up: up) + +let fovy = Angle(degrees: 60) +let aspectRatio: Float32 = 16.0 / 9.0 +let near: Float32 = 0.1 +let far: Float32 = 100.0 +let projectionMatrix = float4x4.proj(fovy: fovy, aspect: aspectRatio, near: near, far: far) +``` + + + +## Codable Support + +Encode and decode float4x4 matrices: + +```swift +let matrix = float4x4.identity + +// Encoding +let encoder = JSONEncoder() +let encodedData = try encoder.encode(matrix) + +// Decoding +let decoder = JSONDecoder() +let decodedMatrix = try decoder.decode(float4x4.self, from: encodedData) +``` diff --git a/Sources/SIMDTools/SIMDTools.docc/WorkingWithAngles.md b/Sources/SIMDTools/SIMDTools.docc/WorkingWithAngles.md new file mode 100644 index 0000000..3bd34e9 --- /dev/null +++ b/Sources/SIMDTools/SIMDTools.docc/WorkingWithAngles.md @@ -0,0 +1,74 @@ +# Working with Angles + +## Creating Angles + +You can create an angle using degrees or radians: + +```swift +let angleInDegrees = Angle(degrees: 45) +let angleInRadians = Angle(radians: .pi / 4) +``` + +## Accessing Angle Values + +Retrieve the angle value in degrees or radians: + +```swift +let degrees = angleInDegrees.degrees // 45.0 +let radians = angleInDegrees.radians // 0.7853982 +``` + +## Arithmetic Operations + +Perform arithmetic operations with angles: + +```swift +let angle1 = Angle(degrees: 30) +let angle2 = Angle(degrees: 60) + +let sum = angle1 + angle2 // 90 degrees +let difference = angle2 - angle1 // 30 degrees +let scaledAngle = angle1 * 2 // 60 degrees +let dividedAngle = angle2 / 2 // 30 degrees +``` + +## Trigonometric Functions + +Compute sine, cosine, and tangent of an angle: + +```swift +let angle = Angle(degrees: 45) +let sine = sin(angle) // 0.70710677 +let cosine = cos(angle) // 0.70710677 +let tangent = tan(angle) // 1.0 + +let (sine, cosine) = sincos(angle) // (0.70710677, 0.70710677) +``` + +## Comparison Operators + +Compare angles: + +```swift +let angle1 = Angle(degrees: 45) +let angle2 = Angle(degrees: 90) + +if angle1 < angle2 { + print("\(angle1) is less than \(angle2)") +} + +if angle1 == Angle(degrees: 45) { + print("\(angle1) is equal to 45 degrees") +} + +``` + +## Constants + +Use predefined angle constants: + +```swift +let zeroAngle = Angle.zero +let rightAngle = Angle.pi_2 +let fullCircle = Angle.pi2 +``` diff --git a/Sources/SIMDTools/float3x3+Extensions.swift b/Sources/SIMDTools/float3x3+Extensions.swift index 63ceaeb..94fe55a 100644 --- a/Sources/SIMDTools/float3x3+Extensions.swift +++ b/Sources/SIMDTools/float3x3+Extensions.swift @@ -3,12 +3,12 @@ import simd public extension float3x3 { // MARK: - Identity - + /// Returns the identity matrix static let identity = matrix_identity_float3x3 // MARK: - Translate - + /// Returns a translation matrix /// - Parameter value: the translation value /// - Returns: a new translation matrix @@ -35,7 +35,7 @@ public extension float3x3 { } // MARK: - Scale - + /// Returns a scaling matrix /// - Parameter value: the scaling value /// - Returns: a new scaling matrix @@ -55,6 +55,9 @@ extension float3x3: Codable { case column1, column2, column3 } + /// Initializes a `float3x3` instance from a decoder + /// - Parameter decoder: The decoder to read data from + /// - Throws: An error if reading from the decoder fails public init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKey.self) let c1 = try values.decode(SIMD3.self, forKey: .column1) @@ -64,6 +67,9 @@ extension float3x3: Codable { self.init(c1, c2, c3) } + /// Encodes a `float3x3` instance into an encoder + /// - Parameter encoder: The encoder to write data to + /// - Throws: An error if encoding fails public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKey.self) try container.encode(self.columns.0, forKey: .column1) diff --git a/Sources/SIMDTools/float4x4+Extensions.swift b/Sources/SIMDTools/float4x4+Extensions.swift index 33e4857..c92a85a 100644 --- a/Sources/SIMDTools/float4x4+Extensions.swift +++ b/Sources/SIMDTools/float4x4+Extensions.swift @@ -3,12 +3,12 @@ import simd public extension float4x4 { // MARK: - Identity - + /// Returns the identity matrix static let identity = matrix_identity_float4x4 // MARK: - Translate - + /// Returns a translation matrix /// - Parameter value: the translation value /// - Returns: a new translation matrix @@ -48,7 +48,7 @@ public extension float4x4 { [0, 0, 0, 1] ) } - + /// Returns a transformation matrix that rotates around the z axis /// - Parameter z: angle /// - Returns: a new rotation matrix @@ -82,6 +82,9 @@ public extension float4x4 { // MARK: - Scale + /// Returns a scaling matrix + /// - Parameter value: The scaling values for x, y, and z axes + /// - Returns: A new scaling matrix static func scale(value: SIMD3) -> float4x4 { float4x4( [value.x, 0, 0, 0], @@ -131,6 +134,12 @@ public extension float4x4 { // MARK: - Matrix Operations + /// Creates a view matrix for a left-handed coordinate system + /// - Parameters: + /// - eye: The position of the camera + /// - at: The position to look at + /// - up: The up direction of the camera + /// - Returns: A left-handed view matrix static func lookAt( eye: SIMD3, at: SIMD3, @@ -143,6 +152,12 @@ public extension float4x4 { ) } + /// Creates a left-handed view matrix + /// - Parameters: + /// - eye: The position of the camera + /// - at: The position to look at + /// - up: The up direction of the camera + /// - Returns: A left-handed view matrix static func lookAtLH( eye: SIMD3, at: SIMD3, up: SIMD3 @@ -155,6 +170,12 @@ public extension float4x4 { ) } + /// Creates a view matrix + /// - Parameters: + /// - eye: The position of the camera + /// - view: The direction to look at + /// - up: The up direction of the camera + /// - Returns: A view matrix static func lookAt( eye: SIMD3, view: SIMD3, @@ -171,6 +192,12 @@ public extension float4x4 { } /// Creates a left-handed perspective projection matrix + /// - Parameters: + /// - fovy: The field of view in the y direction, in degrees + /// - aspect: The aspect ratio of the view + /// - near: The distance to the near clipping plane + /// - far: The distance to the far clipping plane + /// - Returns: A left-handed perspective projection matrix static func proj( fovy: Angle, aspect: Float32, @@ -190,6 +217,14 @@ public extension float4x4 { } /// Creates a left-handed perspective projection matrix + /// - Parameters: + /// - x: The x coordinate of the view + /// - y: The y coordinate of the view + /// - w: The width of the view + /// - h: The height of the view + /// - near: The distance to the near clipping plane + /// - far: The distance to the far clipping plane + /// - Returns: A left-handed perspective projection matrix static func projLH( x: Float32, y: Float32, @@ -210,6 +245,14 @@ public extension float4x4 { } /// Creates a right-handed perspective projection matrix + /// - Parameters: + /// - x: The x coordinate of the view + /// - y: The y coordinate of the view + /// - w: The width of the view + /// - h: The height of the view + /// - near: The distance to the near clipping plane + /// - far: The distance to the far clipping plane + /// - Returns: A right-handed perspective projection matrix static func projRH( x: Float, y: Float, @@ -230,6 +273,14 @@ public extension float4x4 { } /// Creates a left-handed orthographic projection matrix + /// - Parameters: + /// - left: The left coordinate of the view + /// - right: The right coordinate of the view + /// - bottom: The bottom coordinate of the view + /// - top: The top coordinate of the view + /// - near: The distance to the near clipping plane + /// - far: The distance to the far clipping plane + /// - Returns: A left-handed orthographic projection matrix static func ortho( left: Float, right: Float, @@ -249,6 +300,15 @@ public extension float4x4 { } /// Creates a left-handed orthographic projection matrix + /// - Parameters: + /// - left: The left coordinate of the view + /// - right: The right coordinate of the view + /// - bottom: The bottom coordinate of the view + /// - top: The top coordinate of the view + /// - near: The distance to the near clipping plane + /// - far: The distance to the far clipping plane + /// - offset: An offset value for the projection matrix + /// - Returns: A left-handed orthographic projection matrix static func orthoLH( left: Float, right: Float, @@ -273,6 +333,15 @@ public extension float4x4 { } /// Creates a right-handed orthographic projection matrix + /// - Parameters: + /// - left: The left coordinate of the view + /// - right: The right coordinate of the view + /// - bottom: The bottom coordinate of the view + /// - top: The top coordinate of the view + /// - near: The distance to the near clipping plane + /// - far: The distance to the far clipping plane + /// - offset: An offset value for the projection matrix + /// - Returns: A right-handed orthographic projection matrix static func orthoRH( left: Float, right: Float, @@ -304,6 +373,9 @@ extension float4x4: Codable { case column1, column2, column3, column4 } + /// Initializes a `float4x4` instance from a decoder + /// - Parameter decoder: The decoder to read data from + /// - Throws: An error if reading from the decoder fails public init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKey.self) let c1 = try values.decode(SIMD4.self, forKey: .column1) @@ -314,6 +386,9 @@ extension float4x4: Codable { self.init(c1, c2, c3, c4) } + /// Encodes a `float4x4` instance into an encoder + /// - Parameter encoder: The encoder to write data to + /// - Throws: An error if encoding fails public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKey.self) try container.encode(self.columns.0, forKey: .column1) diff --git a/Tests/SIMDToolsTests/Float3x3Tests.swift b/Tests/SIMDToolsTests/Float3x3Tests.swift index 34a13b3..256cf93 100644 --- a/Tests/SIMDToolsTests/Float3x3Tests.swift +++ b/Tests/SIMDToolsTests/Float3x3Tests.swift @@ -1,4 +1,5 @@ import XCTest +import simd @testable import SIMDTools class Float3x3Tests: XCTestCase { diff --git a/Tests/SIMDToolsTests/Float4x4Tests.swift b/Tests/SIMDToolsTests/Float4x4Tests.swift index c65c1ac..8da451b 100644 --- a/Tests/SIMDToolsTests/Float4x4Tests.swift +++ b/Tests/SIMDToolsTests/Float4x4Tests.swift @@ -1,4 +1,5 @@ import XCTest +import simd @testable import SIMDTools class Float4x4Tests: XCTestCase { diff --git a/Tests/SIMDToolsTests/SIMDToolsTests.swift b/Tests/SIMDToolsTests/SIMDToolsTests.swift index de671de..83b560d 100644 --- a/Tests/SIMDToolsTests/SIMDToolsTests.swift +++ b/Tests/SIMDToolsTests/SIMDToolsTests.swift @@ -1,4 +1,5 @@ import XCTest +import simd @testable import SIMDTools final class SIMDToolsTests: XCTestCase {