diff options
-rw-r--r-- | Spear/App/Input.hs | 40 | ||||
-rw-r--r-- | Spear/GL.hs | 3 | ||||
-rw-r--r-- | Spear/Math/Camera.hs | 100 | ||||
-rw-r--r-- | Spear/Math/MatrixUtils.hs | 9 | ||||
-rw-r--r-- | Spear/Math/Spatial3.hs | 134 | ||||
-rw-r--r-- | Spear/Scene/GameObject.hs | 3 |
6 files changed, 176 insertions, 113 deletions
diff --git a/Spear/App/Input.hs b/Spear/App/Input.hs index 0207147..9fa140a 100644 --- a/Spear/App/Input.hs +++ b/Spear/App/Input.hs | |||
@@ -27,14 +27,12 @@ module Spear.App.Input | |||
27 | ) | 27 | ) |
28 | where | 28 | where |
29 | 29 | ||
30 | |||
31 | import Data.Char (ord) | 30 | import Data.Char (ord) |
32 | import qualified Data.Vector.Unboxed as V | 31 | import qualified Data.Vector.Unboxed as V |
33 | import qualified Graphics.UI.GLFW as GLFW | 32 | import qualified Graphics.UI.GLFW as GLFW |
34 | import Graphics.Rendering.OpenGL.GL.CoordTrans | 33 | import Graphics.Rendering.OpenGL.GL.CoordTrans |
35 | import Data.StateVar | 34 | import Data.StateVar |
36 | 35 | ||
37 | |||
38 | data Key | 36 | data Key |
39 | = KEY_A | KEY_B | KEY_C | KEY_D | KEY_E | KEY_F | KEY_G | KEY_H | 37 | = KEY_A | KEY_B | KEY_C | KEY_D | KEY_E | KEY_F | KEY_G | KEY_H |
40 | | KEY_I | KEY_J | KEY_K | KEY_L | KEY_M | KEY_N | KEY_O | KEY_P | 38 | | KEY_I | KEY_J | KEY_K | KEY_L | KEY_M | KEY_N | KEY_O | KEY_P |
@@ -42,33 +40,28 @@ data Key | |||
42 | | KEY_Y | KEY_Z | KEY_0 | KEY_1 | KEY_2 | KEY_3 | KEY_4 | KEY_5 | 40 | | KEY_Y | KEY_Z | KEY_0 | KEY_1 | KEY_2 | KEY_3 | KEY_4 | KEY_5 |
43 | | KEY_6 | KEY_7 | KEY_8 | KEY_9 | KEY_F1 | KEY_F2 | KEY_F3 | 41 | | KEY_6 | KEY_7 | KEY_8 | KEY_9 | KEY_F1 | KEY_F2 | KEY_F3 |
44 | | KEY_F4 | KEY_F5 | KEY_F6 | KEY_F7 | KEY_F8 | KEY_F9 | KEY_F10 | 42 | | KEY_F4 | KEY_F5 | KEY_F6 | KEY_F7 | KEY_F8 | KEY_F9 | KEY_F10 |
45 | | KEY_F11 | KEY_F12 | KEY_ESC | KEY_SPACE | 43 | | KEY_F11 | KEY_F12 | KEY_ESC | KEY_SPACE | KEY_UP | KEY_DOWN |
44 | | KEY_LEFT | KEY_RIGHT | ||
46 | deriving (Enum, Bounded) | 45 | deriving (Enum, Bounded) |
47 | 46 | ||
48 | |||
49 | type Keyboard = Key -> Bool | 47 | type Keyboard = Key -> Bool |
50 | 48 | ||
51 | |||
52 | data MouseButton = LMB | RMB | MMB | 49 | data MouseButton = LMB | RMB | MMB |
53 | deriving (Enum, Bounded) | 50 | deriving (Enum, Bounded) |
54 | 51 | ||
55 | |||
56 | data MouseProp = MouseX | MouseY | MouseDX | MouseDY | 52 | data MouseProp = MouseX | MouseY | MouseDX | MouseDY |
57 | deriving Enum | 53 | deriving Enum |
58 | 54 | ||
59 | |||
60 | data Mouse = Mouse | 55 | data Mouse = Mouse |
61 | { button :: MouseButton -> Bool | 56 | { button :: MouseButton -> Bool |
62 | , property :: MouseProp -> Float | 57 | , property :: MouseProp -> Float |
63 | } | 58 | } |
64 | 59 | ||
65 | |||
66 | data Input = Input | 60 | data Input = Input |
67 | { keyboard :: Keyboard | 61 | { keyboard :: Keyboard |
68 | , mouse :: Mouse | 62 | , mouse :: Mouse |
69 | } | 63 | } |
70 | 64 | ||
71 | |||
72 | -- | Return a new dummy keyboard. | 65 | -- | Return a new dummy keyboard. |
73 | -- | 66 | -- |
74 | -- This function should be called to get an initial keyboard. | 67 | -- This function should be called to get an initial keyboard. |
@@ -79,7 +72,6 @@ data Input = Input | |||
79 | newKeyboard :: Keyboard | 72 | newKeyboard :: Keyboard |
80 | newKeyboard = const False | 73 | newKeyboard = const False |
81 | 74 | ||
82 | |||
83 | -- | Get the keyboard. | 75 | -- | Get the keyboard. |
84 | getKeyboard :: IO Keyboard | 76 | getKeyboard :: IO Keyboard |
85 | getKeyboard = | 77 | getKeyboard = |
@@ -90,7 +82,6 @@ getKeyboard = | |||
90 | (fmap (V.fromList . fmap ((==) GLFW.Press)) . mapM GLFW.getKey . fmap toGLFWkey $ keys) | 82 | (fmap (V.fromList . fmap ((==) GLFW.Press)) . mapM GLFW.getKey . fmap toGLFWkey $ keys) |
91 | >>= return . keyboard' | 83 | >>= return . keyboard' |
92 | 84 | ||
93 | |||
94 | -- | Return a new dummy mouse. | 85 | -- | Return a new dummy mouse. |
95 | -- | 86 | -- |
96 | -- This function should be called to get an initial mouse. | 87 | -- This function should be called to get an initial mouse. |
@@ -101,7 +92,6 @@ getKeyboard = | |||
101 | newMouse :: Mouse | 92 | newMouse :: Mouse |
102 | newMouse = Mouse (const False) (const 0) | 93 | newMouse = Mouse (const False) (const 0) |
103 | 94 | ||
104 | |||
105 | -- | Get the mouse. | 95 | -- | Get the mouse. |
106 | -- | 96 | -- |
107 | -- The previous mouse state is required to compute position deltas. | 97 | -- The previous mouse state is required to compute position deltas. |
@@ -109,21 +99,21 @@ getMouse :: Mouse -> IO Mouse | |||
109 | getMouse oldMouse = | 99 | getMouse oldMouse = |
110 | let getButton :: V.Vector Bool -> MouseButton -> Bool | 100 | let getButton :: V.Vector Bool -> MouseButton -> Bool |
111 | getButton mousestate button = mousestate V.! fromEnum button | 101 | getButton mousestate button = mousestate V.! fromEnum button |
112 | 102 | ||
113 | getProp :: V.Vector Float -> MouseProp -> Float | 103 | getProp :: V.Vector Float -> MouseProp -> Float |
114 | getProp props prop = props V.! fromEnum prop | 104 | getProp props prop = props V.! fromEnum prop |
115 | 105 | ||
116 | props xpos ypos = V.fromList | 106 | props xpos ypos = V.fromList |
117 | [ xpos, ypos | 107 | [ xpos, ypos |
118 | , xpos - property oldMouse MouseX | 108 | , xpos - property oldMouse MouseX |
119 | , ypos - property oldMouse MouseY | 109 | , ypos - property oldMouse MouseY |
120 | ] | 110 | ] |
121 | 111 | ||
122 | getButtonState = | 112 | getButtonState = |
123 | fmap (V.fromList . fmap ((==) GLFW.Press)) . | 113 | fmap (V.fromList . fmap ((==) GLFW.Press)) . |
124 | mapM GLFW.getMouseButton . | 114 | mapM GLFW.getMouseButton . |
125 | fmap toGLFWbutton $ buttons | 115 | fmap toGLFWbutton $ buttons |
126 | 116 | ||
127 | buttons = fmap toEnum [0..fromEnum (maxBound :: MouseButton)] | 117 | buttons = fmap toEnum [0..fromEnum (maxBound :: MouseButton)] |
128 | in do | 118 | in do |
129 | Position xpos ypos <- get GLFW.mousePos | 119 | Position xpos ypos <- get GLFW.mousePos |
@@ -133,12 +123,10 @@ getMouse oldMouse = | |||
133 | , property = getProp $ props (fromIntegral xpos) (fromIntegral ypos) | 123 | , property = getProp $ props (fromIntegral xpos) (fromIntegral ypos) |
134 | } | 124 | } |
135 | 125 | ||
136 | |||
137 | -- | Return a new dummy input. | 126 | -- | Return a new dummy input. |
138 | newInput :: Input | 127 | newInput :: Input |
139 | newInput = Input newKeyboard newMouse | 128 | newInput = Input newKeyboard newMouse |
140 | 129 | ||
141 | |||
142 | -- | Get input devices. | 130 | -- | Get input devices. |
143 | getInput :: Input -> IO Input | 131 | getInput :: Input -> IO Input |
144 | getInput (Input _ oldMouse) = do | 132 | getInput (Input _ oldMouse) = do |
@@ -146,12 +134,10 @@ getInput (Input _ oldMouse) = do | |||
146 | mouse <- getMouse oldMouse | 134 | mouse <- getMouse oldMouse |
147 | return $ Input keyboard mouse | 135 | return $ Input keyboard mouse |
148 | 136 | ||
149 | |||
150 | -- | Poll input devices. | 137 | -- | Poll input devices. |
151 | pollInput :: IO () | 138 | pollInput :: IO () |
152 | pollInput = GLFW.pollEvents | 139 | pollInput = GLFW.pollEvents |
153 | 140 | ||
154 | |||
155 | -- | Return a mouse that reacts to button toggles. | 141 | -- | Return a mouse that reacts to button toggles. |
156 | toggledMouse :: Mouse -- ^ Previous mouse state. | 142 | toggledMouse :: Mouse -- ^ Previous mouse state. |
157 | -> Mouse -- ^ Current mouse state. | 143 | -> Mouse -- ^ Current mouse state. |
@@ -159,7 +145,6 @@ toggledMouse :: Mouse -- ^ Previous mouse state. | |||
159 | 145 | ||
160 | toggledMouse prev cur = cur { button = \bt -> button cur bt && not (button prev bt) } | 146 | toggledMouse prev cur = cur { button = \bt -> button cur bt && not (button prev bt) } |
161 | 147 | ||
162 | |||
163 | -- | Return a keyboard that reacts to key toggles. | 148 | -- | Return a keyboard that reacts to key toggles. |
164 | toggledKeyboard :: Keyboard -- ^ Previous keyboard state. | 149 | toggledKeyboard :: Keyboard -- ^ Previous keyboard state. |
165 | -> Keyboard -- ^ Current keyboard state. | 150 | -> Keyboard -- ^ Current keyboard state. |
@@ -167,9 +152,6 @@ toggledKeyboard :: Keyboard -- ^ Previous keyboard state. | |||
167 | 152 | ||
168 | toggledKeyboard prev cur key = cur key && not (prev key) | 153 | toggledKeyboard prev cur key = cur key && not (prev key) |
169 | 154 | ||
170 | |||
171 | |||
172 | |||
173 | -- | Delay configuration for each mouse button. | 155 | -- | Delay configuration for each mouse button. |
174 | type ButtonDelay = MouseButton -> Float | 156 | type ButtonDelay = MouseButton -> Float |
175 | 157 | ||
@@ -181,13 +163,11 @@ data DelayedMouse = DelayedMouse | |||
181 | , accum :: V.Vector Float | 163 | , accum :: V.Vector Float |
182 | } | 164 | } |
183 | 165 | ||
184 | |||
185 | newDM :: ButtonDelay -- ^ Delay configuration for each button. | 166 | newDM :: ButtonDelay -- ^ Delay configuration for each button. |
186 | -> DelayedMouse | 167 | -> DelayedMouse |
187 | newDM delay = DelayedMouse newMouse delay $ | 168 | newDM delay = DelayedMouse newMouse delay $ |
188 | V.replicate (fromEnum (maxBound :: MouseButton)) 0 | 169 | V.replicate (fromEnum (maxBound :: MouseButton)) 0 |
189 | 170 | ||
190 | |||
191 | updateDM :: DelayedMouse -- ^ Current mouse state. | 171 | updateDM :: DelayedMouse -- ^ Current mouse state. |
192 | -> Float -- ^ Time elapsed since last udpate. | 172 | -> Float -- ^ Time elapsed since last udpate. |
193 | -> DelayedMouse | 173 | -> DelayedMouse |
@@ -199,13 +179,11 @@ updateDM (DelayedMouse mouse delay accum) dt = | |||
199 | button' b = active b && button mouse b | 179 | button' b = active b && button mouse b |
200 | accum' = accum V.// fmap newDelay [0 .. fromEnum (maxBound :: MouseButton)] | 180 | accum' = accum V.// fmap newDelay [0 .. fromEnum (maxBound :: MouseButton)] |
201 | newDelay x = let b = toEnum x | 181 | newDelay x = let b = toEnum x |
202 | in (x, if button' b then 0 else time b) | 182 | in (x, if button' b then 0 else time b) |
203 | in | 183 | in |
204 | DelayedMouse mouse { button = button' } delay accum' | 184 | DelayedMouse mouse { button = button' } delay accum' |
205 | 185 | ||
206 | 186 | ||
207 | |||
208 | |||
209 | toGLFWkey :: Key -> Int | 187 | toGLFWkey :: Key -> Int |
210 | toGLFWkey KEY_A = ord 'A' | 188 | toGLFWkey KEY_A = ord 'A' |
211 | toGLFWkey KEY_B = ord 'B' | 189 | toGLFWkey KEY_B = ord 'B' |
@@ -257,6 +235,10 @@ toGLFWkey KEY_F11 = fromEnum GLFW.F11 | |||
257 | toGLFWkey KEY_F12 = fromEnum GLFW.F12 | 235 | toGLFWkey KEY_F12 = fromEnum GLFW.F12 |
258 | toGLFWkey KEY_ESC = fromEnum GLFW.ESC | 236 | toGLFWkey KEY_ESC = fromEnum GLFW.ESC |
259 | toGLFWkey KEY_SPACE = ord ' ' | 237 | toGLFWkey KEY_SPACE = ord ' ' |
238 | toGLFWkey KEY_UP = fromEnum GLFW.UP | ||
239 | toGLFWkey KEY_DOWN = fromEnum GLFW.DOWN | ||
240 | toGLFWkey KEY_LEFT = fromEnum GLFW.LEFT | ||
241 | toGLFWkey KEY_RIGHT = fromEnum GLFW.RIGHT | ||
260 | 242 | ||
261 | 243 | ||
262 | toGLFWbutton :: MouseButton -> GLFW.MouseButton | 244 | toGLFWbutton :: MouseButton -> GLFW.MouseButton |
diff --git a/Spear/GL.hs b/Spear/GL.hs index 6792d35..af96da4 100644 --- a/Spear/GL.hs +++ b/Spear/GL.hs | |||
@@ -452,7 +452,8 @@ attribVAOPointer | |||
452 | -> Int -- ^ Offset to the first component in the array. | 452 | -> Int -- ^ Offset to the first component in the array. |
453 | -> IO () | 453 | -> IO () |
454 | attribVAOPointer idx ncomp dattype normalise stride off = | 454 | attribVAOPointer idx ncomp dattype normalise stride off = |
455 | glVertexAttribPointer idx ncomp dattype (unsafeCoerce normalise) stride (unsafeCoerce off) | 455 | glVertexAttribPointer idx ncomp dattype normalise' stride (unsafeCoerce off) |
456 | where normalise' = if normalise then 1 else 0 | ||
456 | 457 | ||
457 | -- | Draw the bound vao. | 458 | -- | Draw the bound vao. |
458 | drawArrays | 459 | drawArrays |
diff --git a/Spear/Math/Camera.hs b/Spear/Math/Camera.hs index a86d5f5..9484bef 100644 --- a/Spear/Math/Camera.hs +++ b/Spear/Math/Camera.hs | |||
@@ -1,71 +1,89 @@ | |||
1 | module Spear.Math.Camera | 1 | module Spear.Math.Camera |
2 | ( | ||
3 | Camera | ||
4 | , Fovy | ||
5 | , Aspect | ||
6 | , Near | ||
7 | , Far | ||
8 | , Left | ||
9 | , Right | ||
10 | , Bottom | ||
11 | , Top | ||
12 | , projection | ||
13 | ) | ||
2 | where | 14 | where |
3 | 15 | ||
4 | 16 | ||
5 | import qualified Spear.Math.Matrix4 as M | 17 | import qualified Spear.Math.Matrix4 as M |
6 | import qualified Spear.Math.Spatial3 as S | 18 | import Spear.Math.Spatial3 |
7 | import Spear.Math.Vector | 19 | import Spear.Math.Vector |
8 | 20 | ||
9 | 21 | ||
10 | data Camera = Camera | 22 | data Camera = Camera |
11 | { projection :: M.Matrix4 | 23 | { projection :: M.Matrix4 -- ^ Get the camera's projection. |
12 | , transform :: M.Matrix4 | 24 | , spatial :: Obj3 |
13 | } | 25 | } |
14 | 26 | ||
27 | type Fovy = Float | ||
28 | type Aspect = Float | ||
29 | type Near = Float | ||
30 | type Far = Float | ||
31 | type Left = Float | ||
32 | type Right = Float | ||
33 | type Bottom = Float | ||
34 | type Top = Float | ||
15 | 35 | ||
16 | -- | Build a perspective camera. | 36 | -- | Build a perspective camera. |
17 | perspective :: Float -- ^ Fovy - Vertical field of view angle in degrees. | 37 | perspective :: Fovy -- ^ Fovy - Vertical field of view angle in degrees. |
18 | -> Float -- ^ Aspect ratio. | 38 | -> Aspect -- ^ Aspect ratio. |
19 | -> Float -- ^ Near clip. | 39 | -> Near -- ^ Near clip. |
20 | -> Float -- ^ Far clip. | 40 | -> Far -- ^ Far clip. |
21 | -> Vector3 -- ^ Right vector. | 41 | -> Right3 -- ^ Right vector. |
22 | -> Vector3 -- ^ Up vector. | 42 | -> Up3 -- ^ Up vector. |
23 | -> Vector3 -- ^ Forward vector. | 43 | -> Forward3 -- ^ Forward vector. |
24 | -> Vector3 -- ^ Position vector. | 44 | -> Position3 -- ^ Position vector. |
25 | -> Camera | 45 | -> Camera |
26 | 46 | ||
27 | perspective fovy r n f right up fwd pos = | 47 | perspective fovy r n f right up fwd pos = |
28 | Camera | 48 | Camera |
29 | { projection = M.perspective fovy r n f | 49 | { projection = M.perspective fovy r n f |
30 | , transform = M.transform right up (neg fwd) pos | 50 | , spatial = fromVectors right up fwd pos |
31 | } | 51 | } |
32 | 52 | ||
33 | 53 | ||
34 | -- | Build an orthogonal camera. | 54 | -- | Build an orthogonal camera. |
35 | ortho :: Float -- ^ Left. | 55 | ortho :: Left -- ^ Left. |
36 | -> Float -- ^ Right. | 56 | -> Right -- ^ Right. |
37 | -> Float -- ^ Bottom. | 57 | -> Bottom -- ^ Bottom. |
38 | -> Float -- ^ Top. | 58 | -> Top -- ^ Top. |
39 | -> Float -- ^ Near clip. | 59 | -> Near -- ^ Near clip. |
40 | -> Float -- ^ Far clip. | 60 | -> Far -- ^ Far clip. |
41 | -> Vector3 -- ^ Right vector. | 61 | -> Right3 -- ^ Right vector. |
42 | -> Vector3 -- ^ Up vector. | 62 | -> Up3 -- ^ Up vector. |
43 | -> Vector3 -- ^ Forward vector. | 63 | -> Forward3 -- ^ Forward vector. |
44 | -> Vector3 -- ^ Position vector. | 64 | -> Position3 -- ^ Position vector. |
45 | -> Camera | 65 | -> Camera |
46 | 66 | ||
47 | ortho l r b t n f right up fwd pos = | 67 | ortho l r b t n f right up fwd pos = |
48 | Camera | 68 | Camera |
49 | { projection = M.ortho l r b t n f | 69 | { projection = M.ortho l r b t n f |
50 | , transform = M.transform right up (neg fwd) pos | 70 | , spatial = fromVectors right up fwd pos |
51 | } | 71 | } |
52 | 72 | ||
53 | 73 | ||
54 | instance S.Spatial3 Camera where | 74 | instance Spatial3 Camera where |
55 | move v cam = cam { transform = M.translv v * transform cam } | 75 | move v cam = cam { spatial = move v $ spatial cam } |
56 | moveFwd f cam = cam { transform = M.translv (scale f $ S.fwd cam) * transform cam } | 76 | moveFwd s cam = cam { spatial = moveFwd s $ spatial cam } |
57 | moveBack f cam = cam { transform = M.translv (scale (-f) $ S.fwd cam) * transform cam } | 77 | moveBack s cam = cam { spatial = moveBack s $ spatial cam } |
58 | strafeLeft f cam = cam { transform = M.translv (scale (-f) $ S.right cam) * transform cam } | 78 | strafeLeft s cam = cam { spatial = strafeLeft s $ spatial cam } |
59 | strafeRight f cam = cam { transform = M.translv (scale f $ S.right cam) * transform cam } | 79 | strafeRight s cam = cam { spatial = strafeRight s $ spatial cam } |
60 | pitch a cam = cam { transform = transform cam * M.axisAngle (S.right cam) a } | 80 | pitch a cam = cam { spatial = pitch a $ spatial cam } |
61 | yaw a cam = cam { transform = transform cam * M.axisAngle (S.up cam) a } | 81 | yaw a cam = cam { spatial = yaw a $ spatial cam } |
62 | roll a cam = cam { transform = transform cam * M.axisAngle (S.fwd cam) a } | 82 | roll a cam = cam { spatial = roll a $ spatial cam } |
63 | pos = M.position . transform | 83 | pos cam = pos $ spatial cam |
64 | fwd = M.forward . transform | 84 | fwd cam = fwd $ spatial cam |
65 | up = M.up . transform | 85 | up cam = up $ spatial cam |
66 | right = M.right . transform | 86 | right cam = right $ spatial cam |
67 | transform (Camera _ t) = t | 87 | transform cam = transform $ spatial cam |
68 | setTransform t (Camera proj _) = Camera proj t | 88 | setTransform m cam = cam { spatial = setTransform m $ spatial cam } |
69 | setPos pos (Camera proj t) = Camera proj $ | 89 | setPos p cam = cam { spatial = setPos p $ spatial cam } |
70 | M.transform (M.right t) (M.up t) (M.forward t) pos | ||
71 | |||
diff --git a/Spear/Math/MatrixUtils.hs b/Spear/Math/MatrixUtils.hs index 79bd049..e4273a1 100644 --- a/Spear/Math/MatrixUtils.hs +++ b/Spear/Math/MatrixUtils.hs | |||
@@ -15,6 +15,7 @@ where | |||
15 | import Spear.Math.Camera as Cam | 15 | import Spear.Math.Camera as Cam |
16 | import Spear.Math.Matrix3 as M3 | 16 | import Spear.Math.Matrix3 as M3 |
17 | import Spear.Math.Matrix4 as M4 | 17 | import Spear.Math.Matrix4 as M4 |
18 | import Spear.Math.Spatial3 as S | ||
18 | import Spear.Math.Vector as V | 19 | import Spear.Math.Vector as V |
19 | 20 | ||
20 | 21 | ||
@@ -112,7 +113,7 @@ pltTransform mat = | |||
112 | 113 | ||
113 | 114 | ||
114 | -- | Map an object's transform in world space to view space. | 115 | -- | Map an object's transform in world space to view space. |
115 | -- | 116 | -- |
116 | -- The XY plane in 2D translates to the X(-Z) plane in 3D. | 117 | -- The XY plane in 2D translates to the X(-Z) plane in 3D. |
117 | -- | 118 | -- |
118 | -- Use this in games such as RPGs and RTSs. | 119 | -- Use this in games such as RPGs and RTSs. |
@@ -130,9 +131,9 @@ rpgInverse h a axis pos viewI = | |||
130 | -- | Map an object's transform in world space to view space. | 131 | -- | Map an object's transform in world space to view space. |
131 | -- | 132 | -- |
132 | -- This function maps an object's transform in 2D to the object's inverse in 3D. | 133 | -- This function maps an object's transform in 2D to the object's inverse in 3D. |
133 | -- | 134 | -- |
134 | -- The XY plane in 2D translates to the XY plane in 3D. | 135 | -- The XY plane in 2D translates to the XY plane in 3D. |
135 | -- | 136 | -- |
136 | -- Use this in games like platformers and space invaders style games. | 137 | -- Use this in games like platformers and space invaders style games. |
137 | pltInverse :: Matrix3 -> Matrix4 | 138 | pltInverse :: Matrix3 -> Matrix4 |
138 | pltInverse = M4.inverseTransform . pltTransform | 139 | pltInverse = M4.inverseTransform . pltTransform |
@@ -142,7 +143,7 @@ pltInverse = M4.inverseTransform . pltTransform | |||
142 | objToClip :: Camera -> Matrix4 -> Vector3 -> Vector2 | 143 | objToClip :: Camera -> Matrix4 -> Vector3 -> Vector2 |
143 | objToClip cam model p = | 144 | objToClip cam model p = |
144 | let | 145 | let |
145 | view = M4.inverseTransform $ Cam.transform cam | 146 | view = M4.inverseTransform $ S.transform cam |
146 | proj = Cam.projection cam | 147 | proj = Cam.projection cam |
147 | p' = (proj * view * model) `M4.mulp` p | 148 | p' = (proj * view * model) `M4.mulp` p |
148 | in | 149 | in |
diff --git a/Spear/Math/Spatial3.hs b/Spear/Math/Spatial3.hs index 6db3853..2bc772e 100644 --- a/Spear/Math/Spatial3.hs +++ b/Spear/Math/Spatial3.hs | |||
@@ -1,58 +1,62 @@ | |||
1 | module Spear.Math.Spatial3 | 1 | module Spear.Math.Spatial3 |
2 | ( | ||
3 | Spatial3(..) | ||
4 | , Obj3 | ||
5 | , fromVectors | ||
6 | , fromTransform | ||
7 | ) | ||
2 | where | 8 | where |
3 | 9 | ||
4 | |||
5 | import Spear.Math.Vector | 10 | import Spear.Math.Vector |
6 | import Spear.Math.Matrix4 as M | 11 | import Spear.Math.Matrix4 as M hiding (scale) |
7 | |||
8 | 12 | ||
9 | class Spatial3 s where | 13 | class Spatial3 s where |
10 | -- | Move the 'Spatial'. | 14 | -- | Move the spatial. |
11 | move :: Vector3 -> s -> s | 15 | move :: Vector3 -> s -> s |
12 | 16 | ||
13 | -- | Move the 'Spatial' forwards. | 17 | -- | Move the spatial forwards. |
14 | moveFwd :: Float -> s -> s | 18 | moveFwd :: Float -> s -> s |
15 | 19 | ||
16 | -- | Move the 'Spatial' backwards. | 20 | -- | Move the spatial backwards. |
17 | moveBack :: Float -> s -> s | 21 | moveBack :: Float -> s -> s |
18 | 22 | ||
19 | -- | Make the 'Spatial' strafe left. | 23 | -- | Make the spatial strafe left. |
20 | strafeLeft :: Float -> s -> s | 24 | strafeLeft :: Float -> s -> s |
21 | 25 | ||
22 | -- | Make the 'Spatial' Strafe right. | 26 | -- | Make the spatial Strafe right. |
23 | strafeRight :: Float -> s -> s | 27 | strafeRight :: Float -> s -> s |
24 | 28 | ||
25 | -- | Rotate the 'Spatial' about its local X axis. | 29 | -- | Rotate the spatial about its local X axis. |
26 | pitch :: Float -> s -> s | 30 | pitch :: Float -> s -> s |
27 | 31 | ||
28 | -- | Rotate the 'Spatial' about its local Y axis. | 32 | -- | Rotate the spatial about its local Y axis. |
29 | yaw :: Float -> s -> s | 33 | yaw :: Float -> s -> s |
30 | 34 | ||
31 | -- | Rotate the 'Spatial' about its local Z axis. | 35 | -- | Rotate the spatial about its local Z axis. |
32 | roll :: Float -> s -> s | 36 | roll :: Float -> s -> s |
33 | 37 | ||
34 | -- | Get the 'Spatial''s position. | 38 | -- | Get the spatial's position. |
35 | pos :: s -> Vector3 | 39 | pos :: s -> Vector3 |
36 | 40 | ||
37 | -- | Get the 'Spatial''s forward vector. | 41 | -- | Get the spatial's forward vector. |
38 | fwd :: s -> Vector3 | 42 | fwd :: s -> Vector3 |
39 | 43 | ||
40 | -- | Get the 'Spatial''s up vector. | 44 | -- | Get the spatial's up vector. |
41 | up :: s -> Vector3 | 45 | up :: s -> Vector3 |
42 | 46 | ||
43 | -- | Get the 'Spatial''s right vector. | 47 | -- | Get the spatial's right vector. |
44 | right :: s -> Vector3 | 48 | right :: s -> Vector3 |
45 | 49 | ||
46 | -- | Get the 'Spatial''s transform. | 50 | -- | Get the spatial's transform. |
47 | transform :: s -> Matrix4 | 51 | transform :: s -> Matrix4 |
48 | 52 | ||
49 | -- | Set the 'Spatial''s transform. | 53 | -- | Set the spatial's transform. |
50 | setTransform :: Matrix4 -> s -> s | 54 | setTransform :: Matrix4 -> s -> s |
51 | 55 | ||
52 | -- | Set the 'Spatial''s position. | 56 | -- | Set the spatial's position. |
53 | setPos :: Vector3 -> s -> s | 57 | setPos :: Vector3 -> s -> s |
54 | 58 | ||
55 | -- | Make the 'Spatial' look at the given point. | 59 | -- | Make the spatial look at the given point. |
56 | lookAt :: Vector3 -> s -> s | 60 | lookAt :: Vector3 -> s -> s |
57 | lookAt pt s = | 61 | lookAt pt s = |
58 | let position = pos s | 62 | let position = pos s |
@@ -61,15 +65,15 @@ class Spatial3 s where | |||
61 | u = r `cross` fwd | 65 | u = r `cross` fwd |
62 | in | 66 | in |
63 | setTransform (M.transform r u (-fwd) position) s | 67 | setTransform (M.transform r u (-fwd) position) s |
64 | 68 | ||
65 | -- | Make the 'Spatial' orbit around the given point | 69 | -- | Make the spatial orbit around the given point |
66 | orbit :: Vector3 -- ^ Target point | 70 | orbit :: Vector3 -- ^ Target point |
67 | -> Float -- ^ Horizontal angle | 71 | -> Float -- ^ Horizontal angle |
68 | -> Float -- ^ Vertical angle | 72 | -> Float -- ^ Vertical angle |
69 | -> Float -- ^ Orbit radius. | 73 | -> Float -- ^ Orbit radius. |
70 | -> s | 74 | -> s |
71 | -> s | 75 | -> s |
72 | 76 | ||
73 | orbit pt anglex angley radius s = | 77 | orbit pt anglex angley radius s = |
74 | let ax = anglex * pi / 180 | 78 | let ax = anglex * pi / 180 |
75 | ay = angley * pi / 180 | 79 | ay = angley * pi / 180 |
@@ -82,3 +86,59 @@ class Spatial3 s where | |||
82 | pz = (z pt) + radius*cx*cy | 86 | pz = (z pt) + radius*cx*cy |
83 | in | 87 | in |
84 | setPos (vec3 px py pz) s | 88 | setPos (vec3 px py pz) s |
89 | |||
90 | -- | An object in 3D space. | ||
91 | data Obj3 = Obj3 | ||
92 | { r :: Vector3 | ||
93 | , u :: Vector3 | ||
94 | , f :: Vector3 | ||
95 | , p :: Vector3 | ||
96 | } deriving Show | ||
97 | |||
98 | instance Spatial3 Obj3 where | ||
99 | move d o = o { p = p o + d } | ||
100 | moveFwd s o = o { p = p o + scale (-s) (f o) } | ||
101 | moveBack s o = o { p = p o + scale s (f o) } | ||
102 | strafeLeft s o = o { p = p o + scale (-s) (r o) } | ||
103 | strafeRight s o = o { p = p o + scale s (r o) } | ||
104 | pitch a o = | ||
105 | let a' = toRAD a | ||
106 | sa = sin a' | ||
107 | ca = cos a' | ||
108 | r' = normalise $ scale ca (r o) + scale sa (f o) | ||
109 | f' = normalise $ r' `cross` u o | ||
110 | in o { r = r', f = f' } | ||
111 | yaw a o = | ||
112 | let a' = toRAD a | ||
113 | sa = sin a' | ||
114 | ca = cos a' | ||
115 | f' = normalise $ scale ca (f o) + scale sa (u o) | ||
116 | u' = normalise $ r o `cross` f' | ||
117 | in o { u = u', f = f' } | ||
118 | roll a o = | ||
119 | let a' = toRAD a | ||
120 | sa = sin a' | ||
121 | ca = cos a' | ||
122 | u' = normalise $ scale ca (u o) - scale sa (r o) | ||
123 | f' = normalise $ f o `cross` u' | ||
124 | in o { u = u', f = f' } | ||
125 | pos = p | ||
126 | fwd = f | ||
127 | up = u | ||
128 | right = r | ||
129 | transform o = M.transform (r o) (u o) (f o) (p o) | ||
130 | setTransform t o = Obj3 | ||
131 | { r = M.right t | ||
132 | , u = M.up t | ||
133 | , f = M.forward t | ||
134 | , p = M.position t | ||
135 | } | ||
136 | setPos pos o = o { p = pos } | ||
137 | |||
138 | fromVectors :: Right3 -> Up3 -> Forward3 -> Position3 -> Obj3 | ||
139 | fromVectors = Obj3 | ||
140 | |||
141 | fromTransform :: Matrix4 -> Obj3 | ||
142 | fromTransform m = Obj3 (M.right m) (M.up m) (M.forward m) (M.position m) | ||
143 | |||
144 | toRAD = (*pi) . (/180) | ||
diff --git a/Spear/Scene/GameObject.hs b/Spear/Scene/GameObject.hs index ecbe7a1..30211f4 100644 --- a/Spear/Scene/GameObject.hs +++ b/Spear/Scene/GameObject.hs | |||
@@ -39,6 +39,7 @@ import qualified Spear.Math.Matrix3 as M3 | |||
39 | import qualified Spear.Math.Matrix4 as M4 | 39 | import qualified Spear.Math.Matrix4 as M4 |
40 | import Spear.Math.MatrixUtils | 40 | import Spear.Math.MatrixUtils |
41 | import qualified Spear.Math.Spatial2 as S2 | 41 | import qualified Spear.Math.Spatial2 as S2 |
42 | import qualified Spear.Math.Spatial3 as S3 | ||
42 | import Spear.Math.Utils | 43 | import Spear.Math.Utils |
43 | import Spear.Math.Vector | 44 | import Spear.Math.Vector |
44 | import qualified Spear.Render.AnimatedModel as AM | 45 | import qualified Spear.Render.AnimatedModel as AM |
@@ -264,7 +265,7 @@ goRender sprog aprog cam go = | |||
264 | axis' = axis go | 265 | axis' = axis go |
265 | a = angle go | 266 | a = angle go |
266 | proj = Cam.projection cam | 267 | proj = Cam.projection cam |
267 | view = M4.inverseTransform $ Cam.transform cam | 268 | view = M4.inverseTransform $ S3.transform cam |
268 | transf = S2.transform go | 269 | transf = S2.transform go |
269 | normal = fastNormalMatrix modelview | 270 | normal = fastNormalMatrix modelview |
270 | modelview = case style of | 271 | modelview = case style of |