This file is indexed.

/usr/share/doc/libghc-glut-doc/examples/Misc/Gears.hs is in libghc-glut-doc 2.1.2.2-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
{-
   Gears.hs (adapted from gears.c which is (c) Brian Paul)
   Copyright (c) Shawn P. Garbett 2004 <shawn@garbett.org>
   Further hacked by Sven Panne <sven.panne@aedion.de>
   This file is part of HOpenGL and distributed under a BSD-style license
   See the file libraries/GLUT/LICENSE

   Command line options:
     -info      print GL implementation information
     -exit      automatically exit after 30 seconds
-}

--------------------------------------------------------------------------------

import Control.Monad ( when )
import Data.IORef ( IORef, newIORef )
import Data.List ( intersperse )
import System.Console.GetOpt
import System.Exit ( exitWith, ExitCode(ExitSuccess), exitFailure )
import Graphics.UI.GLUT

--------------------------------------------------------------------------------

type View = (GLfloat, GLfloat, GLfloat)

data State = State {
   frames  :: IORef Int,
   t0      :: IORef Int,
   viewRot :: IORef View,
   angle'  :: IORef GLfloat }

makeState :: IO State
makeState = do
   f <- newIORef 0
   t <- newIORef 0
   v <- newIORef (20, 30, 0)
   a <- newIORef 0
   return $ State { frames = f, t0 = t, viewRot = v, angle' = a }

--  Draw a gear wheel.  You'll probably want to call this function when
--  building a display list since we do a lot of trig here.
--
--  Input: innerRadius - radius of hole at center
--         outerRadius - radius at center of teeth
--         width - width of gear
--         teeth - number of teeth
--         toothDepth - depth of tooth

gear :: GLfloat -> GLfloat -> GLfloat -> GLint -> GLfloat -> IO ()
gear innerRadius outerRadius width teeth toothDepth = do
   let r0 = innerRadius
       r1 = outerRadius - toothDepth / 2
       r2 = outerRadius + toothDepth / 2

       da = 2 * pi / fromIntegral teeth / 4
       w  = 0.5 * width

       render p f =
          renderPrimitive p $
             mapM_ (\i -> let angle = fromIntegral i * 2 * pi / fromIntegral teeth
                              in f r0 r1 r2 w da teeth i angle)
                   [ 0 .. teeth ]

   shadeModel $= Flat
   currentNormal $= Normal3 0 0 1
   render QuadStrip gearFront
   render Quads     teethFront
   currentNormal $= Normal3 0 0 (-1)
   render QuadStrip gearBack
   render Quads     teethBack
   render QuadStrip teethFace
   shadeModel $= Smooth
   render QuadStrip gearInside

type Renderer =
   GLfloat -> GLfloat -> GLfloat -> GLfloat -> GLfloat -> GLint -> GLint -> GLfloat -> IO ()

-- draw front face
gearFront :: Renderer
gearFront r0 r1 _ w da teeth i angle = do
   vertex (Vertex3 (r0 * cos angle) (r0 * sin angle) w)
   vertex (Vertex3 (r1 * cos angle) (r1 * sin angle) w)
   when (i < teeth) $ do
      vertex (Vertex3 (r0 * cos  angle          ) (r0 * sin  angle          ) w)
      vertex (Vertex3 (r1 * cos (angle + 3 * da)) (r1 * sin (angle + 3 * da)) w)

-- draw front sides of teeth
teethFront :: Renderer
teethFront _ r1 r2 w da teeth i angle =
   when (i < teeth) $ do
      vertex (Vertex3 (r1 * cos  angle          ) (r1 * sin  angle          ) w)
      vertex (Vertex3 (r2 * cos (angle +     da)) (r2 * sin (angle +     da)) w)
      vertex (Vertex3 (r2 * cos (angle + 2 * da)) (r2 * sin (angle + 2 * da)) w)
      vertex (Vertex3 (r1 * cos (angle + 3 * da)) (r1 * sin (angle + 3 * da)) w)

-- draw back face
gearBack :: Renderer
gearBack r0 r1 _ w da teeth i angle = do
   vertex (Vertex3 (r1 * cos angle) (r1 * sin angle) (-w))
   vertex (Vertex3 (r0 * cos angle) (r0 * sin angle) (-w))
   when (i < teeth) $ do
      vertex (Vertex3 (r1 * cos (angle + 3 * da)) (r1 * sin (angle + 3 * da)) (-w))
      vertex (Vertex3 (r0 * cos  angle          ) (r0 * sin  angle          ) (-w))

-- draw back sides of teeth
teethBack :: Renderer
teethBack _ r1 r2 w da teeth i angle =
   when (i < teeth) $ do
      vertex (Vertex3 (r1 * cos (angle + 3 * da)) (r1 * sin (angle + 3 * da)) (-w))
      vertex (Vertex3 (r2 * cos (angle + 2 * da)) (r2 * sin (angle + 2 * da)) (-w))
      vertex (Vertex3 (r2 * cos (angle +     da)) (r2 * sin (angle +     da)) (-w))
      vertex (Vertex3 (r1 * cos  angle          ) (r1 * sin  angle          ) (-w))

-- draw outward faces of teeth
teethFace :: Renderer
teethFace _ r1 r2 w da teeth i angle =
  if (i < teeth) then do
    vertex (Vertex3 (r1*(cos angle)) (r1*(sin angle)) w)
    vertex (Vertex3 (r1*(cos angle)) (r1*(sin angle)) (-w))

    let u'    = r2 * cos (angle + da) - r1 * cos angle
        v'    = r2 * sin (angle + da) - r1 * sin angle
        len   = sqrt (u' * u' + v' * v')
        u     = u' / len
        v     = v' / len
    currentNormal $= Normal3 v (-u) 0
    vertex (Vertex3 (r2 * cos (angle +     da)) (r2 * sin (angle +     da))   w )
    vertex (Vertex3 (r2 * cos (angle +     da)) (r2 * sin (angle +     da)) (-w))
    currentNormal $= Normal3 (cos angle) (sin angle) 0
    vertex (Vertex3 (r2 * cos (angle + 2 * da)) (r2 * sin (angle + 2 * da))   w )
    vertex (Vertex3 (r2 * cos (angle + 2 * da)) (r2 * sin (angle + 2 * da)) (-w))
    let u2    = r1 * cos (angle + 3 * da) - r2 * cos (angle + 2 * da);
        v2    = r1 * sin (angle + 3 * da) - r2 * sin (angle + 2 * da);
    currentNormal $= Normal3 v2 (-u2) 0
    vertex (Vertex3 (r1 * cos (angle + 3 * da)) (r1 * sin (angle + 3 * da))   w )
    vertex (Vertex3 (r1 * cos (angle + 3 * da)) (r1 * sin (angle + 3 * da)) (-w))
    currentNormal $= Normal3 (cos angle) (sin angle) 0
  else do
    vertex (Vertex3 (r1 * cos 0) (r1 * sin 0)   w )
    vertex (Vertex3 (r1 * cos 0) (r1 * sin 0) (-w))

-- draw inside radius cylinder
gearInside :: Renderer
gearInside r0 _ _ w _ _ _ angle = do
   currentNormal $= Normal3 (-cos angle) (-sin angle) 0
   vertex (Vertex3 (r0 * cos angle) (r0 * sin angle) (-w))
   vertex (Vertex3 (r0 * cos angle) (r0 * sin angle)   w )

draw :: (DisplayList,DisplayList,DisplayList,Int) -> State -> IO ()
draw (gear1, gear2, gear3, autoexit) state = do
   clear [ ColorBuffer, DepthBuffer ]
   (x, y, z) <- get (viewRot state)
   a <- get (angle' state)

   let translatef = translate :: Vector3 GLfloat -> IO ()
   preservingMatrix $ do
      rotate x (Vector3 1 0 0)
      rotate y (Vector3 0 1 0)
      rotate z (Vector3 0 0 1)

      preservingMatrix $ do
         translatef (Vector3 (-3) (-2) 0)
         rotate a (Vector3 0 0 1)
         callList gear1

      preservingMatrix $ do
         translatef (Vector3 3.1 (-2) 0)
         rotate (-2 * a - 9) (Vector3 0 0 1)
         callList gear2

      preservingMatrix $ do
         translatef (Vector3 (-3.1) 4.2 0)
         rotate (-2 * a - 25) (Vector3 0 0 1)
         callList gear3

   swapBuffers
   frames state $~! (+1)
   t0' <- get (t0 state)
   t <- get elapsedTime
   when (t - t0' >= 5000) $ do
      f <- get (frames state)
      let seconds = fromIntegral (t - t0') / 1000 :: GLfloat
          fps = fromIntegral f / seconds
      putStrLn (show f ++ " frames in " ++ show seconds ++ " seconds = "++ show fps ++ " FPS")
      t0 state $= t
      frames state $= 0
      when ((t >= 999 * autoexit) && (autoexit /= 0)) $
         exitWith ExitSuccess

idle :: State -> IdleCallback
idle state = do
   angle' state $~! (+2)
   postRedisplay Nothing

keyboard :: State -> KeyboardMouseCallback
keyboard state (Char 'z')           _ _ _ = modRot state ( 0,  0,  5)
keyboard state (Char 'Z')           _ _ _ = modRot state ( 0,  0, -5)
keyboard state (SpecialKey KeyUp)   _ _ _ = modRot state ( 5,  0,  0)
keyboard state (SpecialKey KeyDown) _ _ _ = modRot state (-5,  0,  0)
keyboard state (SpecialKey KeyLeft) _ _ _ = modRot state ( 0,  5,  0)
keyboard state (SpecialKey KeyRight)_ _ _ = modRot state ( 0, -5,  0)
keyboard _     (Char '\27')         _ _ _ = exitWith ExitSuccess
keyboard _     _                    _ _ _ = return ()

modRot :: State -> View -> IO ()
modRot state (dx,dy,dz) = do
   (x, y, z) <- get (viewRot state)
   viewRot state $= (x + dx, y + dy, z + dz)
   postRedisplay Nothing

-- new window size or exposure
reshape :: ReshapeCallback
reshape s@(Size width height) = do
   let h = fromIntegral height / fromIntegral width

   viewport $= (Position 0 0, s)
   matrixMode $= Projection
   loadIdentity
   frustum (-1) 1 (-h) h 5 60
   matrixMode $= Modelview 0
   loadIdentity
   translate (Vector3 0 0 (-40 :: GLfloat))

data Flag = GLInfo | AutoExit deriving ( Eq, Ord, Show )

argInfo :: [OptDescr Flag]
argInfo  = [
   Option ['i'] ["info"] (NoArg GLInfo)   "print gl information",
   Option ['e'] ["exit"] (NoArg AutoExit) "auto exit after 30 seconds" ]

opts :: [String] -> IO [Flag]
opts args =
   case getOpt Permute argInfo args of
      (o,_,[])   -> return o
      (_,_,errs) -> do
         putStr (concat errs ++ usageInfo "Usage: Gears [OPTION...]" argInfo)
         exitFailure

info :: IO ()
info = do
   rendererStr <- get renderer
   putStrLn ("GL_RENDERER   = " ++ rendererStr)
   vendorStr <- get vendor
   putStrLn ("GL_VENDOR     = " ++ vendorStr)
   versionStr <- get glVersion
   putStrLn ("GL_VERSION    = " ++ versionStr)
   exts <- get glExtensions
   putStrLn ("GL_EXTENSIONS = " ++ concat (intersperse " " exts))

myInit :: [String] -> IO (DisplayList,DisplayList,DisplayList,Int)
myInit args = do
   position (Light 0) $= Vertex4 5 5 10 0
   cullFace $= Just Back
   lighting $= Enabled
   light (Light 0) $= Enabled
   depthFunc $= Just Less

   -- make the gears
   g1 <- defineNewList Compile $ do
      materialAmbientAndDiffuse Front $= Color4 0.8 0.1 0.0 1.0
      gear 1 4 1 20 0.7

   g2 <- defineNewList Compile $ do
      materialAmbientAndDiffuse Front $= Color4 0.0 0.8 0.2 1.0
      gear 0.5 2 2 10 0.7

   g3 <- defineNewList Compile $ do
      materialAmbientAndDiffuse Front $= Color4 0.2 0.2 1.0 1.0
      gear 1.3 2 0.5 10 0.7

   normalize $= Enabled

   flags <- opts args
   when (GLInfo `elem` flags) info
   let autoexit = if AutoExit `elem` flags then 30 else 0
   when (autoexit /= 0) $
      putStrLn ("Auto Exit after " ++ show autoexit ++ " seconds.")

   return (g1, g2, g3, autoexit)

visible :: State -> Visibility -> IO ()
visible state Visible    = idleCallback $= Just (idle state)
visible _     NotVisible = idleCallback $= Nothing

main :: IO ()
main  = do
   (_progName, args) <- getArgsAndInitialize
   initialDisplayMode $= [ RGBMode, WithDepthBuffer, DoubleBuffered ]

   initialWindowPosition $= Position 0 0
   initialWindowSize $= Size 300 300
   createWindow "Gears"
   state <- makeState
   gearsAndAuto <- myInit args

   displayCallback $= draw gearsAndAuto state
   reshapeCallback $= Just reshape
   keyboardMouseCallback $= Just (keyboard state)
   visibilityCallback $= Just (visible state)

   mainLoop