Skip to content

Commit d935051

Browse files
committed
Move over some SIMD extensions from KojaServ, and collate into a single file
1 parent 4c938eb commit d935051

File tree

2 files changed

+134
-111
lines changed

2 files changed

+134
-111
lines changed
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
//
2+
// SIMD.swift
3+
// allonet2
4+
//
5+
// Created by Nevyn Bengtsson on 2025-11-20.
6+
//
7+
8+
import simd
9+
10+
public extension simd_float3x3 {
11+
static func * (lhs: simd_float3x3, rhs: SIMD2<Float>) -> SIMD2<Float> {
12+
let vec3 = SIMD3<Float>(rhs, 1)
13+
let transformed = lhs * vec3
14+
return transformed.xy
15+
}
16+
}
17+
18+
extension simd_float4x4 : Codable
19+
{
20+
public func encode(to encoder: Encoder) throws
21+
{
22+
var container = encoder.unkeyedContainer()
23+
// Encode in row-major order: for each row, encode all columns.
24+
for row in 0..<4
25+
{
26+
for col in 0..<4
27+
{
28+
try container.encode(self[col][row])
29+
}
30+
}
31+
}
32+
33+
public init(from decoder: Decoder) throws
34+
{
35+
var container = try decoder.unkeyedContainer()
36+
var matrix = simd_float4x4()
37+
// Decode in row-major order.
38+
for row in 0..<4
39+
{
40+
for col in 0..<4
41+
{
42+
let value = try container.decode(Float.self)
43+
matrix[col][row] = value
44+
}
45+
}
46+
self = matrix
47+
}
48+
}
49+
50+
extension simd_float4x4 {
51+
public static var identity: simd_float4x4 {
52+
return matrix_identity_float4x4
53+
}
54+
public var translation: SIMD3<Float> {
55+
get {
56+
return SIMD3<Float>(columns.3.x, columns.3.y, columns.3.z)
57+
}
58+
set {
59+
columns.3 = SIMD4<Float>(newValue.x, newValue.y, newValue.z, columns.3.w)
60+
}
61+
}
62+
63+
public var scale: SIMD3<Float> {
64+
get {
65+
// The scale is the length of each column vector (ignoring the homogeneous component).
66+
let scaleX = length(SIMD3<Float>(columns.0.x, columns.0.y, columns.0.z))
67+
let scaleY = length(SIMD3<Float>(columns.1.x, columns.1.y, columns.1.z))
68+
let scaleZ = length(SIMD3<Float>(columns.2.x, columns.2.y, columns.2.z))
69+
return SIMD3<Float>(scaleX, scaleY, scaleZ)
70+
}
71+
set {
72+
// Update the rotation part to apply the new scale while preserving the current rotation.
73+
let currentRotation = self.rotation
74+
let rotationMatrix = float3x3(currentRotation)
75+
columns.0 = SIMD4<Float>(rotationMatrix.columns.0 * newValue.x, 0)
76+
columns.1 = SIMD4<Float>(rotationMatrix.columns.1 * newValue.y, 0)
77+
columns.2 = SIMD4<Float>(rotationMatrix.columns.2 * newValue.z, 0)
78+
}
79+
}
80+
81+
/// The rotation component as a quaternion.
82+
public var rotation: simd_quatf {
83+
get {
84+
// Remove the scaling from the upper-left 3x3 part.
85+
let currentScale = self.scale
86+
let col0 = SIMD3<Float>(columns.0.x, columns.0.y, columns.0.z) / (currentScale.x != 0 ? currentScale.x : 1)
87+
let col1 = SIMD3<Float>(columns.1.x, columns.1.y, columns.1.z) / (currentScale.y != 0 ? currentScale.y : 1)
88+
let col2 = SIMD3<Float>(columns.2.x, columns.2.y, columns.2.z) / (currentScale.z != 0 ? currentScale.z : 1)
89+
let rotationMatrix = float3x3(col0, col1, col2)
90+
return simd_quatf(rotationMatrix)
91+
}
92+
set {
93+
// Preserve the current scale while setting a new rotation.
94+
let currentScale = self.scale
95+
let rotationMatrix = float3x3(newValue)
96+
columns.0 = SIMD4<Float>(rotationMatrix.columns.0 * currentScale.x, 0)
97+
columns.1 = SIMD4<Float>(rotationMatrix.columns.1 * currentScale.y, 0)
98+
columns.2 = SIMD4<Float>(rotationMatrix.columns.2 * currentScale.z, 0)
99+
}
100+
}
101+
}
102+
103+
public extension simd_float4x4
104+
{
105+
static func * (lhs: simd_float4x4, rhs: SIMD3<Float>) -> SIMD3<Float> {
106+
let vec4 = SIMD4<Float>(rhs, 1)
107+
let transformed = lhs * vec4
108+
return transformed.xyz
109+
}
110+
}
111+
112+
public extension simd_quatf
113+
{
114+
public static var identity: simd_quatf
115+
{
116+
simd_quatf(ix: 0, iy: 0, iz: 0, r: 1)
117+
}
118+
}
119+
120+
public extension SIMD3
121+
{
122+
var xy: SIMD2<Scalar>
123+
{
124+
SIMD2<Scalar>(self.x, self.y)
125+
}
126+
}
127+
128+
public extension SIMD4
129+
{
130+
var xyz: SIMD3<Scalar>
131+
{
132+
SIMD3<Scalar>(self.x, self.y, self.z)
133+
}
134+
}

