diff options
author | Joe Crayne <joe@jerkface.net> | 2019-05-02 02:11:37 -0400 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2019-05-02 02:11:37 -0400 |
commit | 7853a4b2f025d6368564bc9ea6cbf72c36b6fcd9 (patch) | |
tree | bf64e077d14fbba3a44cd1e6d3ce37dbd25a287a | |
parent | a7998a03dccd5c879508e729559de20743c7dafd (diff) |
meshsketch: drag background.
-rw-r--r-- | MeshSketch.hs | 127 |
1 files changed, 121 insertions, 6 deletions
diff --git a/MeshSketch.hs b/MeshSketch.hs index 6d7e757..c88da0c 100644 --- a/MeshSketch.hs +++ b/MeshSketch.hs | |||
@@ -53,6 +53,7 @@ data State = State | |||
53 | , stSkyboxes :: Skyboxes | 53 | , stSkyboxes :: Skyboxes |
54 | , stSkybox :: IORef Int | 54 | , stSkybox :: IORef Int |
55 | , stSkyTexture :: IORef TextureData | 55 | , stSkyTexture :: IORef TextureData |
56 | , stDragFrom :: IORef (Maybe (Vector Float,Camera)) | ||
56 | } | 57 | } |
57 | 58 | ||
58 | data Camera = Camera | 59 | data Camera = Camera |
@@ -140,6 +141,8 @@ uploadState obj glarea storage = do | |||
140 | mi <- LC.uploadMeshToGPU cubeMesh | 141 | mi <- LC.uploadMeshToGPU cubeMesh |
141 | LC.addMeshToObjectArray storage "SkyCube" [] mi | 142 | LC.addMeshToObjectArray storage "SkyCube" [] mi |
142 | 143 | ||
144 | drag <- newIORef Nothing | ||
145 | |||
143 | let st = State | 146 | let st = State |
144 | { stAnimator = tm | 147 | { stAnimator = tm |
145 | , stCamera = cam | 148 | , stCamera = cam |
@@ -147,8 +150,9 @@ uploadState obj glarea storage = do | |||
147 | , stSkyboxes = skyboxes | 150 | , stSkyboxes = skyboxes |
148 | , stSkybox = skybox | 151 | , stSkybox = skybox |
149 | , stSkyTexture = skytex | 152 | , stSkyTexture = skytex |
153 | , stDragFrom = drag | ||
150 | } | 154 | } |
151 | _ <- addAnimation tm (whirlingCamera st) | 155 | -- _ <- addAnimation tm (whirlingCamera st) |
152 | 156 | ||
153 | return st | 157 | return st |
154 | 158 | ||
@@ -164,7 +168,7 @@ deg30 = pi/6 | |||
164 | whirlingCamera :: State -> Animation | 168 | whirlingCamera :: State -> Animation |
165 | whirlingCamera st = Animation $ \_ t -> do | 169 | whirlingCamera st = Animation $ \_ t -> do |
166 | let tf = realToFrac t :: Float | 170 | let tf = realToFrac t :: Float |
167 | rot = rotMatrixZ (-tf) <> rotMatrixX (-tf) | 171 | rot = rotMatrixZ (-tf/2) <> rotMatrixX (-tf/pi) |
168 | modifyIORef (stCamera st) $ \cam -> cam | 172 | modifyIORef (stCamera st) $ \cam -> cam |
169 | { camUp = rot #> fromList [0,1,0] | 173 | { camUp = rot #> fromList [0,1,0] |
170 | , camDirection = (scale (1/camDistance cam) $ fromList [-2,-2,-10]) <# rot | 174 | , camDirection = (scale (1/camDistance cam) $ fromList [-2,-2,-10]) <# rot |
@@ -285,10 +289,79 @@ onResize glarea realized w h = do | |||
285 | modifyIORef' (stCamera $ stState realized) | 289 | modifyIORef' (stCamera $ stState realized) |
286 | $ \c -> c { camWidth = fromIntegral wd | 290 | $ \c -> c { camWidth = fromIntegral wd |
287 | , camHeight = fromIntegral ht | 291 | , camHeight = fromIntegral ht |
292 | , camWorldToScreen = Nothing | ||
293 | , camScreenToWorld = Nothing | ||
288 | } | 294 | } |
289 | LC.setScreenSize (stStorage realized) wd ht) | 295 | LC.setScreenSize (stStorage realized) wd ht) |
290 | 296 | ||
291 | onEvent :: w -> Realized -> Event -> IO Bool | 297 | computeDirection :: Camera -> Double -> Double -> Vector Float |
298 | computeDirection cam h k = | ||
299 | let d̂ = camDirection cam -- forward | ||
300 | û = camUp cam -- upward | ||
301 | r̂ = d̂ `cross` û -- rightward | ||
302 | xr = realToFrac h - (camWidth cam / 2) | ||
303 | xu = (camHeight cam / 2) - realToFrac k | ||
304 | xd = (camHeight cam / 2) / tan (camHeightAngle cam / 2) | ||
305 | in scale xr r̂ + scale xu û + scale xd d̂ | ||
306 | |||
307 | rotate :: Float -> Vector Float -> Matrix Float | ||
308 | rotate cosθ u = (3><3) | ||
309 | [ cosθ + ux² mcosθ , (uy.uy)mcosθ - uz sinθ , (ux.uz)mcosθ + uy sinθ | ||
310 | , (uy.ux)mcosθ + uz sinθ , cosθ + uy² mcosθ , (uy.uz)mcosθ - ux sinθ | ||
311 | , (uz.ux)mcosθ - uy sinθ , (uz.uy)mcosθ + ux sinθ , cosθ + uz² mcosθ | ||
312 | ] | ||
313 | where | ||
314 | sinθ = sqrt (1 - cosθ * cosθ) | ||
315 | mcosθ = 1 - cosθ | ||
316 | û = scale (1/realToFrac (norm_2 u)) u | ||
317 | ux a = (û!0) * a | ||
318 | uy a = (û!1) * a | ||
319 | uz a = (û!2) * a | ||
320 | ux² = ux . ux | ||
321 | uy² = uy . uy | ||
322 | uz² = uz . uz | ||
323 | |||
324 | updateCameraRotation w st h k = do | ||
325 | m <- readIORef (stDragFrom st) | ||
326 | forM_ m $ \(df,cam) -> do | ||
327 | let d̂ = camDirection cam -- forward | ||
328 | û = camUp cam -- upward | ||
329 | r̂ = d̂ `cross` û -- rightward | ||
330 | -- fr = df `dot` r̂ | ||
331 | -- fu = df `dot` û | ||
332 | -- fd = df `dot` d̂ | ||
333 | dt = computeDirection cam h k | ||
334 | -- tr = dt `dot` r̂ | ||
335 | -- tu = dt `dot` û | ||
336 | -- td = dt `dot` d̂ | ||
337 | cosθ = dot df dt / realToFrac (norm_2 df) / realToFrac (norm_2 dt) | ||
338 | axis = df `cross` dt | ||
339 | cam' = cam | ||
340 | { camDirection = d̂ <# rotate cosθ axis | ||
341 | , camWorldToScreen = Nothing | ||
342 | , camScreenToWorld = Nothing | ||
343 | } | ||
344 | writeIORef (stCamera st) cam' | ||
345 | mwin <- widgetGetWindow w | ||
346 | forM_ mwin $ \win -> | ||
347 | windowInvalidateRect win Nothing False | ||
348 | |||
349 | sanitizeCamera st = do | ||
350 | modifyIORef (stCamera st) $ \cam -> | ||
351 | let d = camDirection cam | ||
352 | dd = norm_2 d | ||
353 | e = scale (realToFrac $ 1/dd) d | ||
354 | d̂ = if any isNaN (toList e) | ||
355 | then fromList [0,0,-1] | ||
356 | else e | ||
357 | in cam | ||
358 | { camDirection = d̂ | ||
359 | , camWorldToScreen = Nothing | ||
360 | , camScreenToWorld = Nothing | ||
361 | } | ||
362 | |||
363 | |||
364 | onEvent :: IsWidget w => w -> Realized -> Event -> IO Bool | ||
292 | onEvent w realized ev = do | 365 | onEvent w realized ev = do |
293 | let st = stState realized | 366 | let st = stState realized |
294 | msrc <- eventGetSourceDevice ev | 367 | msrc <- eventGetSourceDevice ev |
@@ -298,15 +371,54 @@ onEvent w realized ev = do | |||
298 | etype <- get ev #type | 371 | etype <- get ev #type |
299 | -- putStrLn $ "onEvent! " ++ show (etype,inputSource) | 372 | -- putStrLn $ "onEvent! " ++ show (etype,inputSource) |
300 | let put x = putStrLn (show inputSource ++ " " ++ show x) | 373 | let put x = putStrLn (show inputSource ++ " " ++ show x) |
374 | let st = stState realized | ||
301 | case etype of | 375 | case etype of |
302 | 376 | ||
303 | EventTypeMotionNotify -> do | 377 | EventTypeMotionNotify -> do |
304 | mev <- get ev #motion | 378 | mev <- get ev #motion |
305 | x <- get mev #x | 379 | h <- get mev #x |
306 | y <- get mev #y | 380 | k <- get mev #y |
307 | put (x,y) | 381 | {- |
382 | cam <- readIORef (stCamera st) | ||
383 | {- | ||
384 | let o = fromList [ camWidth cam / 2, camHeight cam / 2 ] | ||
385 | r = camHeight cam / (2 * sin (camHeight cam / 2)) | ||
386 | |||
387 | c = fromList [realToFrac h, realToFrac k] - o :: Vector Float | ||
388 | d = realToFrac $ norm_2 c | ||
389 | τ = asin (d / r) -- angle from center | ||
390 | axis = fromList [c!1, - (c!0)] :: Vector Float | ||
391 | -} | ||
392 | let d̂ = camDirection cam -- forward | ||
393 | û = camUp cam -- upward | ||
394 | r̂ = d̂ `cross` û -- rightward | ||
395 | x_r = realToFrac h - (camWidth cam / 2) | ||
396 | x_u = (camHeight cam / 2) - realToFrac k | ||
397 | x_d = (camHeight cam / 2) / tan (camHeightAngle cam / 2) | ||
398 | x = fromList [x_r,x_u,x_d] | ||
399 | -} | ||
400 | |||
401 | updateCameraRotation w st h k | ||
308 | return () | 402 | return () |
309 | 403 | ||
404 | EventTypeButtonPress -> do | ||
405 | bev <- get ev #button | ||
406 | h <- get bev #x | ||
407 | k <- get bev #y | ||
408 | cam <- readIORef (stCamera st) | ||
409 | let d = computeDirection cam h k | ||
410 | writeIORef (stDragFrom st) $ Just (d,cam) | ||
411 | put (etype,(h,k),d) | ||
412 | return () | ||
413 | |||
414 | EventTypeButtonRelease -> do | ||
415 | bev <- get ev #button | ||
416 | h <- get bev #x | ||
417 | k <- get bev #y | ||
418 | updateCameraRotation w st h k | ||
419 | sanitizeCamera st | ||
420 | writeIORef (stDragFrom st) Nothing | ||
421 | |||
310 | EventTypeScroll -> do | 422 | EventTypeScroll -> do |
311 | sev <- get ev #scroll | 423 | sev <- get ev #scroll |
312 | d <- get sev #direction | 424 | d <- get sev #direction |
@@ -320,6 +432,9 @@ onEvent w realized ev = do | |||
320 | , camWorldToScreen = Nothing | 432 | , camWorldToScreen = Nothing |
321 | , camScreenToWorld = Nothing | 433 | , camScreenToWorld = Nothing |
322 | } | 434 | } |
435 | mwin <- widgetGetWindow w | ||
436 | forM_ mwin $ \win -> | ||
437 | windowInvalidateRect win Nothing False | ||
323 | put d | 438 | put d |
324 | return () | 439 | return () |
325 | 440 | ||