-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathlesson11.hs
178 lines (162 loc) · 5.91 KB
/
lesson11.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
--
-- This code was created by Jeff Molofee '99 (ported to Haskell GHC 2005)
--
module Main where
import qualified Graphics.UI.GLFW as GLFW
-- everything from here starts with gl or GL
import Graphics.Rendering.OpenGL.Raw
import Graphics.Rendering.GLU.Raw ( gluPerspective )
import Data.Bits ( (.|.) )
import System.Exit ( exitWith, ExitCode(..) )
import Control.Monad ( forever, when, forM_, join )
import Data.IORef ( IORef, newIORef, readIORef, writeIORef )
import Foreign ( withForeignPtr, plusPtr, alloca, peek )
import qualified Data.ByteString.Internal as BSI
import Util ( Image(..), bitmapLoad )
import Data.Array.IO ( readArray, IOArray, newListArray )
import Control.Applicative ( (<$>), (<*>) )
import Paths_nehe_tuts
type Points = IOArray (Int, Int, Int) GLfloat
initGL :: GLFW.Window -> IO GLuint
initGL win = do
glEnable gl_TEXTURE_2D
glShadeModel gl_SMOOTH
glClearColor 0 0 0 0.5
glClearDepth 1
glEnable gl_DEPTH_TEST
glDepthFunc gl_LEQUAL
glHint gl_PERSPECTIVE_CORRECTION_HINT gl_NICEST
-- On some video cards/drivers this looks terrible
-- So if you get an ugly image, try commenting out
-- these two glPolygonMode lines
glPolygonMode gl_BACK gl_FILL
glPolygonMode gl_FRONT gl_LINE
(w,h) <- GLFW.getFramebufferSize win
resizeScene win w h
loadGLTextures
loadGLTextures :: IO GLuint
loadGLTextures = do
fp <- getDataFileName "tim.bmp"
Just (Image w h pd) <- bitmapLoad fp
putStrLn $ "Image w = " ++ show w
putStrLn $ "Image h = " ++ show h
tex <- alloca $ \p -> do
glGenTextures 1 p
peek p
let (ptr, off, _) = BSI.toForeignPtr pd
_ <- withForeignPtr ptr $ \p -> do
let p' = p `plusPtr` off
glNearest = fromIntegral gl_NEAREST
-- create linear filtered texture
glBindTexture gl_TEXTURE_2D tex
glTexImage2D gl_TEXTURE_2D 0 3
(fromIntegral w) (fromIntegral h)
0 gl_RGB gl_UNSIGNED_BYTE p'
glTexParameteri gl_TEXTURE_2D gl_TEXTURE_MAG_FILTER glNearest
glTexParameteri gl_TEXTURE_2D gl_TEXTURE_MIN_FILTER glNearest
return tex
shutdown :: GLFW.WindowCloseCallback
shutdown win = do
GLFW.destroyWindow win
GLFW.terminate
_ <- exitWith ExitSuccess
return ()
resizeScene :: GLFW.WindowSizeCallback
resizeScene win w 0 = resizeScene win w 1 -- prevent divide by zero
resizeScene _ width height = do
glViewport 0 0 (fromIntegral width) (fromIntegral height)
glMatrixMode gl_PROJECTION
glLoadIdentity
gluPerspective 45 (fromIntegral width/fromIntegral height) 0.1 100
glMatrixMode gl_MODELVIEW
glLoadIdentity
glFlush
drawScene :: GLuint -> IORef GLfloat -> IORef GLfloat -> IORef GLfloat
-> Points -> IORef Int -> IORef Int -> GLFW.Window -> IO ()
drawScene tex xrot yrot zrot points wiggleRef offsetRef _ = do
glClear $ fromIntegral $ gl_COLOR_BUFFER_BIT
.|. gl_DEPTH_BUFFER_BIT
glLoadIdentity
glTranslatef 0 0 (-12)
xr <- readIORef xrot
yr <- readIORef yrot
zr <- readIORef zrot
offset <- readIORef offsetRef
wiggle <- readIORef wiggleRef
glRotatef xr 1 0 0
glRotatef yr 0 1 0
glRotatef zr 0 0 1
glBindTexture gl_TEXTURE_2D tex
glBegin gl_QUADS
forM_ [(x,y) | x <- [0..43], y<-[0..43]] $ \(x,y) -> do
let x' = (x+offset) `mod` 45
fx = fromIntegral x/44 :: GLfloat
fy = fromIntegral y/44 :: GLfloat
fxb = fromIntegral (x+1)/44 :: GLfloat
fyb = fromIntegral (y+1)/44 :: GLfloat
glTexCoord2f fx fy
join $ glVertex3f <$> (readArray points (x,y,0))
<*> (readArray points (x,y,1))
<*> (readArray points (x',y,2))
glTexCoord2f fx fyb
join $ glVertex3f <$> (readArray points (x,y+1,0))
<*> (readArray points (x,y+1,1))
<*> (readArray points (x',y+1,2))
glTexCoord2f fxb fyb
join $ glVertex3f <$> (readArray points (x+1,y+1,0))
<*> (readArray points (x+1,y+1,1))
<*> (readArray points ((x'+1)`mod`45,y+1,2))
glTexCoord2f fxb fy
join $ glVertex3f <$> (readArray points (x+1,y,0))
<*> (readArray points (x+1,y,1))
<*> (readArray points ((x'+1)`mod`45,y,2))
glEnd
writeIORef xrot $! xr + 0.3
writeIORef yrot $! yr + 0.2
writeIORef zrot $! zr + 0.4
when (wiggle == 2) $ do
writeIORef offsetRef $! offset + 1
writeIORef wiggleRef $! 0
w <- readIORef wiggleRef
writeIORef wiggleRef $! w + 1
glFlush
keyPressed :: GLFW.KeyCallback
keyPressed win GLFW.Key'Escape _ GLFW.KeyState'Pressed _ = shutdown win
keyPressed _ _ _ _ _ = return ()
main :: IO ()
main = do
True <- GLFW.init
-- select type of display mode:
-- Double buffer
-- RGBA color
-- Alpha components supported
-- Depth buffer
GLFW.defaultWindowHints
-- open a window
Just win <- GLFW.createWindow 800 600 "Lesson 11" Nothing Nothing
GLFW.makeContextCurrent (Just win)
-- window starts at upper left corner of the screen
xrot <- newIORef 0
yrot <- newIORef 0
zrot <- newIORef 0
wiggle <- newIORef 0
offset <- newIORef 0
let elems = concat [[((x/5)-4.5),
((y/5)-4.5),
sin (((x/5)*40/360)*pi*2)]
| x <- [0..44]::[GLfloat], y <- [0..44]::[GLfloat] ]
points <- newListArray ((0,0,0), (44,44,2)) elems :: IO Points
-- initialize our window.
tex <- initGL win
GLFW.setWindowRefreshCallback win $
Just (drawScene tex xrot yrot zrot points wiggle offset)
-- register the funciton called when our window is resized
GLFW.setFramebufferSizeCallback win (Just resizeScene)
-- register the function called when the keyboard is pressed.
GLFW.setKeyCallback win $
Just keyPressed
GLFW.setWindowCloseCallback win (Just shutdown)
forever $ do
GLFW.pollEvents
drawScene tex xrot yrot zrot points wiggle offset win
GLFW.swapBuffers win