Skip to content

Commit 989cd64

Browse files
committed
Continue new GameMath implementation
1 parent c1d088a commit 989cd64

File tree

7 files changed

+228
-12
lines changed

7 files changed

+228
-12
lines changed

Sources/GameMath/3D Types (New)/Direction3n.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ public extension Direction3n where Scalar: FloatingPoint {
130130
}
131131

132132
extension Direction3n: AdditiveArithmetic where Scalar: AdditiveArithmetic { }
133-
extension Direction3n: ExpressibleByIntegerLiteral where Scalar: FixedWidthInteger & _ExpressibleByBuiltinIntegerLiteral & ExpressibleByIntegerLiteral { }
133+
extension Direction3n: ExpressibleByIntegerLiteral where Scalar: _ExpressibleByBuiltinIntegerLiteral & ExpressibleByIntegerLiteral { }
134134
extension Direction3n: ExpressibleByFloatLiteral where Scalar: FloatingPoint & _ExpressibleByBuiltinFloatLiteral & ExpressibleByFloatLiteral { }
135135
extension Direction3n: Equatable where Scalar: Equatable { }
136136
extension Direction3n: Hashable where Scalar: Hashable { }
@@ -152,9 +152,10 @@ extension Direction3n: Codable where Scalar: Codable {
152152
public func encode(to encoder: any Encoder) throws {
153153
var container = encoder.container(keyedBy: CodingKeys.self)
154154
try container.encode(self.x, forKey: .x)
155-
try container.encode(self.x, forKey: .y)
156-
try container.encode(self.x, forKey: .z)
155+
try container.encode(self.y, forKey: .y)
156+
try container.encode(self.z, forKey: .z)
157157
}
158158
}
159+
extension Direction3n: RandomAccessCollection, MutableCollection { }
159160
extension Direction3n: BitwiseCopyable where Scalar: BitwiseCopyable { }
160161
extension Direction3n: BinaryCodable where Self: BitwiseCopyable { }
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/*
2+
* Copyright © 2025 Dustin Collins (Strega's Gate)
3+
* All Rights Reserved.
4+
*
5+
* http://stregasgate.com
6+
*/
7+
8+
/// Common opperations used on box types for surface calculations
9+
public protocol Rect3nSurfaceMath {
10+
typealias ScalarType = Vector3n.ScalarType
11+
associatedtype Scalar: ScalarType
12+
13+
var center: Position3n<Scalar> { get }
14+
var radius: Size3n<Scalar> { get }
15+
}
16+
17+
public extension Rect3nSurfaceMath {
18+
var minPosition: Position3n<Scalar> {
19+
return center - radius
20+
}
21+
22+
var maxPosition: Position3n<Scalar> {
23+
return center + radius
24+
}
25+
26+
var size: Size3n<Scalar> {
27+
return radius * 2
28+
}
29+
}
30+
31+
public extension Rect3nSurfaceMath where Scalar: Comparable {
32+
/**
33+
Locates a position on the surface of this box that is as close to the given point as possible.
34+
- parameter position: A point in space to use as an reference
35+
- returns: The point on the box's surface that is nearest to `p`
36+
*/
37+
func nearestSurfacePosition(to position: Position3n<Scalar>) -> Position3n<Scalar> {
38+
let minPosition: Position3n<Scalar> = self.minPosition
39+
let maxPosition: Position3n<Scalar> = self.maxPosition
40+
41+
var result: Position3n<Scalar> = .zero
42+
43+
for i in 0 ..< 3 {
44+
var v: Scalar = position[i]
45+
let min: Scalar = minPosition[i]
46+
if v < min {
47+
v = min // v = max(v, b.min[i])
48+
}
49+
let max: Scalar = maxPosition[i]
50+
if v > max {
51+
v = max // v = min(v, b.max[i])
52+
}
53+
result[i] = v
54+
}
55+
56+
return result
57+
}
58+
}
59+
60+
public extension Rect3nSurfaceMath where Scalar: Comparable {
61+
@inlinable
62+
func contains(_ rhs: Position3n<Scalar>) -> Bool {
63+
let min = self.minPosition
64+
guard rhs.x >= min.x && rhs.y >= min.y && rhs.z >= min.z else {return false}
65+
66+
let max = self.maxPosition
67+
guard rhs.x < max.x && rhs.y < max.y && rhs.z < max.z else {return false}
68+
69+
return true
70+
}
71+
72+
@inlinable
73+
func contains<T: Rect3nSurfaceMath>(_ otherRect: T) -> Bool where T.Scalar == Scalar {
74+
guard self.contains(otherRect.minPosition) else {return false}
75+
guard self.contains(otherRect.maxPosition) else {return false}
76+
return true
77+
}
78+
79+
@inlinable
80+
func contains(_ rhs: Position3n<Scalar>, withThreshold threshold: Scalar) -> Bool {
81+
let min = self.minPosition - threshold
82+
guard rhs.x >= min.x && rhs.y >= min.y && rhs.z >= min.z else {return false}
83+
84+
let max = self.maxPosition + threshold
85+
guard rhs.x < max.x && rhs.y < max.y && rhs.z < max.z else {return false}
86+
87+
return true
88+
}
89+
90+
@inlinable
91+
func contains<T: Rect3nSurfaceMath>(_ otherRect: T, withThreshold threshold: Scalar) -> Bool where T.Scalar == Scalar {
92+
guard self.contains(otherRect.minPosition, withThreshold: threshold) else {return false}
93+
guard self.contains(otherRect.maxPosition, withThreshold: threshold) else {return false}
94+
return true
95+
}
96+
}
97+
98+
// MARK: Ray3nIntersectable
99+
public extension Rect3nSurfaceMath where Scalar: Ray3nIntersectable.ScalarType {
100+
func intersection(of ray: Ray3n<Scalar>) -> Position3n<Scalar>? {
101+
let minPosition: Position3n<Scalar> = self.minPosition
102+
let maxPosition: Position3n<Scalar> = self.maxPosition
103+
104+
var tmin: Scalar = (minPosition.x - ray.origin.x) / ray.direction.x
105+
var tmax: Scalar = (maxPosition.x - ray.origin.x) / ray.direction.x
106+
107+
if tmin > tmax {
108+
Swift.swap(&tmin, &tmax)
109+
}
110+
111+
var tymin: Scalar = (minPosition.y - ray.origin.y) / ray.direction.y
112+
var tymax: Scalar = (maxPosition.y - ray.origin.y) / ray.direction.y
113+
114+
if tymin > tymax {
115+
Swift.swap(&tymin, &tymax)
116+
}
117+
118+
if tmin > tymax || tymin > tmax {
119+
return nil
120+
}
121+
122+
if tymin > tmin {
123+
tmin = tymin
124+
}
125+
126+
if tymax < tmax {
127+
tmax = tymax
128+
}
129+
130+
var tzmin: Scalar = (minPosition.z - ray.origin.z) / ray.direction.z
131+
var tzmax: Scalar = (maxPosition.z - ray.origin.z) / ray.direction.z
132+
133+
if tzmin > tzmax {
134+
Swift.swap(&tzmin, &tzmax)
135+
}
136+
137+
if tmin > tzmax || tzmin > tmax {
138+
return nil
139+
}
140+
141+
if tzmin > tmin {
142+
tmin = tzmin
143+
}
144+
145+
if tzmax < tmax {
146+
tmax = tzmax
147+
}
148+
let t: Scalar = Swift.min(tmin, tmax)
149+
guard t > 0 else {return nil}
150+
return ray.origin.moved(t, toward: ray.direction)
151+
}
152+
}