Sources/allonet2/util.swift

Lines changed: 0 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
//
77

88
import Foundation
9-
import simd
109
import OpenCombineShim
1110

1211
func with<T>(_ value: T, using closure: (inout T) -> Void) -> T {
@@ -27,116 +26,6 @@ extension Dictionary {
2726
}
2827
}
2928

30-
extension float4x4 : Codable
31-
{
32-
public func encode(to encoder: Encoder) throws
33-
{
34-
var container = encoder.unkeyedContainer()
35-
// Encode in row-major order: for each row, encode all columns.
36-
for row in 0..<4
37-
{
38-
for col in 0..<4
39-
{
40-
try container.encode(self[col][row])
41-
}
42-
}
43-
}
44-
45-
public init(from decoder: Decoder) throws
46-
{
47-
var container = try decoder.unkeyedContainer()
48-
var matrix = simd_float4x4()
49-
// Decode in row-major order.
50-
for row in 0..<4
51-
{
52-
for col in 0..<4
53-
{
54-
let value = try container.decode(Float.self)
55-
matrix[col][row] = value
56-
}
57-
}
58-
self = matrix
59-
}
60-
}
61-
62-
extension simd_float4x4 {
63-
public static var identity: simd_float4x4 {
64-
return matrix_identity_float4x4
65-
}
66-
public var translation: SIMD3<Float> {
67-
get {
68-
return SIMD3<Float>(columns.3.x, columns.3.y, columns.3.z)
69-
}
70-
set {
71-
columns.3 = SIMD4<Float>(newValue.x, newValue.y, newValue.z, columns.3.w)
72-
}
73-
}
74-
75-
public var scale: SIMD3<Float> {
76-
get {
77-
// The scale is the length of each column vector (ignoring the homogeneous component).
78-
let scaleX = length(SIMD3<Float>(columns.0.x, columns.0.y, columns.0.z))
79-
let scaleY = length(SIMD3<Float>(columns.1.x, columns.1.y, columns.1.z))
80-
let scaleZ = length(SIMD3<Float>(columns.2.x, columns.2.y, columns.2.z))
81-
return SIMD3<Float>(scaleX, scaleY, scaleZ)
82-
}
83-
set {
84-
// Update the rotation part to apply the new scale while preserving the current rotation.
85-
let currentRotation = self.rotation
86-
let rotationMatrix = float3x3(currentRotation)
87-
columns.0 = SIMD4<Float>(rotationMatrix.columns.0 * newValue.x, 0)
88-
columns.1 = SIMD4<Float>(rotationMatrix.columns.1 * newValue.y, 0)
89-
columns.2 = SIMD4<Float>(rotationMatrix.columns.2 * newValue.z, 0)
90-
}
91-
}
92-
93-
/// The rotation component as a quaternion.
94-
public var rotation: simd_quatf {
95-
get {
96-
// Remove the scaling from the upper-left 3x3 part.
97-
let currentScale = self.scale
98-
let col0 = SIMD3<Float>(columns.0.x, columns.0.y, columns.0.z) / (currentScale.x != 0 ? currentScale.x : 1)
99-
let col1 = SIMD3<Float>(columns.1.x, columns.1.y, columns.1.z) / (currentScale.y != 0 ? currentScale.y : 1)
100-
let col2 = SIMD3<Float>(columns.2.x, columns.2.y, columns.2.z) / (currentScale.z != 0 ? currentScale.z : 1)
101-
let rotationMatrix = float3x3(col0, col1, col2)
102-
return simd_quatf(rotationMatrix)
103-
}
104-
set {
105-
// Preserve the current scale while setting a new rotation.
106-
let currentScale = self.scale
107-
let rotationMatrix = float3x3(newValue)
108-
columns.0 = SIMD4<Float>(rotationMatrix.columns.0 * currentScale.x, 0)
109-
columns.1 = SIMD4<Float>(rotationMatrix.columns.1 * currentScale.y, 0)
110-
columns.2 = SIMD4<Float>(rotationMatrix.columns.2 * currentScale.z, 0)
111-
}
112-
}
113-
}
114-
115-
extension simd_float4x4
116-
{
117-
static func * (lhs: simd_float4x4, rhs: SIMD3<Float>) -> SIMD3<Float> {
118-
let vec4 = SIMD4<Float>(rhs, 1)
119-
let transformed = lhs * vec4
120-
return transformed.xyz
121-
}
122-
}
123-
124-
extension simd_quatf
125-
{
126-
public static var identity: simd_quatf
127-
{
128-
simd_quatf(ix: 0, iy: 0, iz: 0, r: 1)
129-
}
130-
}
131-
132-
extension SIMD4
133-
{
134-
var xyz: SIMD3<Scalar>
135-
{
136-
SIMD3<Scalar>(self.x, self.y, self.z)
137-
}
138-
}
139-
14029
extension EntityID
14130
{
14231
static func random() -> EntityID

0 commit comments

Comments
 (0)