2014-02-05 16:33:32 +01:00
|
|
|
{-# LANGUAGE BangPatterns, DoAndIfThenElse #-}
|
2014-01-20 14:12:02 +01:00
|
|
|
module Main where
|
2014-01-03 03:01:54 +01:00
|
|
|
|
2014-01-20 23:18:07 +01:00
|
|
|
-- Monad-foo and higher functional stuff
|
|
|
|
import Control.Monad (unless, void, when, join)
|
|
|
|
import Control.Arrow ((***))
|
2014-01-20 19:28:02 +01:00
|
|
|
|
|
|
|
-- data consistency/conversion
|
|
|
|
import Control.Concurrent (threadDelay)
|
2014-02-04 14:11:16 +01:00
|
|
|
import Control.Concurrent.STM (TQueue,
|
|
|
|
newTQueueIO)
|
|
|
|
|
2014-01-05 20:23:22 +01:00
|
|
|
import Control.Monad.RWS.Strict (RWST, ask, asks,
|
|
|
|
evalRWST, get, liftIO,
|
|
|
|
modify, put)
|
2014-01-20 19:28:02 +01:00
|
|
|
import Data.Distributive (distribute, collect)
|
|
|
|
|
2014-01-20 14:12:02 +01:00
|
|
|
-- FFI
|
2014-01-05 20:23:22 +01:00
|
|
|
import Foreign (Ptr, castPtr, with)
|
|
|
|
import Foreign.C (CFloat)
|
2014-01-20 14:12:02 +01:00
|
|
|
|
|
|
|
-- Math
|
2014-02-04 14:11:16 +01:00
|
|
|
import Control.Lens ((^.))
|
2014-01-05 20:23:22 +01:00
|
|
|
import Linear as L
|
|
|
|
|
2014-01-20 14:12:02 +01:00
|
|
|
-- GUI
|
2014-01-20 19:28:02 +01:00
|
|
|
import Graphics.UI.SDL as SDL
|
2014-02-05 16:33:32 +01:00
|
|
|
import Graphics.UI.SDL.TTF as TTF
|
|
|
|
import Graphics.UI.SDL.TTF.Types
|
2014-01-20 14:12:02 +01:00
|
|
|
|
|
|
|
-- Render
|
2014-01-05 20:23:22 +01:00
|
|
|
import qualified Graphics.Rendering.OpenGL.GL as GL
|
|
|
|
import Graphics.Rendering.OpenGL.Raw.Core31
|
2014-01-20 19:28:02 +01:00
|
|
|
import Data.Time (getCurrentTime, UTCTime, diffUTCTime)
|
2014-01-05 20:23:22 +01:00
|
|
|
|
2014-01-21 16:18:48 +01:00
|
|
|
import Graphics.Rendering.OpenGL.Raw.ARB.TessellationShader
|
2014-01-20 14:12:02 +01:00
|
|
|
-- Our modules
|
2014-01-05 20:23:22 +01:00
|
|
|
import Map.Map
|
|
|
|
import Render.Misc (checkError,
|
|
|
|
createFrustum, getCam,
|
2014-02-04 14:11:16 +01:00
|
|
|
curb)
|
2014-01-05 20:23:22 +01:00
|
|
|
import Render.Render (initRendering,
|
|
|
|
initShader)
|
2014-02-05 16:33:32 +01:00
|
|
|
import UI.Callbacks
|
|
|
|
import Types
|
2014-01-03 03:01:54 +01:00
|
|
|
|
2014-01-20 19:28:02 +01:00
|
|
|
import qualified Debug.Trace as D (trace)
|
|
|
|
|
2014-01-20 16:11:34 +01:00
|
|
|
--------------------------------------------------------------------------------
|
2013-12-22 23:29:11 +01:00
|
|
|
main :: IO ()
|
2014-01-20 16:11:34 +01:00
|
|
|
main = do
|
2014-01-20 19:28:02 +01:00
|
|
|
SDL.withInit [InitVideo, InitAudio] $ do --also: InitNoParachute -> faster, without parachute!
|
2014-02-07 17:08:17 +01:00
|
|
|
SDL.withWindow "Pioneers" (Position 100 100) (Size 1024 600) [WindowOpengl -- we want openGL
|
2014-01-20 16:11:34 +01:00
|
|
|
,WindowShown -- window should be visible
|
|
|
|
,WindowResizable -- and resizable
|
|
|
|
,WindowInputFocus -- focused (=> active)
|
|
|
|
,WindowMouseFocus -- Mouse into it
|
2014-02-05 16:33:32 +01:00
|
|
|
,WindowInputGrabbed-- never let go of input (KB/Mouse)
|
2014-01-20 19:42:49 +01:00
|
|
|
] $ \window -> do
|
|
|
|
withOpenGL window $ do
|
2014-02-05 16:33:32 +01:00
|
|
|
TTF.withInit $ do
|
2014-01-20 16:11:34 +01:00
|
|
|
(Size fbWidth fbHeight) <- glGetDrawableSize window
|
|
|
|
initRendering
|
|
|
|
--generate map vertices
|
|
|
|
(mapBuffer, vert) <- getMapBufferObject
|
2014-01-21 16:44:42 +01:00
|
|
|
(ci, ni, vi, pri, vii, mi, nmi, tli, tlo) <- initShader
|
2014-01-20 19:28:02 +01:00
|
|
|
putStrLn "foo"
|
2014-01-20 16:11:34 +01:00
|
|
|
eventQueue <- newTQueueIO :: IO (TQueue Event)
|
2014-01-20 19:28:02 +01:00
|
|
|
putStrLn "foo"
|
|
|
|
now <- getCurrentTime
|
|
|
|
putStrLn "foo"
|
2014-02-05 16:33:32 +01:00
|
|
|
font <- TTF.openFont "fonts/ttf-04B_03B_/04B_03B_.TTF" 10
|
|
|
|
TTF.setFontStyle font TTFNormal
|
|
|
|
TTF.setFontHinting font TTFHNormal
|
2014-01-20 16:11:34 +01:00
|
|
|
|
2014-01-21 16:18:48 +01:00
|
|
|
let zDistClosest = 1
|
|
|
|
zDistFarthest = zDistClosest + 30
|
2014-02-04 14:11:16 +01:00
|
|
|
--TODO: Move near/far/fov to state for runtime-changability & central storage
|
2014-01-20 16:11:34 +01:00
|
|
|
fov = 90 --field of view
|
|
|
|
near = 1 --near plane
|
|
|
|
far = 100 --far plane
|
|
|
|
ratio = fromIntegral fbWidth / fromIntegral fbHeight
|
|
|
|
frust = createFrustum fov near far ratio
|
2014-01-20 23:18:07 +01:00
|
|
|
aks = ArrowKeyState {
|
|
|
|
arrowUp = False
|
|
|
|
,arrowDown = False
|
|
|
|
,arrowLeft = False
|
|
|
|
,arrowRight = False
|
|
|
|
}
|
2014-01-20 16:11:34 +01:00
|
|
|
env = Env
|
|
|
|
{ envEventsChan = eventQueue
|
|
|
|
, envWindow = window
|
|
|
|
, envZDistClosest = zDistClosest
|
|
|
|
, envZDistFarthest = zDistFarthest
|
2014-02-05 16:33:32 +01:00
|
|
|
, envFont = font
|
2014-01-20 16:11:34 +01:00
|
|
|
}
|
|
|
|
state = State
|
|
|
|
{ stateWindowWidth = fbWidth
|
|
|
|
, stateWindowHeight = fbHeight
|
|
|
|
, stateXAngle = pi/6
|
|
|
|
, stateYAngle = pi/2
|
|
|
|
, stateZDist = 10
|
|
|
|
, statePositionX = 5
|
|
|
|
, statePositionY = 5
|
2014-01-20 23:18:07 +01:00
|
|
|
, stateCursorPosX = 0
|
|
|
|
, stateCursorPosY = 0
|
2014-01-20 16:11:34 +01:00
|
|
|
, stateMouseDown = False
|
|
|
|
, stateDragging = False
|
|
|
|
, stateDragStartX = 0
|
|
|
|
, stateDragStartY = 0
|
|
|
|
, stateDragStartXAngle = 0
|
|
|
|
, stateDragStartYAngle = 0
|
|
|
|
, shdrVertexIndex = vi
|
|
|
|
, shdrNormalIndex = ni
|
|
|
|
, shdrColorIndex = ci
|
|
|
|
, shdrProjMatIndex = pri
|
|
|
|
, shdrViewMatIndex = vii
|
|
|
|
, shdrModelMatIndex = mi
|
|
|
|
, shdrNormalMatIndex = nmi
|
2014-01-21 16:44:42 +01:00
|
|
|
, shdrTessInnerIndex = tli
|
|
|
|
, shdrTessOuterIndex = tlo
|
2014-01-20 16:11:34 +01:00
|
|
|
, stateMap = mapBuffer
|
|
|
|
, mapVert = vert
|
|
|
|
, stateFrustum = frust
|
|
|
|
, stateWinClose = False
|
2014-01-20 19:28:02 +01:00
|
|
|
, stateClock = now
|
2014-01-20 23:18:07 +01:00
|
|
|
, stateArrowsPressed = aks
|
2014-01-21 16:44:42 +01:00
|
|
|
, stateTessellationFactor = 4
|
2014-01-20 16:11:34 +01:00
|
|
|
}
|
2014-01-20 19:28:02 +01:00
|
|
|
|
|
|
|
putStrLn "init done."
|
2014-01-20 16:11:34 +01:00
|
|
|
void $ evalRWST (adjustWindow >> run) env state
|
|
|
|
|
|
|
|
destroyWindow window
|
|
|
|
|
2014-01-20 19:28:02 +01:00
|
|
|
-- Render-Pipeline
|
|
|
|
|
|
|
|
draw :: Pioneers ()
|
|
|
|
draw = do
|
|
|
|
state <- get
|
|
|
|
let xa = stateXAngle state
|
|
|
|
ya = stateYAngle state
|
|
|
|
(GL.UniformLocation proj) = shdrProjMatIndex state
|
|
|
|
(GL.UniformLocation nmat) = shdrNormalMatIndex state
|
|
|
|
(GL.UniformLocation vmat) = shdrViewMatIndex state
|
2014-01-21 16:44:42 +01:00
|
|
|
(GL.UniformLocation tli) = shdrTessInnerIndex state
|
|
|
|
(GL.UniformLocation tlo) = shdrTessOuterIndex state
|
2014-01-20 19:28:02 +01:00
|
|
|
vi = shdrVertexIndex state
|
|
|
|
ni = shdrNormalIndex state
|
|
|
|
ci = shdrColorIndex state
|
|
|
|
numVert = mapVert state
|
|
|
|
map' = stateMap state
|
|
|
|
frust = stateFrustum state
|
|
|
|
camX = statePositionX state
|
|
|
|
camY = statePositionY state
|
|
|
|
zDist = stateZDist state
|
2014-01-21 16:44:42 +01:00
|
|
|
tessFac = stateTessellationFactor state
|
2014-01-20 19:28:02 +01:00
|
|
|
liftIO $ do
|
|
|
|
--(vi,GL.UniformLocation proj) <- initShader
|
|
|
|
GL.clear [GL.ColorBuffer, GL.DepthBuffer]
|
|
|
|
checkError "foo"
|
|
|
|
--set up projection (= copy from state)
|
2014-02-04 14:11:16 +01:00
|
|
|
with (distribute frust) $ \ptr ->
|
2014-01-20 19:28:02 +01:00
|
|
|
glUniformMatrix4fv proj 1 0 (castPtr (ptr :: Ptr (M44 CFloat)))
|
|
|
|
checkError "foo"
|
|
|
|
|
|
|
|
--set up camera
|
|
|
|
let ! cam = getCam (camX,camY) zDist xa ya
|
2014-02-04 14:11:16 +01:00
|
|
|
with (distribute cam) $ \ptr ->
|
2014-01-20 19:28:02 +01:00
|
|
|
glUniformMatrix4fv vmat 1 0 (castPtr (ptr :: Ptr (M44 CFloat)))
|
|
|
|
checkError "foo"
|
|
|
|
|
|
|
|
--set up normal--Mat transpose((model*camera)^-1)
|
2014-02-04 14:11:16 +01:00
|
|
|
let normal = (case inv33 (fmap (^. _xyz) cam ^. _xyz) of
|
2014-01-20 19:28:02 +01:00
|
|
|
(Just a) -> a
|
|
|
|
Nothing -> eye3) :: M33 CFloat
|
2014-02-04 14:11:16 +01:00
|
|
|
nmap = collect id normal :: M33 CFloat --transpose...
|
2014-01-20 19:28:02 +01:00
|
|
|
|
2014-02-04 14:11:16 +01:00
|
|
|
with (distribute nmap) $ \ptr ->
|
2014-01-20 19:28:02 +01:00
|
|
|
glUniformMatrix3fv nmat 1 0 (castPtr (ptr :: Ptr (M33 CFloat)))
|
|
|
|
|
|
|
|
checkError "nmat"
|
2014-01-21 16:44:42 +01:00
|
|
|
|
|
|
|
glUniform1f tli (fromIntegral tessFac)
|
|
|
|
glUniform1f tlo (fromIntegral tessFac)
|
2014-01-20 19:28:02 +01:00
|
|
|
|
|
|
|
GL.bindBuffer GL.ArrayBuffer GL.$= Just map'
|
|
|
|
GL.vertexAttribPointer ci GL.$= fgColorIndex
|
|
|
|
GL.vertexAttribArray ci GL.$= GL.Enabled
|
|
|
|
GL.vertexAttribPointer ni GL.$= fgNormalIndex
|
|
|
|
GL.vertexAttribArray ni GL.$= GL.Enabled
|
|
|
|
GL.vertexAttribPointer vi GL.$= fgVertexIndex
|
|
|
|
GL.vertexAttribArray vi GL.$= GL.Enabled
|
|
|
|
checkError "beforeDraw"
|
2014-01-21 16:18:48 +01:00
|
|
|
|
|
|
|
glPatchParameteri gl_PATCH_VERTICES 3
|
|
|
|
glPolygonMode gl_FRONT gl_LINE
|
2014-01-20 19:28:02 +01:00
|
|
|
|
2014-01-21 16:18:48 +01:00
|
|
|
glDrawArrays gl_PATCHES 0 (fromIntegral numVert)
|
2014-01-20 19:28:02 +01:00
|
|
|
checkError "draw"
|
|
|
|
|
|
|
|
|
2014-01-20 16:11:34 +01:00
|
|
|
-- Main game loop
|
|
|
|
|
|
|
|
run :: Pioneers ()
|
|
|
|
run = do
|
|
|
|
win <- asks envWindow
|
|
|
|
|
|
|
|
-- draw Scene
|
2014-01-20 20:04:21 +01:00
|
|
|
draw
|
2014-02-04 14:11:16 +01:00
|
|
|
liftIO $ glSwapWindow win
|
2014-01-20 16:11:34 +01:00
|
|
|
-- getEvents & process
|
|
|
|
processEvents
|
|
|
|
|
|
|
|
-- update State
|
|
|
|
|
|
|
|
state <- get
|
|
|
|
-- change in camera-angle
|
2014-01-20 23:18:07 +01:00
|
|
|
when (stateDragging state) $ do
|
2014-01-20 16:11:34 +01:00
|
|
|
let sodx = stateDragStartX state
|
|
|
|
sody = stateDragStartY state
|
|
|
|
sodxa = stateDragStartXAngle state
|
|
|
|
sodya = stateDragStartYAngle state
|
2014-01-20 23:18:07 +01:00
|
|
|
x = stateCursorPosX state
|
|
|
|
y = stateCursorPosY state
|
2014-01-20 16:11:34 +01:00
|
|
|
let myrot = (x - sodx) / 2
|
|
|
|
mxrot = (y - sody) / 2
|
|
|
|
newXAngle = curb (pi/12) (0.45*pi) newXAngle'
|
|
|
|
newXAngle' = sodxa + mxrot/100
|
|
|
|
newYAngle
|
|
|
|
| newYAngle' > pi = newYAngle' - 2 * pi
|
|
|
|
| newYAngle' < (-pi) = newYAngle' + 2 * pi
|
|
|
|
| otherwise = newYAngle'
|
|
|
|
newYAngle' = sodya + myrot/100
|
|
|
|
put $ state
|
|
|
|
{ stateXAngle = newXAngle
|
|
|
|
, stateYAngle = newYAngle
|
|
|
|
}
|
|
|
|
|
|
|
|
-- get cursor-keys - if pressed
|
|
|
|
--TODO: Add sin/cos from stateYAngle
|
2014-02-04 14:11:16 +01:00
|
|
|
(kxrot, kyrot) <- fmap (join (***) fromIntegral) getArrowMovement
|
2014-01-20 16:11:34 +01:00
|
|
|
modify $ \s ->
|
|
|
|
let
|
|
|
|
multc = cos $ stateYAngle s
|
|
|
|
mults = sin $ stateYAngle s
|
|
|
|
in
|
|
|
|
s {
|
|
|
|
statePositionX = statePositionX s - 0.2 * kxrot * multc
|
|
|
|
- 0.2 * kyrot * mults
|
|
|
|
, statePositionY = statePositionY s + 0.2 * kxrot * mults
|
|
|
|
- 0.2 * kyrot * multc
|
|
|
|
}
|
2014-01-20 23:18:07 +01:00
|
|
|
|
2014-01-20 16:11:34 +01:00
|
|
|
{-
|
|
|
|
--modify the state with all that happened in mt time.
|
|
|
|
mt <- liftIO GLFW.getTime
|
|
|
|
modify $ \s -> s
|
|
|
|
{
|
|
|
|
}
|
|
|
|
-}
|
2014-01-20 19:28:02 +01:00
|
|
|
mt <- liftIO $ do
|
|
|
|
now <- getCurrentTime
|
|
|
|
diff <- return $ diffUTCTime now (stateClock state) -- get time-diffs
|
2014-02-04 14:11:16 +01:00
|
|
|
title <- return $ unwords ["Pioneers @ ",show ((round .fromRational.toRational $ 1.0/diff)::Int),"fps"]
|
|
|
|
setWindowTitle win title
|
2014-01-20 19:28:02 +01:00
|
|
|
sleepAmount <- return $ floor (max 0 (0.04 - diff))*1000000 -- get time until next frame in microseconds
|
|
|
|
threadDelay sleepAmount
|
|
|
|
return now
|
|
|
|
-- set state with new clock-time
|
|
|
|
modify $ \s -> s
|
|
|
|
{
|
|
|
|
stateClock = mt
|
|
|
|
}
|
|
|
|
shouldClose <- return $ stateWinClose state
|
|
|
|
unless shouldClose run
|
2014-01-20 16:11:34 +01:00
|
|
|
|
2014-01-20 23:18:07 +01:00
|
|
|
getArrowMovement :: Pioneers (Int, Int)
|
|
|
|
getArrowMovement = do
|
|
|
|
state <- get
|
|
|
|
aks <- return $ stateArrowsPressed state
|
|
|
|
let
|
|
|
|
horz = left' + right'
|
|
|
|
vert = up'+down'
|
|
|
|
left' = if arrowLeft aks then -1 else 0
|
|
|
|
right' = if arrowRight aks then 1 else 0
|
|
|
|
up' = if arrowUp aks then -1 else 0
|
|
|
|
down' = if arrowDown aks then 1 else 0
|
|
|
|
return (horz,vert)
|
|
|
|
|
2014-01-20 16:11:34 +01:00
|
|
|
adjustWindow :: Pioneers ()
|
|
|
|
adjustWindow = do
|
|
|
|
state <- get
|
|
|
|
let fbWidth = stateWindowWidth state
|
|
|
|
fbHeight = stateWindowHeight state
|
|
|
|
fov = 90 --field of view
|
|
|
|
near = 1 --near plane
|
|
|
|
far = 100 --far plane
|
|
|
|
ratio = fromIntegral fbWidth / fromIntegral fbHeight
|
|
|
|
frust = createFrustum fov near far ratio
|
|
|
|
liftIO $ glViewport 0 0 (fromIntegral fbWidth) (fromIntegral fbHeight)
|
|
|
|
put $ state {
|
|
|
|
stateFrustum = frust
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
processEvents :: Pioneers ()
|
|
|
|
processEvents = do
|
2014-01-20 19:28:02 +01:00
|
|
|
me <- liftIO pollEvent
|
|
|
|
case me of
|
|
|
|
Just e -> do
|
|
|
|
processEvent e
|
|
|
|
processEvents
|
|
|
|
Nothing -> return ()
|
|
|
|
|
|
|
|
processEvent :: Event -> Pioneers ()
|
|
|
|
processEvent e = do
|
2014-01-20 20:04:21 +01:00
|
|
|
case eventData e of
|
2014-02-04 13:58:12 +01:00
|
|
|
Window _ winEvent ->
|
|
|
|
case winEvent of
|
|
|
|
Closing ->
|
|
|
|
modify $ \s -> s {
|
|
|
|
stateWinClose = True
|
2014-01-20 23:18:07 +01:00
|
|
|
}
|
2014-02-04 13:58:12 +01:00
|
|
|
Resized {windowResizedTo=size} -> do
|
|
|
|
modify $ \s -> s {
|
|
|
|
stateWindowWidth = sizeWidth size
|
|
|
|
,stateWindowHeight = sizeHeight size
|
|
|
|
}
|
|
|
|
adjustWindow
|
|
|
|
SizeChanged ->
|
|
|
|
adjustWindow
|
2014-02-04 14:15:15 +01:00
|
|
|
_ ->
|
|
|
|
return ()
|
|
|
|
--liftIO $ putStrLn $ unwords ["Unhandled Window-Event:",show e]
|
2014-02-04 14:11:16 +01:00
|
|
|
Keyboard movement _ isRepeated key -> --up/down window(ignored) true/false actualKey
|
2014-02-04 13:58:12 +01:00
|
|
|
-- need modifiers? use "keyModifiers key" to get them
|
|
|
|
case keyScancode key of
|
|
|
|
Escape ->
|
2014-01-20 23:18:07 +01:00
|
|
|
modify $ \s -> s {
|
2014-02-04 13:58:12 +01:00
|
|
|
stateWinClose = True
|
2014-01-20 23:18:07 +01:00
|
|
|
}
|
2014-02-04 13:58:12 +01:00
|
|
|
SDL.Left ->
|
|
|
|
modify $ \s -> s {
|
|
|
|
stateArrowsPressed = (stateArrowsPressed s) {
|
|
|
|
arrowLeft = movement == KeyDown
|
|
|
|
}
|
2014-01-20 23:18:07 +01:00
|
|
|
}
|
2014-02-04 13:58:12 +01:00
|
|
|
SDL.Right ->
|
|
|
|
modify $ \s -> s {
|
|
|
|
stateArrowsPressed = (stateArrowsPressed s) {
|
|
|
|
arrowRight = movement == KeyDown
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SDL.Up ->
|
|
|
|
modify $ \s -> s {
|
|
|
|
stateArrowsPressed = (stateArrowsPressed s) {
|
|
|
|
arrowUp = movement == KeyDown
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SDL.Down ->
|
|
|
|
modify $ \s -> s {
|
|
|
|
stateArrowsPressed = (stateArrowsPressed s) {
|
|
|
|
arrowDown = movement == KeyDown
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SDL.KeypadPlus ->
|
|
|
|
when (movement == KeyDown) $ do
|
|
|
|
modify $ \s -> s {
|
2014-02-04 14:11:16 +01:00
|
|
|
stateTessellationFactor = min (stateTessellationFactor s + 1) 5
|
2014-02-04 13:58:12 +01:00
|
|
|
}
|
|
|
|
state <- get
|
|
|
|
liftIO $ putStrLn $ unwords ["Tessellation at: ", show $ stateTessellationFactor state]
|
|
|
|
SDL.KeypadMinus ->
|
|
|
|
when (movement == KeyDown) $ do
|
|
|
|
modify $ \s -> s {
|
2014-02-04 14:11:16 +01:00
|
|
|
stateTessellationFactor = max (stateTessellationFactor s - 1) 1
|
2014-02-04 13:58:12 +01:00
|
|
|
}
|
|
|
|
state <- get
|
|
|
|
liftIO $ putStrLn $ unwords ["Tessellation at: ", show $ stateTessellationFactor state]
|
|
|
|
_ ->
|
|
|
|
return ()
|
2014-02-04 14:11:16 +01:00
|
|
|
MouseMotion _ mouseId st (Position x y) xrel yrel -> do
|
2014-02-04 13:58:12 +01:00
|
|
|
state <- get
|
|
|
|
when (stateMouseDown state && not (stateDragging state)) $
|
|
|
|
put $ state
|
|
|
|
{ stateDragging = True
|
|
|
|
, stateDragStartX = fromIntegral x
|
|
|
|
, stateDragStartY = fromIntegral y
|
|
|
|
, stateDragStartXAngle = stateXAngle state
|
|
|
|
, stateDragStartYAngle = stateYAngle state
|
|
|
|
}
|
|
|
|
modify $ \s -> s {
|
|
|
|
stateCursorPosX = fromIntegral x
|
|
|
|
, stateCursorPosY = fromIntegral y
|
|
|
|
}
|
2014-02-04 14:11:16 +01:00
|
|
|
MouseButton _ mouseId button state (Position x y) ->
|
2014-02-04 13:58:12 +01:00
|
|
|
case button of
|
|
|
|
LeftButton -> do
|
|
|
|
let pressed = state == Pressed
|
2014-01-20 23:18:07 +01:00
|
|
|
modify $ \s -> s {
|
2014-02-04 13:58:12 +01:00
|
|
|
stateMouseDown = pressed
|
2014-01-20 23:18:07 +01:00
|
|
|
}
|
2014-02-05 16:33:32 +01:00
|
|
|
unless pressed $ do
|
|
|
|
st <- get
|
|
|
|
if stateDragging st then
|
|
|
|
modify $ \s -> s {
|
|
|
|
stateDragging = False
|
|
|
|
}
|
|
|
|
else
|
|
|
|
clickHandler (UI.Callbacks.Pixel x y)
|
|
|
|
RightButton -> do
|
|
|
|
when (state == Released) $ alternateClickHandler (UI.Callbacks.Pixel x y)
|
2014-02-04 13:58:12 +01:00
|
|
|
_ ->
|
|
|
|
return ()
|
2014-02-04 14:11:16 +01:00
|
|
|
MouseWheel _ mouseId hscroll vscroll -> do
|
2014-02-04 13:58:12 +01:00
|
|
|
env <- ask
|
|
|
|
modify $ \s -> s
|
|
|
|
{ stateZDist =
|
2014-02-04 14:11:16 +01:00
|
|
|
let zDist' = stateZDist s + realToFrac (negate vscroll)
|
2014-02-04 13:58:12 +01:00
|
|
|
in curb (envZDistClosest env) (envZDistFarthest env) zDist'
|
|
|
|
}
|
|
|
|
Quit -> modify $ \s -> s {stateWinClose = True}
|
|
|
|
-- there is more (joystic, touchInterface, ...), but currently ignored
|
2014-02-07 17:08:23 +01:00
|
|
|
_ -> liftIO $ putStrLn $ unwords ["Not processing Event:", show e]
|