Sources/GameMath/3D Types (New)/Position3n.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ public extension Position3n where Scalar: FloatingPoint {
136136
}
137137

138138
extension Position3n: AdditiveArithmetic where Scalar: AdditiveArithmetic { }
139-
extension Position3n: ExpressibleByIntegerLiteral where Scalar: FixedWidthInteger & _ExpressibleByBuiltinIntegerLiteral & ExpressibleByIntegerLiteral { }
139+
extension Position3n: ExpressibleByIntegerLiteral where Scalar: _ExpressibleByBuiltinIntegerLiteral & ExpressibleByIntegerLiteral { }
140140
extension Position3n: ExpressibleByFloatLiteral where Scalar: FloatingPoint & _ExpressibleByBuiltinFloatLiteral & ExpressibleByFloatLiteral { }
141141
extension Position3n: Equatable where Scalar: Equatable { }
142142
extension Position3n: Hashable where Scalar: Hashable { }
@@ -158,9 +158,10 @@ extension Position3n: Codable where Scalar: Codable {
158158
public func encode(to encoder: any Encoder) throws {
159159
var container = encoder.container(keyedBy: CodingKeys.self)
160160
try container.encode(self.x, forKey: .x)
161-
try container.encode(self.x, forKey: .y)
162-
try container.encode(self.x, forKey: .z)
161+
try container.encode(self.y, forKey: .y)
162+
try container.encode(self.z, forKey: .z)
163163
}
164164
}
165+
extension Position3n: RandomAccessCollection, MutableCollection { }
165166
extension Position3n: BitwiseCopyable where Scalar: BitwiseCopyable { }
166167
extension Position3n: BinaryCodable where Self: BitwiseCopyable { }
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright © 2025 Dustin Collins (Strega's Gate)
3+
* All Rights Reserved.
4+
*
5+
* http://stregasgate.com
6+
*/
7+
8+
public typealias Rect3f = Rect3n<Float32>
9+
public typealias Rect3d = Rect3n<Float64>
10+
11+
@frozen
12+
public struct Rect3n<Scalar: Vector3n.ScalarType> {
13+
public var center: Position3n<Scalar>
14+
public var radius: Size3n<Scalar>
15+
16+
public init(size: Size3n<Scalar>, center: Position3n<Scalar>) where Scalar: FixedWidthInteger {
17+
self.center = center
18+
self.radius = size / Size3n<Scalar>(width: 2, height: 2, depth: 2)
19+
}
20+
21+
public init(size: Size3n<Scalar>, center: Position3n<Scalar>) where Scalar: FloatingPoint, Scalar: ExpressibleByFloatLiteral {
22+
self.center = center
23+
self.radius = size * 0.5
24+
}
25+
}
26+
27+
extension Rect3n: Rect3nSurfaceMath where Scalar: Rect3nSurfaceMath.ScalarType { }
28+
extension Rect3n: Ray3nIntersectable where Scalar: Ray3nIntersectable.ScalarType { }

Sources/GameMath/3D Types (New)/Size3n.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public extension Size3n {
6363
}
6464

6565
extension Size3n: AdditiveArithmetic where Scalar: AdditiveArithmetic { }
66-
extension Size3n: ExpressibleByIntegerLiteral where Scalar: FixedWidthInteger & _ExpressibleByBuiltinIntegerLiteral & ExpressibleByIntegerLiteral { }
66+
extension Size3n: ExpressibleByIntegerLiteral where Scalar: _ExpressibleByBuiltinIntegerLiteral & ExpressibleByIntegerLiteral { }
6767
extension Size3n: ExpressibleByFloatLiteral where Scalar: FloatingPoint & _ExpressibleByBuiltinFloatLiteral & ExpressibleByFloatLiteral { }
6868
extension Size3n: Equatable where Scalar: Equatable { }
6969
extension Size3n: Hashable where Scalar: Hashable { }
@@ -85,9 +85,10 @@ extension Size3n: Codable where Scalar: Codable {
8585
public func encode(to encoder: any Encoder) throws {
8686
var container = encoder.container(keyedBy: CodingKeys.self)
8787
try container.encode(self.x, forKey: .x)
88-
try container.encode(self.x, forKey: .y)
89-
try container.encode(self.x, forKey: .z)
88+
try container.encode(self.y, forKey: .y)
89+
try container.encode(self.z, forKey: .z)
9090
}
9191
}
92+
extension Size3n: RandomAccessCollection, MutableCollection { }
9293
extension Size3n: BitwiseCopyable where Scalar: BitwiseCopyable { }
9394
extension Size3n: BinaryCodable where Self: BitwiseCopyable { }

Sources/GameMath/3D Types (New)/Vector3n.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,40 @@ public extension Vector3n where Scalar: FloatingPoint & _ExpressibleByBuiltinFlo
124124
}
125125
}
126126

