1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
module Spear.Math.Spatial3
(
Spatial3(..)
, Obj3
, fromVectors
, fromTransform
)
where
import Spear.Math.Vector
import Spear.Math.Matrix4 as M hiding (scale)
class Spatial3 s where
-- | Move the spatial.
move :: Vector3 -> s -> s
-- | Move the spatial forwards.
moveFwd :: Float -> s -> s
-- | Move the spatial backwards.
moveBack :: Float -> s -> s
-- | Make the spatial strafe left.
strafeLeft :: Float -> s -> s
-- | Make the spatial Strafe right.
strafeRight :: Float -> s -> s
-- | Rotate the spatial about its local X axis.
pitch :: Float -> s -> s
-- | Rotate the spatial about its local Y axis.
yaw :: Float -> s -> s
-- | Rotate the spatial about its local Z axis.
roll :: Float -> s -> s
-- | Get the spatial's position.
pos :: s -> Vector3
-- | Get the spatial's forward vector.
fwd :: s -> Vector3
-- | Get the spatial's up vector.
up :: s -> Vector3
-- | Get the spatial's right vector.
right :: s -> Vector3
-- | Get the spatial's transform.
transform :: s -> Matrix4
-- | Set the spatial's transform.
setTransform :: Matrix4 -> s -> s
-- | Set the spatial's position.
setPos :: Vector3 -> s -> s
-- | Make the spatial look at the given point.
lookAt :: Vector3 -> s -> s
lookAt pt s =
let position = pos s
fwd = normalise $ pt - position
r = fwd `cross` unity3
u = r `cross` fwd
in
setTransform (M.transform r u (-fwd) position) s
-- | Make the spatial orbit around the given point
orbit :: Vector3 -- ^ Target point
-> Float -- ^ Horizontal angle
-> Float -- ^ Vertical angle
-> Float -- ^ Orbit radius.
-> s
-> s
orbit pt anglex angley radius s =
let ax = anglex * pi / 180
ay = angley * pi / 180
sx = sin ax
sy = sin ay
cx = cos ax
cy = cos ay
px = (x pt) + radius*cy*sx
py = (y pt) + radius*sy
pz = (z pt) + radius*cx*cy
in
setPos (vec3 px py pz) s
-- | An object in 3D space.
data Obj3 = Obj3
{ r :: Vector3
, u :: Vector3
, f :: Vector3
, p :: Vector3
} deriving Show
instance Spatial3 Obj3 where
move d o = o { p = p o + d }
moveFwd s o = o { p = p o + scale (-s) (f o) }
moveBack s o = o { p = p o + scale s (f o) }
strafeLeft s o = o { p = p o + scale (-s) (r o) }
strafeRight s o = o { p = p o + scale s (r o) }
pitch a o =
let a' = toRAD a
sa = sin a'
ca = cos a'
r' = normalise $ scale ca (r o) + scale sa (f o)
f' = normalise $ r' `cross` u o
in o { r = r', f = f' }
yaw a o =
let a' = toRAD a
sa = sin a'
ca = cos a'
f' = normalise $ scale ca (f o) + scale sa (u o)
u' = normalise $ r o `cross` f'
in o { u = u', f = f' }
roll a o =
let a' = toRAD a
sa = sin a'
ca = cos a'
u' = normalise $ scale ca (u o) - scale sa (r o)
f' = normalise $ f o `cross` u'
in o { u = u', f = f' }
pos = p
fwd = f
up = u
right = r
transform o = M.transform (r o) (u o) (f o) (p o)
setTransform t o = Obj3
{ r = M.right t
, u = M.up t
, f = M.forward t
, p = M.position t
}
setPos pos o = o { p = pos }
fromVectors :: Right3 -> Up3 -> Forward3 -> Position3 -> Obj3
fromVectors = Obj3
fromTransform :: Matrix4 -> Obj3
fromTransform m = Obj3 (M.right m) (M.up m) (M.forward m) (M.position m)
toRAD = (*pi) . (/180)
|