-
Notifications
You must be signed in to change notification settings - Fork 3
/
test_mouse.hs
187 lines (159 loc) · 5.97 KB
/
test_mouse.hs
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
import Graphics.Rendering.OpenGL as GL
import Graphics.UI.GLFW as GLFW
import Graphics.Rendering.OpenGL (($=))
import Data.IORef
import Control.Monad
import System.Environment (getArgs, getProgName)
data Action = Action (IO Action)
main = do
-- invoke either active or passive drawing loop depending on command line argument
args <- getArgs
prog <- getProgName
case args of
["active"] -> putStrLn "Running in active mode" >> main' active
["passive"] -> putStrLn "Running in passive mode" >> main' passive
_ -> putStrLn $ "USAGE: " ++ prog ++ " [active|passive]"
main' run = do
GLFW.initialize
-- open window
GLFW.openWindow (GL.Size 400 400) [GLFW.DisplayAlphaBits 8] GLFW.Window
GLFW.windowTitle $= "GLFW Demo"
GL.shadeModel $= GL.Smooth
-- enable antialiasing
GL.lineSmooth $= GL.Enabled
GL.blend $= GL.Enabled
GL.blendFunc $= (GL.SrcAlpha, GL.OneMinusSrcAlpha)
GL.lineWidth $= 1.5
-- set the color to clear background
GL.clearColor $= Color4 0 0 0 0
-- set 2D orthogonal view inside windowSizeCallback because
-- any change to the Window size should result in different
-- OpenGL Viewport.
GLFW.windowSizeCallback $= \ size@(GL.Size w h) ->
do
GL.viewport $= (GL.Position 0 0, size)
GL.matrixMode $= GL.Projection
GL.loadIdentity
GL.ortho2D 0 (realToFrac w) (realToFrac h) 0
-- keep all line strokes as a list of points in an IORef
lines <- newIORef []
-- run the main loop
run lines
-- finish up
GLFW.closeWindow
GLFW.terminate
-- we start with waitForPress action
active lines = loop waitForPress
where
loop action = do
-- draw the entire screen
render lines
-- swap buffer
GLFW.swapBuffers
-- check whether ESC is pressed for termination
p <- GLFW.getKey GLFW.ESC
unless (p == GLFW.Press) $
do
-- perform action
Action action' <- action
-- sleep for 1ms to yield CPU to other applications
GLFW.sleep 0.001
-- only continue when the window is not closed
windowOpen <- getParam Opened
unless (not windowOpen) $
loop action' -- loop with next action
waitForPress = do
b <- GLFW.getMouseButton GLFW.ButtonLeft
case b of
GLFW.Release -> return (Action waitForPress)
GLFW.Press -> do
-- when left mouse button is pressed, add the point
-- to lines and switch to waitForRelease action.
(GL.Position x y) <- GL.get GLFW.mousePos
modifyIORef lines (((x,y):) . ((x,y):))
return (Action waitForRelease)
waitForRelease = do
-- keep track of mouse movement while waiting for button
-- release
(GL.Position x y) <- GL.get GLFW.mousePos
-- update the line with new ending position
modifyIORef lines (((x,y):) . tail)
b <- GLFW.getMouseButton GLFW.ButtonLeft
case b of
-- when button is released, switch back back to
-- waitForPress action
GLFW.Release -> return (Action waitForPress)
GLFW.Press -> return (Action waitForRelease)
passive lines = do
-- disable auto polling in swapBuffers
GLFW.disableSpecial GLFW.AutoPollEvent
-- keep track of whether ESC has been pressed
quit <- newIORef False
-- keep track of whether screen needs to be redrawn
dirty <- newIORef True
-- mark screen dirty in refresh callback which is often called
-- when screen or part of screen comes into visibility.
GLFW.windowRefreshCallback $= writeIORef dirty True
-- use key callback to track whether ESC is pressed
GLFW.keyCallback $= \k s ->
when (fromEnum k == fromEnum GLFW.ESC && s == GLFW.Press) $
writeIORef quit True
-- Terminate the program if the window is closed
GLFW.windowCloseCallback $= (writeIORef quit True >> return True)
-- by default start with waitForPress
waitForPress dirty
loop dirty quit
where
loop dirty quit = do
GLFW.waitEvents
-- redraw screen if dirty
d <- readIORef dirty
when d $
render lines >> GLFW.swapBuffers
writeIORef dirty False
-- check if we need to quit the loop
q <- readIORef quit
unless q $
loop dirty quit
waitForPress dirty =
do
--GLFW.mousePosCallback $= \_ -> return ()
GLFW.mousePosCallback $= \s ->
when (True) $
do
-- when left mouse button is pressed, add the point
-- to lines and switch to waitForRelease action.
(GL.Position x y) <- GL.get GLFW.mousePos
modifyIORef lines (((x,y):) . ((x,y):))
waitForRelease dirty
GLFW.mouseButtonCallback $= \b s ->
when (b == GLFW.ButtonLeft && s == GLFW.Press) $
do
-- when left mouse button is pressed, add the point
-- to lines and switch to waitForRelease action.
(GL.Position x y) <- GL.get GLFW.mousePos
modifyIORef lines (((x,y):) . ((x,y):))
waitForRelease dirty
waitForRelease dirty =
do
GLFW.mousePosCallback $= \(Position x y) ->
do
-- update the line with new ending position
modifyIORef lines (((x,y):) . tail)
-- mark screen dirty
writeIORef dirty True
GLFW.mouseButtonCallback $= \b s ->
-- when left mouse button is released, switch back to
-- waitForPress action.
when (b == GLFW.ButtonLeft && s == GLFW.Release) $
waitForPress dirty
render lines = do
l <- readIORef lines
GL.clear [GL.ColorBuffer]
GL.color $ color3 1 0 0
GL.renderPrimitive GL.Lines $ mapM_
(\ (x, y) -> GL.vertex (vertex3 (fromIntegral x) (fromIntegral y) 0)) l
vertex3 :: GLfloat -> GLfloat -> GLfloat -> GL.Vertex3 GLfloat
vertex3 = GL.Vertex3
color3 :: GLfloat -> GLfloat -> GLfloat -> GL.Color3 GLfloat
color3 = GL.Color3