127+
public extension Vector3n {
128+
typealias Element = Scalar
129+
130+
var startIndex: Int {
131+
nonmutating get {
132+
return 0
133+
}
134+
}
135+
136+
@inlinable
137+
var endIndex: Int {
138+
nonmutating get {
139+
return 3
140+
}
141+
}
142+
143+
@safe // <- Bounds checked with precondition
144+
@inlinable
145+
subscript (index: Int) -> Scalar {
146+
nonmutating get {
147+
precondition(index >= 0 && index < 3, "Index out of range.")
148+
return withUnsafeBytes(of: self) { bytes in
149+
return bytes.load(fromByteOffset: MemoryLayout<Scalar>.size * index, as: Scalar.self)
150+
}
151+
}
152+
mutating set {
153+
precondition(index >= 0 && index < 3, "Index out of range.")
154+
withUnsafeMutableBytes(of: &self) { bytes in
155+
bytes.storeBytes(of: newValue, toByteOffset: MemoryLayout<Scalar>.size * index, as: Scalar.self)
156+
}
157+
}
158+
}
159+
}
160+
127161
public extension Vector3n where Scalar: AdditiveArithmetic {
128162
@inlinable
129163
static func + (lhs: Self, rhs: some Vector3n<Scalar>) -> Self {

Sources/GateEngine/Resources/Geometry/Raw/Vertex.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,8 @@ public struct Vertex: Codable, Equatable, Hashable {
9191
public static func * (lhs: Self, rhs: Matrix4x4) -> Self {
9292
var copy = lhs
9393
copy.position = copy.position * rhs
94-
let m3 = Matrix3x3(rhs)
95-
copy.normal = copy.normal * m3
96-
copy.tangent = copy.tangent * m3
94+
copy.normal = copy.normal.rotated(by: rhs.rotation.conjugate)
95+
copy.tangent = copy.tangent.rotated(by: rhs.rotation.conjugate)
9796
return copy
9897
}
9998
}

0 commit comments

Comments
 (0)