PageRenderTime 57ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/CollisionTest.hs

https://github.com/mrd/hcullide
Haskell | 164 lines | 130 code | 25 blank | 9 comment | 5 complexity | 039879b21f7151322e447330d1c2510f MD5 | raw file
Possible License(s): BSD-3-Clause
  1. -- hcullide -- simple test program
  2. -- Author: Matthew Danish. License: BSD3 (see LICENSE file)
  3. --
  4. -- Simple test of the Cullide library. There is a bunch of spheres
  5. -- bouncing around an enclosed space. They turn red when they
  6. -- collide. You can change direction of orthographic projection using
  7. -- x, y, and z keys.
  8. module Main where
  9. import Graphics.Collision.Cullide
  10. import Graphics.UI.GLUT
  11. import Data.IORef ( IORef, newIORef )
  12. import System.Exit ( exitWith, ExitCode(ExitSuccess) )
  13. import System.Random
  14. data Axis = AxisX | AxisY | AxisZ
  15. data State = State { objs :: IORef [(Vector3d, Vector3d, IO ())]
  16. , axisOf :: IORef Axis }
  17. boundMinX = -2
  18. boundMaxX = 2
  19. boundMinY = -2
  20. boundMaxY = 2
  21. boundMinZ = -2
  22. boundMaxZ = 2
  23. light0Position = Vertex4 1 1 1 0
  24. light0Ambient = Color4 0.25 0.25 0.25 1
  25. light0Diffuse = Color4 1 1 1 1
  26. numObjs = 5
  27. objW = 0.3
  28. frameDelay = floor (1000.0 / 60.0)
  29. makeState0 = do
  30. let qstyle = (QuadricStyle (Just Smooth) GenerateTextureCoordinates Outside FillStyle)
  31. let w = objW
  32. dl1 <- defineNewList Compile (renderQuadric qstyle $ Sphere w 18 9)
  33. let actions = map (\ _ -> callList dl1)
  34. [ 1 .. numObjs ]
  35. objs <- flip mapM actions $ \ a -> do
  36. p <- randomVector3d
  37. v <- randomVector3d
  38. return (p, vecScale (0.01 / magnitude v) v, a)
  39. r_objs <- newIORef objs
  40. r_axis <- newIORef AxisZ
  41. return $ State r_objs r_axis
  42. main :: IO ()
  43. main = do
  44. (progName, _args) <- getArgsAndInitialize
  45. initialDisplayMode $= [ DoubleBuffered, RGBMode, WithDepthBuffer ]
  46. initialWindowSize $= Size 640 480
  47. initialWindowPosition $= Position 100 100
  48. createWindow progName
  49. myInit
  50. state0 <- makeState0
  51. displayCallback $= display state0
  52. reshapeCallback $= Just reshape
  53. addTimerCallback frameDelay $ computeFrame state0
  54. keyboardMouseCallback $= Just (keyboard state0)
  55. mainLoop
  56. computeFrame state = do
  57. os <- get (objs state)
  58. os' <- flip mapM os $ \ (p, v, a) -> do
  59. let Vector3 x y z = p
  60. let Vector3 vx vy vz = v
  61. let v' = Vector3 (if abs x > 1 then -vx else vx)
  62. (if abs y > 1 then -vy else vy)
  63. (if abs z > 1 then -vz else vz)
  64. return (p `vecAdd` v', v', a)
  65. objs state $= os'
  66. postRedisplay Nothing
  67. addTimerCallback frameDelay $ computeFrame state
  68. reshape :: ReshapeCallback
  69. reshape size = do
  70. viewport $= (Position 0 0, size)
  71. matrixMode $= Projection
  72. loadIdentity
  73. frustum (-1.0) 1.0 (-1.0) 1.0 2 10
  74. lookAt (Vertex3 0 0 4) (Vertex3 0 0 0) (Vector3 0 1 0)
  75. matrixMode $= Modelview 0
  76. display :: State -> DisplayCallback
  77. display state = do
  78. os <- get (objs state)
  79. -- collision detect
  80. collides <- detect (scaled (1/3, 1/3, 1/3)) . flip map os $ (\ (p, v, a) -> do
  81. preservingMatrix $ do
  82. translated' p
  83. a)
  84. clear [ ColorBuffer, DepthBuffer ]
  85. loadIdentity -- clear the matrix
  86. axis <- get (axisOf state)
  87. case axis of
  88. AxisX -> rotated (-90) (0, 1, 0)
  89. AxisY -> rotated ( 90) (1, 0, 0)
  90. AxisZ -> return ()
  91. flip mapM_ (zip os collides) $ \ ((p, v, a), c) -> do
  92. preservingMatrix $ do
  93. translated' p
  94. if c then color3d (1, 0, 0) else color3d (0, 1, 1)
  95. a
  96. swapBuffers
  97. myInit :: IO ()
  98. myInit = do
  99. clearColor $= Color4 0 0 0 0
  100. shadeModel $= Smooth
  101. polygonMode $= (Fill, Fill) -- fill front and back
  102. colorMaterial $= Just (Front, AmbientAndDiffuse)
  103. position (Light 0) $= light0Position
  104. ambient (Light 0) $= light0Ambient
  105. diffuse (Light 0) $= light0Diffuse
  106. lighting $= Enabled
  107. light (Light 0) $= Enabled
  108. normalize $= Enabled
  109. depthFunc $= Just Less
  110. keyboard :: State -> KeyboardMouseCallback
  111. keyboard state (Char '\27') Down _ _ = exitWith ExitSuccess
  112. keyboard state (Char 'x') Down _ _ = axisOf state $= AxisX
  113. keyboard state (Char 'y') Down _ _ = axisOf state $= AxisY
  114. keyboard state (Char 'z') Down _ _ = axisOf state $= AxisZ
  115. keyboard state _ _ _ _ = return ()
  116. -- utils
  117. randomVector3d :: IO Vector3d
  118. randomVector3d = do
  119. x <- randomRIO (-1, 1)
  120. y <- randomRIO (-1, 1)
  121. z <- randomRIO (-1, 1)
  122. return $ Vector3 x y z
  123. type Vector3d = Vector3 GLdouble
  124. uncurry3 f (a, b, c) = f a b c
  125. color3d' = color :: Color3 GLdouble -> IO ()
  126. color3d = color3d' . uncurry3 Color3
  127. scaled' = scale :: GLdouble -> GLdouble -> GLdouble -> IO ()
  128. scaled = uncurry3 scaled'
  129. vertex3d' = vertex :: Vertex3 GLdouble -> IO ()
  130. vertex3d = vertex3d' . uncurry3 Vertex3
  131. normal3d' = normal :: Normal3 GLdouble -> IO ()
  132. normal3d = normal3d' . uncurry3 Normal3
  133. rotated' = rotate :: GLdouble -> Vector3d -> IO ()
  134. rotated a = rotated' a . uncurry3 Vector3
  135. translated' = translate :: Vector3d -> IO ()
  136. translated = translated' . uncurry3 Vector3
  137. magnitude (Vector3 x y z) = sqrt (x*x + y*y + z*z)
  138. s `vecScale` Vector3 x y z = Vector3 (s*x) (s*y) (s*z)
  139. Vector3 x1 y1 z1 `vecAdd` Vector3 x2 y2 z2 = Vector3 (x1+x2) (y1+y2) (z1+z2)