diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2022-12-03 17:37:59 -0700 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2022-12-03 17:37:59 -0700 |
commit | ba59711a51b4fee34009b1fe6afdce9ef8e60ae0 (patch) | |
tree | 7274bd2c9007abe08c8db7cea9e55babfd041125 /Resources.hs | |
parent | 601f77922490888c3ae9986674e332a5192008ec (diff) | |
download | terralloc-master.tar.gz terralloc-master.tar.bz2 terralloc-master.zip |
Diffstat (limited to 'Resources.hs')
-rw-r--r-- | Resources.hs | 1407 |
1 files changed, 734 insertions, 673 deletions
diff --git a/Resources.hs b/Resources.hs index ce38b21..da5040e 100644 --- a/Resources.hs +++ b/Resources.hs @@ -1,580 +1,612 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE LambdaCase #-} -module Resources where -import qualified SDL -import qualified SDL.Image +module Resources where -import Foreign.Storable -import Foreign.Ptr +import Control.Applicative +import Control.Concurrent +import Control.Monad +import Data.Angle +import Data.Array +import qualified Data.Array.IO as ArrIO +import qualified Data.Foldable as Fold +import Data.Function +import Data.Maybe +import qualified Data.Sequence as Seq +import qualified Data.StateVar as SV +import Data.Time.Clock.POSIX +import Debug.Trace import Foreign.Marshal.Array - +import Foreign.Ptr +import Foreign.Storable +import Graphics.GL.Compatibility30 +import Graphics.Glyph.BufferBuilder +import Graphics.Glyph.ExtendedGL as Ex import Graphics.Glyph.GLMath as V import Graphics.Glyph.GlyphObject +import Graphics.Glyph.Mat4 import Graphics.Glyph.ObjLoader import Graphics.Glyph.Shaders -import Graphics.SDL.SDLHelp -import Graphics.Glyph.BufferBuilder -import Graphics.Glyph.Mat4 import Graphics.Glyph.Util -import Graphics.Glyph.ExtendedGL as Ex import Graphics.Rendering.OpenGL as GL -import Graphics.GL.Compatibility30 - -import Control.Applicative -import Control.Monad - -import Data.Angle -import Data.Function -import qualified Data.Sequence as Seq -import qualified Data.Foldable as Fold -import Data.Maybe -import Debug.Trace - +import Graphics.SDL.SDLHelp +import qualified SDL +import qualified SDL.Image import System.Exit -import qualified Data.Array.IO as ArrIO - -import Data.Array -import qualified Data.StateVar as SV -import Data.Time.Clock.POSIX -import Control.Concurrent -import Text.Printf import System.IO import System.Random hiding (uniform) -import qualified SDL +import Text.Printf {- Types of terrain which are possible -} -data TileType = Forest | Beach | Water | Grass | Jungle | Mountains | - Tundra | Unknown deriving (Enum,Eq) +data TileType + = Forest + | Beach + | Water + | Grass + | Jungle + | Mountains + | Tundra + | Unknown + deriving (Enum, Eq) + instance Show TileType where - show = \case - Forest -> "F" - Beach -> "B" - Water -> "W" - Grass -> "G" - Jungle -> "J" - Mountains -> "M" - Tundra -> "T" - Unknown -> "?" + show = \case + Forest -> "F" + Beach -> "B" + Water -> "W" + Grass -> "G" + Jungle -> "J" + Mountains -> "M" + Tundra -> "T" + Unknown -> "?" {- A tile has 2 things, a type and - elevation, however, the term tile is - a litte misleading, it is really a point. -} -data Tile = Tile { - tileType :: TileType, +data Tile = Tile + { tileType :: TileType, elevation :: Int -} deriving Show + } + deriving (Show) {- Position of the camera as described by - polar coordinates -} -data CameraPosition = CameraPosition { - pEye :: Vec3 GLfloat, +data CameraPosition = CameraPosition + { pEye :: Vec3 GLfloat, pTh :: GLfloat, pPh :: GLfloat -} deriving Show + } + deriving (Show) {- The central data type for rendering - the scene. Contains the 'global' information -} -data Resources = Resources { - rWindow :: SDL.Window, - +data Resources = Resources + { rWindow :: SDL.Window, rPosition :: CameraPosition, rDPosition :: CameraPosition, - pMatrix :: Mat4 GLfloat, mvMatrix :: Mat4 GLfloat, - routines :: [ResourcesClosure -> IO ()], - timeSpeed :: Int, time :: Int, - - heightMap :: Array (Int,Int) Tile, + heightMap :: Array (Int, Int) Tile, positionUpdate :: (Resources -> IO Resources), - {- Smaller if in first person -} speedFactor :: GLfloat, {- Higher if shift is held -} speedMultiplier :: GLfloat, {- Direction -} speedDirection :: Vec3 GLfloat, - dDown :: GLfloat, - waterArray :: ArrIO.IOArray (Int,Int) GLfloat, + waterArray :: ArrIO.IOArray (Int, Int) GLfloat, headBob :: GLfloat, mode :: CameraMode, threadDiff :: Double -} + } setHeadBob :: GLfloat -> Resources -> Resources -setHeadBob f r = r { headBob = f } +setHeadBob f r = r {headBob = f} setThreadDiff :: Double -> Resources -> Resources -setThreadDiff f r = r { threadDiff = f } +setThreadDiff f r = r {threadDiff = f} setRSurface :: SDL.Window -> Resources -> Resources -setRSurface x r = r { rWindow = x } +setRSurface x r = r {rWindow = x} setRPosition :: CameraPosition -> Resources -> Resources -setRPosition x r = r { rPosition = x } +setRPosition x r = r {rPosition = x} setRDPosition :: CameraPosition -> Resources -> Resources -setRDPosition x r = r { rDPosition = x } +setRDPosition x r = r {rDPosition = x} setPMatrix :: Mat4 GLfloat -> Resources -> Resources -setPMatrix x r = r { pMatrix = x } +setPMatrix x r = r {pMatrix = x} setMvMatrix :: Mat4 GLfloat -> Resources -> Resources -setMvMatrix x r = r { mvMatrix = x } +setMvMatrix x r = r {mvMatrix = x} setRoutines :: [ResourcesClosure -> IO ()] -> Resources -> Resources -setRoutines x r = r { routines = x } +setRoutines x r = r {routines = x} setSpeedDirection :: Vec3 GLfloat -> Resources -> Resources -setSpeedDirection x r = r { speedDirection = x } +setSpeedDirection x r = r {speedDirection = x} setTimeSpeed :: Int -> Resources -> Resources -setTimeSpeed x r = r { timeSpeed = x } +setTimeSpeed x r = r {timeSpeed = x} setTime :: Int -> Resources -> Resources -setTime x r = r { time = x } +setTime x r = r {time = x} -setHeightMap :: Array (Int,Int) Tile -> Resources -> Resources -setHeightMap x r = r { heightMap = x } +setHeightMap :: Array (Int, Int) Tile -> Resources -> Resources +setHeightMap x r = r {heightMap = x} setPositionUpdate :: (Resources -> IO Resources) -> Resources -> Resources -setPositionUpdate x r = r { positionUpdate = x } +setPositionUpdate x r = r {positionUpdate = x} setSpeedFactor :: GLfloat -> Resources -> Resources -setSpeedFactor x r = r { speedFactor = x } +setSpeedFactor x r = r {speedFactor = x} setDDown :: GLfloat -> Resources -> Resources -setDDown x r = r { dDown = x } +setDDown x r = r {dDown = x} -setWaterArray :: ArrIO.IOArray (Int,Int) GLfloat -> Resources -> Resources -setWaterArray x r = r { waterArray = x } +setWaterArray :: ArrIO.IOArray (Int, Int) GLfloat -> Resources -> Resources +setWaterArray x r = r {waterArray = x} getSpeed :: Resources -> GLfloat -getSpeed res =speedFactor res * speedMultiplier res * norm (speedDirection res) +getSpeed res = speedFactor res * speedMultiplier res * norm (speedDirection res) cameraForward :: CameraPosition -> Vec3 GLfloat -cameraForward (CameraPosition _ th ph) = Vec3 $ toEuclidian (1,th,ph) +cameraForward (CameraPosition _ th ph) = Vec3 $ toEuclidian (1, th, ph) cameraUp :: CameraPosition -> Vec3 GLfloat -cameraUp (CameraPosition _ _ ph) = - if ph' >= 90 && ph' < 270 then Vec3 (0,-1,0) else Vec3 (0,1,0) - where ph' = (floor ph::Int) `mod` 360 +cameraUp (CameraPosition _ _ ph) = + if ph' >= 90 && ph' < 270 then Vec3 (0, -1, 0) else Vec3 (0, 1, 0) + where + ph' = (floor ph :: Int) `mod` 360 cameraRight :: CameraPosition -> Vec3 GLfloat cameraRight cam = cameraUp cam × cameraForward cam - getVelocity :: Resources -> Vec3 GLfloat getVelocity res = - let dir = speedDirection res - camdir = cameraForward $ rPosition res - truedir = coordinateConvert camdir (Vec3 (0,1,0)) dir in - getSpeed res `vScale` maybeNormalize truedir + let dir = speedDirection res + camdir = cameraForward $ rPosition res + truedir = coordinateConvert camdir (Vec3 (0, 1, 0)) dir + in getSpeed res `vScale` maybeNormalize truedir -data CameraMode = Oracle | FirstPerson deriving Eq +data CameraMode = Oracle | FirstPerson deriving (Eq) {- Central data type for rendering each frame -} -data ResourcesClosure = ResourcesClosure { - rcMVMatrix :: Mat4 GLfloat - , rcPMatrix :: Mat4 GLfloat - , rcLightPos :: Vec4 GLfloat - , rcTime :: GLfloat - , rcNormalMatrix :: Mat3 GLfloat - , rcGlobalAmbient :: Vec4 GLfloat - , rcCameraPos :: CameraPosition - , rcCameraLocation :: Vec3 GLfloat - , rcResources :: Resources -} +data ResourcesClosure = ResourcesClosure + { rcMVMatrix :: Mat4 GLfloat, + rcPMatrix :: Mat4 GLfloat, + rcLightPos :: Vec4 GLfloat, + rcTime :: GLfloat, + rcNormalMatrix :: Mat3 GLfloat, + rcGlobalAmbient :: Vec4 GLfloat, + rcCameraPos :: CameraPosition, + rcCameraLocation :: Vec3 GLfloat, + rcResources :: Resources + } {- A function that makes the resources data first - person -} firstPerson :: Resources -> IO Resources firstPerson res = - let camera@(CameraPosition (Vec3 (x,curh,y)) th ph) = rPosition res - (_,(w,h)) = bounds $ heightMap res - (!!!) arr (x',y') = if x' < 0 || y' < 0 || x' > w || y' > h then -1000 else elevation (arr ! (x',y')) - h1 = ((/10.0).fromIntegral) (heightMap res !!! (floor x, floor y) ) - h2 = ((/10.0).fromIntegral) (heightMap res !!! (floor x, floor (y+1)) ) - h3 = ((/10.0).fromIntegral) (heightMap res !!! (floor (x+1), floor y) ) - h4 = ((/10.0).fromIntegral) (heightMap res !!! (floor (x+1), floor (y+1))) - u = x - (int $ (floor x::Int)) - v = y - (int $ (floor y::Int)) - mixu1 = mix h3 h1 u - mixu2 = mix h4 h2 u - newh = mix mixu2 mixu1 v - droph = curh - dDown res - speed = getSpeed res - jitter = (max 0 $ speed - 0.029) ** 0.1 / 2 - dy = sin (headBob res*2) * jitter - dx = realToFrac $ cos (headBob res) * jitter - in do - return $ ((setHeadBob.(+ jitter)) <..> headBob) $ - if (newh+0.3 > droph) then - setSpeedFactor 0.03 $ - setRPosition (CameraPosition (Vec3 (x,newh+0.2,y)) (th + (asin dx) * speed * 15) (ph - (asin dy) * speed * 15)) $ + let camera@(CameraPosition (Vec3 (x, curh, y)) th ph) = rPosition res + (_, (w, h)) = bounds $ heightMap res + (!!!) arr (x', y') = if x' < 0 || y' < 0 || x' > w || y' > h then -1000 else elevation (arr ! (x', y')) + h1 = ((/ 10.0) . fromIntegral) (heightMap res !!! (floor x, floor y)) + h2 = ((/ 10.0) . fromIntegral) (heightMap res !!! (floor x, floor (y + 1))) + h3 = ((/ 10.0) . fromIntegral) (heightMap res !!! (floor (x + 1), floor y)) + h4 = ((/ 10.0) . fromIntegral) (heightMap res !!! (floor (x + 1), floor (y + 1))) + u = x - (int $ (floor x :: Int)) + v = y - (int $ (floor y :: Int)) + mixu1 = mix h3 h1 u + mixu2 = mix h4 h2 u + newh = mix mixu2 mixu1 v + droph = curh - dDown res + speed = getSpeed res + jitter = (max 0 $ speed - 0.029) ** 0.1 / 2 + dy = sin (headBob res * 2) * jitter + dx = realToFrac $ cos (headBob res) * jitter + in do + return $ + ((setHeadBob . (+ jitter)) <..> headBob) $ + if (newh + 0.3 > droph) + then + setSpeedFactor 0.03 $ + setRPosition (CameraPosition (Vec3 (x, newh + 0.2, y)) (th + (asin dx) * speed * 15) (ph - (asin dy) * speed * 15)) $ setDDown 0 res - else + else setRPosition (CameraPosition (Vec3 (x, droph, y)) th ph) $ - setDDown (dDown res + 0.03) res + setDDown (dDown res + 0.03) res {- A function which will explode if a uniform - does not exist for the shader given, otherwis, - it will return a list of uniform locations -} getUniformsSafe :: Program -> [String] -> IO [UniformLocation] getUniformsSafe prog uniforms = - forM uniforms $ \a_uniform -> do - tmp <- get $ uniformLocation prog a_uniform - case tmp of - UniformLocation (-1) -> do - putStrLn $ "No uniform with name: "++a_uniform - exitWith (ExitFailure 112) - _ -> return tmp + forM uniforms $ \a_uniform -> do + tmp <- get $ uniformLocation prog a_uniform + case tmp of + UniformLocation (-1) -> do + putStrLn $ "No uniform with name: " ++ a_uniform + exitWith (ExitFailure 112) + _ -> return tmp {- Builds an model view matrix given the - camera position of the scene -} buildMVMatrix :: CameraPosition -> Mat4 GLfloat buildMVMatrix camera@(CameraPosition eye _ _) = - let lookat = eye <+> cameraForward camera in - lookAtMatrix eye lookat (cameraUp camera) + let lookat = eye <+> cameraForward camera + in lookAtMatrix eye lookat (cameraUp camera) {- Called after each frame to crunch throught the - events -} eventHandle :: SDL.EventPayload -> Resources -> IO Resources eventHandle event = case event of - SDL.KeyboardEvent e -> - case (SDL.keyboardEventKeyMotion e, SDL.keysymScancode (SDL.keyboardEventKeysym e)) of - (SDL.Pressed, SDL.ScancodeW) -> setPh 2 - (SDL.Released, SDL.ScancodeW) -> setPh 0 - (SDL.Pressed, SDL.ScancodeA) -> setTh (-2) - (SDL.Released, SDL.ScancodeA) -> setTh 0 - (SDL.Pressed, SDL.ScancodeS) -> setPh (-2) - (SDL.Released, SDL.ScancodeS) -> setPh 0 - (SDL.Pressed, SDL.ScancodeD) -> setTh 2 - (SDL.Released, SDL.ScancodeD) -> setTh 0 - (SDL.Pressed, SDL.ScancodeI) -> return . setSpeedDirection (Vec3 (0, 0, 1)) - (SDL.Released, SDL.ScancodeI) -> return . setSpeedDirection (Vec3 (0, 0, 0)) - (SDL.Pressed, SDL.ScancodeK) -> return . setSpeedDirection (Vec3 (0, 0, -1)) - (SDL.Released, SDL.ScancodeK) -> return . setSpeedDirection (Vec3 (0, 0, 0)) - - -- Pressing the 'q' enters first-person-mode - (SDL.Pressed, SDL.ScancodeQ) -> return . appAll - [setPositionUpdate firstPerson, - setSpeedFactor 0.1, - \res -> res { dDown = negate $ (\(Vec3 (_,y,_)) -> y) $ resourcesVelocity res}] - - (SDL.Pressed, SDL.ScancodeE) -> return . appAll - [setPositionUpdate return, - setSpeedFactor 1, - \res -> res { dDown = 0 }] - - (SDL.Pressed, SDL.ScancodeSpace) -> return . appAll - [setSpeedFactor 0.05, - \res -> res { dDown = -0.2 }] - - (SDL.Pressed, SDL.ScancodeLShift) -> \res -> return $ res { speedMultiplier = 4 } - - (SDL.Released, SDL.ScancodeLShift) -> \res -> return $ res { speedMultiplier = 1 } - - -- KeyDown (Keysym SDLK_LSHIFT _ _) -> do - -- return $ setSpeedMultiplier 4 res - - -- KeyUp (Keysym SDLK_LSHIFT _ _) -> do - -- return $ setSpeedMultiplier 1 res - -- KeyUp (Keysym SDLK_e _ _) -> - -- return $ - -- setPositionUpdate return $ - -- setSpeedFactor 1 $ - -- if speed res > 0 then setSpeed 1 res else res - - _ -> return - _ -> return - - where - appAll :: [a -> a] -> a -> a - appAll (f:fs) a = appAll fs (f a) - appAll [] a = a - - setPh i res = - let (CameraPosition eye th ph) = rDPosition res in - return $ setRDPosition (CameraPosition eye th i) res - setTh i res = - let (CameraPosition eye th ph) = rDPosition res in - return $ setRDPosition (CameraPosition eye i ph) res + SDL.KeyboardEvent e -> + case (SDL.keyboardEventKeyMotion e, SDL.keysymScancode (SDL.keyboardEventKeysym e)) of + (SDL.Pressed, SDL.ScancodeW) -> setPh 2 + (SDL.Released, SDL.ScancodeW) -> setPh 0 + (SDL.Pressed, SDL.ScancodeA) -> setTh (-2) + (SDL.Released, SDL.ScancodeA) -> setTh 0 + (SDL.Pressed, SDL.ScancodeS) -> setPh (-2) + (SDL.Released, SDL.ScancodeS) -> setPh 0 + (SDL.Pressed, SDL.ScancodeD) -> setTh 2 + (SDL.Released, SDL.ScancodeD) -> setTh 0 + (SDL.Pressed, SDL.ScancodeI) -> return . setSpeedDirection (Vec3 (0, 0, 1)) + (SDL.Released, SDL.ScancodeI) -> return . setSpeedDirection (Vec3 (0, 0, 0)) + (SDL.Pressed, SDL.ScancodeK) -> return . setSpeedDirection (Vec3 (0, 0, -1)) + (SDL.Released, SDL.ScancodeK) -> return . setSpeedDirection (Vec3 (0, 0, 0)) + -- Pressing the 'q' enters first-person-mode + (SDL.Pressed, SDL.ScancodeQ) -> + return + . appAll + [ setPositionUpdate firstPerson, + setSpeedFactor 0.1, + \res -> res {dDown = negate $ (\(Vec3 (_, y, _)) -> y) $ resourcesVelocity res} + ] + (SDL.Pressed, SDL.ScancodeE) -> + return + . appAll + [ setPositionUpdate return, + setSpeedFactor 1, + \res -> res {dDown = 0} + ] + (SDL.Pressed, SDL.ScancodeSpace) -> + return + . appAll + [ setSpeedFactor 0.05, + \res -> res {dDown = -0.2} + ] + (SDL.Pressed, SDL.ScancodeLShift) -> \res -> return $ res {speedMultiplier = 4} + (SDL.Released, SDL.ScancodeLShift) -> \res -> return $ res {speedMultiplier = 1} + -- KeyDown (Keysym SDLK_LSHIFT _ _) -> do + -- return $ setSpeedMultiplier 4 res + + -- KeyUp (Keysym SDLK_LSHIFT _ _) -> do + -- return $ setSpeedMultiplier 1 res + -- KeyUp (Keysym SDLK_e _ _) -> + -- return $ + -- setPositionUpdate return $ + -- setSpeedFactor 1 $ + -- if speed res > 0 then setSpeed 1 res else res + + _ -> return + _ -> return + where + appAll :: [a -> a] -> a -> a + appAll (f : fs) a = appAll fs (f a) + appAll [] a = a + + setPh i res = + let (CameraPosition eye th ph) = rDPosition res + in return $ setRDPosition (CameraPosition eye th i) res + setTh i res = + let (CameraPosition eye th ph) = rDPosition res + in return $ setRDPosition (CameraPosition eye i ph) res -- eventHandle :: SDL.Event -> Resources -> IO Resources -- eventHandle event res = do - -- let (CameraPosition eye th ph) = rDPosition res - -- let (CameraPosition peye pth pph) = rPosition res - -- case event of - -- KeyDown (Keysym SDLK_ESCAPE _ _) -> exitSuccess - - -- KeyDown (Keysym SDLK_EQUALS _ _) -> - -- return $ (setTimeSpeed <..> ((+1).timeSpeed)) res - -- KeyDown (Keysym SDLK_MINUS _ _) -> - -- return $ (setTimeSpeed <..> ((subtract 1).timeSpeed)) res - - -- KeyDown (Keysym SDLK_UP _ _) -> - -- return $ setRDPosition (CameraPosition eye th (ph+1)) res - -- KeyDown (Keysym SDLK_DOWN _ _) -> - -- return $ setRDPosition (CameraPosition eye th (ph-1)) res - -- KeyDown (Keysym SDLK_RIGHT _ _) -> - -- return $ setRDPosition (CameraPosition eye (th+1) ph) res - -- KeyDown (Keysym SDLK_LEFT _ _) -> - -- return $ setRDPosition (CameraPosition eye (th-1) ph) res - - -- KeyUp (Keysym SDLK_UP _ _) -> - -- return $ setRDPosition (CameraPosition eye th (ph-1)) res - -- KeyUp (Keysym SDLK_DOWN _ _) -> - -- return $ setRDPosition (CameraPosition eye th (ph+1)) res - -- KeyUp (Keysym SDLK_RIGHT _ _) -> - -- return $ setRDPosition (CameraPosition eye (th-1) ph) res - -- KeyUp (Keysym SDLK_LEFT _ _) -> - -- return $ setRDPosition (CameraPosition eye (th+1) ph) res - - -- MouseMotion _ _ x y -> do - -- return $ setRPosition (CameraPosition peye (pth+(fromIntegral x/30.0)) (pph-(fromIntegral y/30.0))) res - - -- KeyDown (Keysym SDLK_w _ _) -> - -- return $ setSpeed (speed res + speedFactor res) res - -- KeyDown (Keysym SDLK_s _ _) -> - -- return $ setSpeed (speed res - speedFactor res) res - -- KeyUp (Keysym SDLK_w _ _) -> - -- return $ setSpeed 0 res - -- KeyUp (Keysym SDLK_s _ _) -> - -- return $ setSpeed 0 res - - -- KeyUp (Keysym SDLK_q _ _) -> - -- let getY (Vec3 (_,y,_)) = y in - -- return $ - -- setPositionUpdate firstPerson $ - -- setSpeedFactor 0.1 $ - -- (setDDown <..> (negate . getY . resourcesVelocity)) res - -- KeyUp (Keysym SDLK_e _ _) -> - -- return $ - -- setPositionUpdate return $ - -- setSpeedFactor 1 $ - -- if speed res > 0 then setSpeed 1 res else res - - -- KeyUp (Keysym SDLK_f _ _) -> do - -- ret <- reshape 1920 1080 res - -- SDL.toggleFullscreen $ rSurface ret - -- SDL.showCursor False - -- SDL.grabInput True - -- return ret - -- KeyUp (Keysym SDLK_g _ _) -> do - -- SDL.showCursor False - -- SDL.grabInput True - -- return res - - -- KeyDown (Keysym SDLK_SPACE _ _) -> do - -- return $ setDDown (-0.3) res - -- MouseMotion _ _ x y -> do - -- return $ - -- setRPosition (CameraPosition peye (pth+(fromIntegral x/30.0)) (pph-(fromIntegral y/30.0))) res - - -- KeyDown (Keysym SDLK_w _ _) -> - -- return $ ((setSpeedDirection.(<+>Vec3 (0,0,1))) <..> speedDirection) res - -- KeyDown (Keysym SDLK_s _ _) -> - -- return $ ((setSpeedDirection.(<->Vec3 (0,0,1))) <..> speedDirection) res - -- KeyDown (Keysym SDLK_d _ _) -> - -- return $ ((setSpeedDirection.(<+>Vec3 (1,0,0))) <..> speedDirection) res - -- KeyDown (Keysym SDLK_a _ _) -> - -- return $ ((setSpeedDirection.(<->Vec3 (1,0,0))) <..> speedDirection) res - - -- KeyUp (Keysym SDLK_w _ _) -> - -- return $ ((setSpeedDirection.(<->Vec3 (0,0,1))) <..> speedDirection) res - -- KeyUp (Keysym SDLK_s _ _) -> - -- return $ ((setSpeedDirection.(<+>Vec3 (0,0,1))) <..> speedDirection) res - -- KeyUp (Keysym SDLK_d _ _) -> - -- return $ ((setSpeedDirection.(<->Vec3 (1,0,0))) <..> speedDirection) res - -- KeyUp (Keysym SDLK_a _ _) -> - -- return $ ((setSpeedDirection.(<+>Vec3 (1,0,0))) <..> speedDirection) res - - -- KeyUp (Keysym SDLK_q _ _) -> - -- let getY (Vec3 (_,y,_)) = y in - -- return $ - -- setPositionUpdate firstPerson $ - -- setMode FirstPerson $ - -- (setDDown <..> (negate . getY . resourcesVelocity)) res - -- KeyUp (Keysym SDLK_e _ _) -> - -- return $ - -- setPositionUpdate return $ - -- setSpeedFactor 1 $ - -- setMode Oracle res - - -- KeyUp (Keysym SDLK_f _ _) -> do - -- ret <- reshape 1920 1080 res - -- SDL.toggleFullscreen $ rSurface ret - -- SDL.showCursor False - -- SDL.grabInput True - -- return ret - -- KeyUp (Keysym SDLK_c _ _) -> do - -- SDL.showCursor True - -- SDL.grabInput False - -- return res - -- KeyUp (Keysym SDLK_g _ _) -> do - -- SDL.showCursor False - -- SDL.grabInput True - -- return res - - -- KeyDown (Keysym SDLK_SPACE _ _) -> do - -- return $ - -- setDDown (-0.2) $ - -- setSpeedFactor 0.05 res - - -- KeyDown (Keysym SDLK_LSHIFT _ _) -> do - -- return $ setSpeedMultiplier 4 res - - -- KeyUp (Keysym SDLK_LSHIFT _ _) -> do - -- return $ setSpeedMultiplier 1 res - - -- KeyDown (Keysym SDLK_LSHIFT _ _) -> do - -- return $ (setSpeed <..> ((*3) . speed)) res - -- KeyUp (Keysym SDLK_LSHIFT _ _) -> do - -- return $ (setSpeed <..> ((/3) . speed)) res - - -- _ -> return res +-- let (CameraPosition eye th ph) = rDPosition res +-- let (CameraPosition peye pth pph) = rPosition res +-- case event of +-- KeyDown (Keysym SDLK_ESCAPE _ _) -> exitSuccess + +-- KeyDown (Keysym SDLK_EQUALS _ _) -> +-- return $ (setTimeSpeed <..> ((+1).timeSpeed)) res +-- KeyDown (Keysym SDLK_MINUS _ _) -> +-- return $ (setTimeSpeed <..> ((subtract 1).timeSpeed)) res + +-- KeyDown (Keysym SDLK_UP _ _) -> +-- return $ setRDPosition (CameraPosition eye th (ph+1)) res +-- KeyDown (Keysym SDLK_DOWN _ _) -> +-- return $ setRDPosition (CameraPosition eye th (ph-1)) res +-- KeyDown (Keysym SDLK_RIGHT _ _) -> +-- return $ setRDPosition (CameraPosition eye (th+1) ph) res +-- KeyDown (Keysym SDLK_LEFT _ _) -> +-- return $ setRDPosition (CameraPosition eye (th-1) ph) res + +-- KeyUp (Keysym SDLK_UP _ _) -> +-- return $ setRDPosition (CameraPosition eye th (ph-1)) res +-- KeyUp (Keysym SDLK_DOWN _ _) -> +-- return $ setRDPosition (CameraPosition eye th (ph+1)) res +-- KeyUp (Keysym SDLK_RIGHT _ _) -> +-- return $ setRDPosition (CameraPosition eye (th-1) ph) res +-- KeyUp (Keysym SDLK_LEFT _ _) -> +-- return $ setRDPosition (CameraPosition eye (th+1) ph) res + +-- MouseMotion _ _ x y -> do +-- return $ setRPosition (CameraPosition peye (pth+(fromIntegral x/30.0)) (pph-(fromIntegral y/30.0))) res + +-- KeyDown (Keysym SDLK_w _ _) -> +-- return $ setSpeed (speed res + speedFactor res) res +-- KeyDown (Keysym SDLK_s _ _) -> +-- return $ setSpeed (speed res - speedFactor res) res +-- KeyUp (Keysym SDLK_w _ _) -> +-- return $ setSpeed 0 res +-- KeyUp (Keysym SDLK_s _ _) -> +-- return $ setSpeed 0 res + +-- KeyUp (Keysym SDLK_q _ _) -> +-- let getY (Vec3 (_,y,_)) = y in +-- return $ +-- setPositionUpdate firstPerson $ +-- setSpeedFactor 0.1 $ +-- (setDDown <..> (negate . getY . resourcesVelocity)) res +-- KeyUp (Keysym SDLK_e _ _) -> +-- return $ +-- setPositionUpdate return $ +-- setSpeedFactor 1 $ +-- if speed res > 0 then setSpeed 1 res else res + +-- KeyUp (Keysym SDLK_f _ _) -> do +-- ret <- reshape 1920 1080 res +-- SDL.toggleFullscreen $ rSurface ret +-- SDL.showCursor False +-- SDL.grabInput True +-- return ret +-- KeyUp (Keysym SDLK_g _ _) -> do +-- SDL.showCursor False +-- SDL.grabInput True +-- return res + +-- KeyDown (Keysym SDLK_SPACE _ _) -> do +-- return $ setDDown (-0.3) res +-- MouseMotion _ _ x y -> do +-- return $ +-- setRPosition (CameraPosition peye (pth+(fromIntegral x/30.0)) (pph-(fromIntegral y/30.0))) res + +-- KeyDown (Keysym SDLK_w _ _) -> +-- return $ ((setSpeedDirection.(<+>Vec3 (0,0,1))) <..> speedDirection) res +-- KeyDown (Keysym SDLK_s _ _) -> +-- return $ ((setSpeedDirection.(<->Vec3 (0,0,1))) <..> speedDirection) res +-- KeyDown (Keysym SDLK_d _ _) -> +-- return $ ((setSpeedDirection.(<+>Vec3 (1,0,0))) <..> speedDirection) res +-- KeyDown (Keysym SDLK_a _ _) -> +-- return $ ((setSpeedDirection.(<->Vec3 (1,0,0))) <..> speedDirection) res + +-- KeyUp (Keysym SDLK_w _ _) -> +-- return $ ((setSpeedDirection.(<->Vec3 (0,0,1))) <..> speedDirection) res +-- KeyUp (Keysym SDLK_s _ _) -> +-- return $ ((setSpeedDirection.(<+>Vec3 (0,0,1))) <..> speedDirection) res +-- KeyUp (Keysym SDLK_d _ _) -> +-- return $ ((setSpeedDirection.(<->Vec3 (1,0,0))) <..> speedDirection) res +-- KeyUp (Keysym SDLK_a _ _) -> +-- return $ ((setSpeedDirection.(<+>Vec3 (1,0,0))) <..> speedDirection) res + +-- KeyUp (Keysym SDLK_q _ _) -> +-- let getY (Vec3 (_,y,_)) = y in +-- return $ +-- setPositionUpdate firstPerson $ +-- setMode FirstPerson $ +-- (setDDown <..> (negate . getY . resourcesVelocity)) res +-- KeyUp (Keysym SDLK_e _ _) -> +-- return $ +-- setPositionUpdate return $ +-- setSpeedFactor 1 $ +-- setMode Oracle res + +-- KeyUp (Keysym SDLK_f _ _) -> do +-- ret <- reshape 1920 1080 res +-- SDL.toggleFullscreen $ rSurface ret +-- SDL.showCursor False +-- SDL.grabInput True +-- return ret +-- KeyUp (Keysym SDLK_c _ _) -> do +-- SDL.showCursor True +-- SDL.grabInput False +-- return res +-- KeyUp (Keysym SDLK_g _ _) -> do +-- SDL.showCursor False +-- SDL.grabInput True +-- return res + +-- KeyDown (Keysym SDLK_SPACE _ _) -> do +-- return $ +-- setDDown (-0.2) $ +-- setSpeedFactor 0.05 res + +-- KeyDown (Keysym SDLK_LSHIFT _ _) -> do +-- return $ setSpeedMultiplier 4 res + +-- KeyUp (Keysym SDLK_LSHIFT _ _) -> do +-- return $ setSpeedMultiplier 1 res + +-- KeyDown (Keysym SDLK_LSHIFT _ _) -> do +-- return $ (setSpeed <..> ((*3) . speed)) res +-- KeyUp (Keysym SDLK_LSHIFT _ _) -> do +-- return $ (setSpeed <..> ((/3) . speed)) res + +-- _ -> return res {- Callback for the display -} displayHandle :: Resources -> IO Resources displayHandle resources = do - time1 <- getPOSIXTime - let cameraPos@(CameraPosition loc _ _) = rPosition resources - let lighty = ((/10) . fromIntegral . time) resources - let logist c = (1 / (1 + 2.71828**(-c*x))) * 0.9 + 0.1 - where x = sine $ Degrees (lighty) - let globalAmbient::(GLfloat,GLfloat,GLfloat,GLfloat) - globalAmbient = ( logist 2+0.1, logist 10, (logist 15) + 0.1,(sine.Degrees) lighty) - let lightPos = Vec4( 50, - 1000000 * (sine.Degrees $ lighty), - -1000000 * (cosine.Degrees . (/10) . fromIntegral . time) resources, - 1 ) - let l_mvMatrix = buildMVMatrix $ cameraPos - let normalMatrix = glslModelViewToNormalMatrix l_mvMatrix - - clearColor $= Color4 0 0 0 0 - clear [ColorBuffer, DepthBuffer] - printErrors "Display" - - - let rc = ResourcesClosure l_mvMatrix - (pMatrix resources) - (l_mvMatrix `glslMatMul` lightPos) - (fromIntegral $ time resources) - (normalMatrix) - (Vec4 globalAmbient) - cameraPos - loc - resources - - in mapM_ (Prelude.$rc) $ routines resources - - SDL.glSwapWindow (rWindow resources) - time2 <- getPOSIXTime - - let diff = threadDiff resources - (realToFrac $ time2 - time1) - when (diff > 0) (threadDelay $ round $ diff * 1000000) - time3 <- getPOSIXTime - let fps = realToFrac $ 1 / (time3 - time1) :: Double - - putStr $ printf "FPS: %.2f\r" fps - - return $ - if' (fps < 30) - ((setThreadDiff.(subtract 0.0001)) <..> threadDiff) - ((setThreadDiff.(+0.0001)) <..> threadDiff) resources + time1 <- getPOSIXTime + let cameraPos@(CameraPosition loc _ _) = rPosition resources + let lighty = ((/ 10) . fromIntegral . time) resources + let logist c = (1 / (1 + 2.71828 ** (- c * x))) * 0.9 + 0.1 + where + x = sine $ Degrees (lighty) + let globalAmbient :: (GLfloat, GLfloat, GLfloat, GLfloat) + globalAmbient = (logist 2 + 0.1, logist 10, (logist 15) + 0.1, (sine . Degrees) lighty) + let lightPos = + Vec4 + ( 50, + 1000000 * (sine . Degrees $ lighty), + -1000000 * (cosine . Degrees . (/ 10) . fromIntegral . time) resources, + 1 + ) + let l_mvMatrix = buildMVMatrix $ cameraPos + let normalMatrix = glslModelViewToNormalMatrix l_mvMatrix + + clearColor $= Color4 0 0 0 0 + clear [ColorBuffer, DepthBuffer] + printErrors "Display" + + let rc = + ResourcesClosure + l_mvMatrix + (pMatrix resources) + (l_mvMatrix `glslMatMul` lightPos) + (fromIntegral $ time resources) + (normalMatrix) + (Vec4 globalAmbient) + cameraPos + loc + resources + in mapM_ (Prelude.$ rc) $ routines resources + + SDL.glSwapWindow (rWindow resources) + time2 <- getPOSIXTime + + let diff = threadDiff resources - (realToFrac $ time2 - time1) + when (diff > 0) (threadDelay $ round $ diff * 1000000) + time3 <- getPOSIXTime + let fps = realToFrac $ 1 / (time3 - time1) :: Double + + putStr $ printf "FPS: %.2f\r" fps + + return $ + if' + (fps < 30) + ((setThreadDiff . (subtract 0.0001)) <..> threadDiff) + ((setThreadDiff . (+ 0.0001)) <..> threadDiff) + resources cameraToEuclidian :: CameraPosition -> Vec3 GLfloat -cameraToEuclidian (CameraPosition _ ph th) = V.normalize $ Vec3 $ toEuclidian (1,ph,th) +cameraToEuclidian (CameraPosition _ ph th) = V.normalize $ Vec3 $ toEuclidian (1, ph, th) resourcesVelocity :: Resources -> Vec3 GLfloat resourcesVelocity res = getSpeed res `vScale` cameraToEuclidian (rPosition res) resourcesUnderWater :: Resources -> IO Bool resourcesUnderWater res = do - let (CameraPosition (Vec3 (x,ch,y)) _ _) = rPosition res - (_,(w,h)) <- ArrIO.getBounds $ waterArray res - if x < 0 || y < 0 || x > int w || y > int h then return False else do - height <- ArrIO.readArray (waterArray res) (floor x, floor y) - return (height > ch && height >= 0) + let (CameraPosition (Vec3 (x, ch, y)) _ _) = rPosition res + (_, (w, h)) <- ArrIO.getBounds $ waterArray res + if x < 0 || y < 0 || x > int w || y > int h + then return False + else do + height <- ArrIO.readArray (waterArray res) (floor x, floor y) + return (height > ch && height >= 0) updateHandle :: Resources -> IO Resources updateHandle res = do - (positionUpdate res) $ setRPosition (rPosition res `cAdd` rDPosition res) $ - let new = ((+) `on` (Prelude.$ res)) timeSpeed time in - setTime new res - where (CameraPosition x y z) `cAdd` (CameraPosition _ y' z') = - let x' = getVelocity res in - CameraPosition (x <+> x') (y + y') (z + z') + (positionUpdate res) $ + setRPosition (rPosition res `cAdd` rDPosition res) $ + let new = ((+) `on` (Prelude.$ res)) timeSpeed time + in setTime new res + where + (CameraPosition x y z) `cAdd` (CameraPosition _ y' z') = + let x' = getVelocity res + in CameraPosition (x <+> x') (y + y') (z + z') reshape :: Int -> Int -> Resources -> IO Resources reshape w h res = - defaultReshape w h () >> do - let pMatrix' = perspectiveMatrix 50 (fromIntegral w / fromIntegral h) 0.1 10000 - return $ setPMatrix pMatrix' res + defaultReshape w h () >> do + let pMatrix' = perspectiveMatrix 50 (fromIntegral w / fromIntegral h) 0.1 10000 + return $ setPMatrix pMatrix' res loadProgramSafe' :: - (IsShaderSource a, - IsShaderSource b, - IsShaderSource c) => a -> b -> Maybe c -> IO Program + ( IsShaderSource a, + IsShaderSource b, + IsShaderSource c + ) => + a -> + b -> + Maybe c -> + IO Program loadProgramSafe' s1 s2 s3 = do - progMaybe <- loadProgramSafe s1 s2 s3 - when (isNothing progMaybe) $ exitWith (ExitFailure 111) - return $ fromJust progMaybe - -loadProgramFullSafe' :: - (IsShaderSource tc, IsShaderSource te, - IsShaderSource g, IsShaderSource v, - IsShaderSource f) => Maybe (tc, te) -> Maybe g -> v -> f -> IO Program + progMaybe <- loadProgramSafe s1 s2 s3 + when (isNothing progMaybe) $ exitWith (ExitFailure 111) + return $ fromJust progMaybe + +loadProgramFullSafe' :: + ( IsShaderSource tc, + IsShaderSource te, + IsShaderSource g, + IsShaderSource v, + IsShaderSource f + ) => + Maybe (tc, te) -> + Maybe g -> + v -> + f -> + IO Program loadProgramFullSafe' a b c d = do - progMaybe <- loadProgramFullSafe a b c d - when (isNothing progMaybe) $ exitWith (ExitFailure 111) - return $ fromJust progMaybe + progMaybe <- loadProgramFullSafe a b c d + when (isNothing progMaybe) $ exitWith (ExitFailure 111) + return $ fromJust progMaybe buildTerrainObject :: BuilderM GLfloat b -> IO (ResourcesClosure -> IO ()) buildTerrainObject builder = do - let terrainList = map ("terrain/"++) - [ "forest.png", "beach.png", - "oceanfloor.png", "grass.png", - "jungle.png", "mountains.png", - "tundra.png" ] - print terrainList - terrainProg <- loadProgramSafe' "shaders/basic.vert" "shaders/basic.frag" (Nothing::Maybe String) - lst <- forM (zip [0..7::Int] $ terrainList ++ repeat "terrain/unknown.png") $ \(idx,str) -> do - location <- get $ uniformLocation terrainProg $ "textures[" ++! idx ++ "]" - SDL.Image.load str >>= textureFromSurface >>= return . (,) location - - let (dx,dy) = (mapT2 $ (1/).fromIntegral) (mapT2 maximum (unzip $ map (textureSize.snd) lst)); - dXlocation <- get $ uniformLocation terrainProg "dX" - dYlocation <- get $ uniformLocation terrainProg "dY" - putStrLn $ "(dx,dy)=" ++! (dx,dy) - obj <- newDefaultGlyphObjectWithClosure builder () $ \_ -> do - currentProgram $= Just terrainProg - forM_ (zip [0..] lst) $ \(i,(loc,td)) -> - setupTexturing td loc i - uniform dXlocation $= Index1 (dx::GLfloat) - uniform dYlocation $= Index1 (dy::GLfloat) - printErrors "terrainObjectClosure" - - [lightposU, globalAmbientU, pjMatrixU, mvMatrixU, normalMatrixU, fogU] - <- getUniformsSafe terrainProg ["lightPos","globalAmbient","pjMatrix","mvMatrix","normalMatrix","fog"] - return $ \rc -> do - draw $ prepare obj $ \_ -> do - cullFace $= Just Front - uniform mvMatrixU $= rcMVMatrix rc - uniform pjMatrixU $= rcPMatrix rc - uniform lightposU $= rcLightPos rc - uniform normalMatrixU $= rcNormalMatrix rc - uniform globalAmbientU $= rcGlobalAmbient rc - bool <- (resourcesUnderWater $ rcResources rc) - if bool then - uniform fogU $= Index1 (0.9::GLfloat) else - uniform fogU $= Index1 (0.0::GLfloat) + let terrainList = + map + ("terrain/" ++) + [ "forest.png", + "beach.png", + "oceanfloor.png", + "grass.png", + "jungle.png", + "mountains.png", + "tundra.png" + ] + print terrainList + terrainProg <- loadProgramSafe' "shaders/basic.vert" "shaders/basic.frag" (Nothing :: Maybe String) + lst <- forM (zip [0 .. 7 :: Int] $ terrainList ++ repeat "terrain/unknown.png") $ \(idx, str) -> do + location <- get $ uniformLocation terrainProg $ "textures[" ++! idx ++ "]" + SDL.Image.load str >>= textureFromSurface >>= return . (,) location + + let (dx, dy) = (mapT2 $ (1 /) . fromIntegral) (mapT2 maximum (unzip $ map (textureSize . snd) lst)) + dXlocation <- get $ uniformLocation terrainProg "dX" + dYlocation <- get $ uniformLocation terrainProg "dY" + putStrLn $ "(dx,dy)=" ++! (dx, dy) + obj <- newDefaultGlyphObjectWithClosure builder () $ \_ -> do + currentProgram $= Just terrainProg + forM_ (zip [0 ..] lst) $ \(i, (loc, td)) -> + setupTexturing td loc i + uniform dXlocation $= Index1 (dx :: GLfloat) + uniform dYlocation $= Index1 (dy :: GLfloat) + printErrors "terrainObjectClosure" + + [lightposU, globalAmbientU, pjMatrixU, mvMatrixU, normalMatrixU, fogU] <- + getUniformsSafe terrainProg ["lightPos", "globalAmbient", "pjMatrix", "mvMatrix", "normalMatrix", "fog"] + return $ \rc -> do + draw $ + prepare obj $ \_ -> do + cullFace $= Just Front + uniform mvMatrixU $= rcMVMatrix rc + uniform pjMatrixU $= rcPMatrix rc + uniform lightposU $= rcLightPos rc + uniform normalMatrixU $= rcNormalMatrix rc + uniform globalAmbientU $= rcGlobalAmbient rc + bool <- (resourcesUnderWater $ rcResources rc) + if bool + then uniform fogU $= Index1 (0.9 :: GLfloat) + else uniform fogU $= Index1 (0.0 :: GLfloat) -- cloudProgram :: IO (ResourcesClosure -> IO ()) -- cloudProgram = do @@ -583,13 +615,13 @@ buildTerrainObject builder = do -- bColor4 (x,y,z,0) -- bVertex3 (x,y+20,z) -- program <- loadProgramSafe' "shaders/clouds.vert" "shaders/clouds.frag" noShader --- +-- -- stgen <- newStdGen -- array3D <- SA.newListArray ((0,0,0,0),(3,64,64,64)) (map (fromIntegral . (`mod`256)) $ (randoms stgen::[Int])) --- +-- -- SA.withStorableArray array3D $ \ptr3D -> do -- density <- makeTexture3D >>= textureFromPointer3D ptr3D (64,64,64) --- +-- -- obj' <- newDefaultGlyphObjectWithClosure builder () $ \_ -> do -- currentProgram $= Just program -- [mvMatU, pMatU, densityU, globalAmbientU,lightposU] <- mapM (get . uniformLocation program) @@ -602,93 +634,102 @@ buildTerrainObject builder = do -- uniform globalAmbientU $= rcGlobalAmbient rc -- uniform lightposU $= rcLightPos rc -- setupTexturing3D density densityU 0 - -buildSnowVal :: Array (Int,Int) Tile -> StdGen -> BuilderM GLfloat () + +buildSnowVal :: Array (Int, Int) Tile -> StdGen -> BuilderM GLfloat () buildSnowVal arr gen = - let (_,(w,h)) = bounds arr - run :: [Int] -> (Int,Int) -> BuilderM GLfloat [Int] - run rs (x,y) = do - let (seed:npart:t) = rs - nStdGen = mkStdGen seed - height = elevation (arr ! (x,y)) - when (tileType (arr ! (x,y)) == Tundra) $ - forM_ (take (npart`mod`50) $ chunkList3 $ randomRs (0::GLfloat,1) nStdGen ) $ \(a,b,c) -> do - let (x',y') = (int x + a, int y + b) - bVertex3 (x',c*100,y') - bColor4 (int $ height `div` 10,1, 0, 0) - - return t - in - - foldM_ run (randoms gen) [(x,y) | x <- [1..w], y <- [1..h]] - -buildSnowObject :: Array (Int,Int) Tile -> StdGen -> IO (ResourcesClosure -> IO ()) + let (_, (w, h)) = bounds arr + run :: [Int] -> (Int, Int) -> BuilderM GLfloat [Int] + run rs (x, y) = do + let (seed : npart : t) = rs + nStdGen = mkStdGen seed + height = elevation (arr ! (x, y)) + when (tileType (arr ! (x, y)) == Tundra) $ + forM_ (take (npart `mod` 50) $ chunkList3 $ randomRs (0 :: GLfloat, 1) nStdGen) $ \(a, b, c) -> do + let (x', y') = (int x + a, int y + b) + bVertex3 (x', c * 100, y') + bColor4 (int $ height `div` 10, 1, 0, 0) + + return t + in foldM_ run (randoms gen) [(x, y) | x <- [1 .. w], y <- [1 .. h]] + +buildSnowObject :: Array (Int, Int) Tile -> StdGen -> IO (ResourcesClosure -> IO ()) buildSnowObject arr gen = do - snowProgram <- loadProgramSafe' "shaders/snow.vert" "shaders/snow.frag" (Just "shaders/snow.geom") - obj <- - liftM (flip setPrimitiveMode Ex.Points) $ - newDefaultGlyphObjectWithClosure (buildSnowVal arr gen) () $ \_ -> do - currentProgram $= Just snowProgram - - [globalAmbientU,pjMatrixU,mvMatrixU,timeU] <- - getUniformsSafe snowProgram ["globalAmbient","pjMatrix","mvMatrix","time"] - return $ \rc -> do - draw $ (prepare obj) $ \_ -> do - uniform mvMatrixU $= rcMVMatrix rc - uniform pjMatrixU $= rcPMatrix rc - uniform timeU $= (Index1 $ (rcTime rc/75)) - uniform globalAmbientU $= rcGlobalAmbient rc + snowProgram <- loadProgramSafe' "shaders/snow.vert" "shaders/snow.frag" (Just "shaders/snow.geom") + obj <- + liftM (flip setPrimitiveMode Ex.Points) $ + newDefaultGlyphObjectWithClosure (buildSnowVal arr gen) () $ \_ -> do + currentProgram $= Just snowProgram + + [globalAmbientU, pjMatrixU, mvMatrixU, timeU] <- + getUniformsSafe snowProgram ["globalAmbient", "pjMatrix", "mvMatrix", "time"] + return $ \rc -> do + draw $ + (prepare obj) $ \_ -> do + uniform mvMatrixU $= rcMVMatrix rc + uniform pjMatrixU $= rcPMatrix rc + uniform timeU $= (Index1 $ (rcTime rc / 75)) + uniform globalAmbientU $= rcGlobalAmbient rc buildForestObject :: Seq.Seq GLfloat -> String -> String -> IO (ResourcesClosure -> IO ()) buildForestObject a_seq obj tex = - if Seq.null a_seq then return ((const.return) ()) else do - let bufferIO :: IO BufferObject - bufferIO = (newArray . Fold.toList) a_seq >>= ptrToBuffer ArrayBuffer (Seq.length a_seq * 4) - - !buffer <- bufferIO - (log',file) <- loadObjFile obj :: IO ([String],ObjectFile GLfloat) - mapM_ putStrLn log' - let !treeF = trace "build tree" $ (basicBuildObject file :: BuilderM GLfloat ()) - - forestProg <- loadProgramSafe' - "shaders/forest.vert" "shaders/forest.frag" noShader - - woodTexture <- SDL.Image.load tex >>= textureFromSurface - let (dx,dy) = (mapT2 $ (1/).fromIntegral) (textureSize woodTexture) - dXlocation <- get $ uniformLocation forestProg "dX" - dYlocation <- get $ uniformLocation forestProg "dY" - - [textureU,lightU,globalAmbientU,pjMatrixU,mvMatrixU,timeU,normalMatrixU] <- - getUniformsSafe forestProg ["texture","light","globalAmbient","pjMatrix","mvMatrix","time","normalMatrix"] - - obj' <- newDefaultGlyphObjectWithClosure treeF () $ \_ -> do - currentProgram $= Just forestProg - setupTexturing woodTexture textureU 0 - uniform dXlocation $= (Index1 $ (dx::GLfloat)) - uniform dYlocation $= (Index1 $ (dy::GLfloat)) - - bindBuffer ArrayBuffer $= Just buffer - - let declareAttr location nelem' offset = do - vertexAttribPointer location $= - (ToFloat, VertexArrayDescriptor - nelem' Float (fromIntegral $ (3+3+2+1+1)*sizeOf (0::GLfloat)) - (wordPtrToPtr offset)) - vertexAttribArray location $= Enabled - vertexAttributeDivisor location SV.$= 1 - - declareAttr (AttribLocation 10) 3 0 - declareAttr (AttribLocation 11) 3 (3*4) - declareAttr (AttribLocation 12) 2 (6*4) - declareAttr (AttribLocation 13) 1 (8*4) - declareAttr (AttribLocation 14) 1 (9*4) - - printErrors "forestClosure" - putStrLn $ "N trees = " ++! (Seq.length a_seq `div` 3) - let obj'' = setNumInstances obj' (Seq.length a_seq `div` 3) - - return $ \rc -> do - draw $ (prepare obj'') $ \_ -> do + if Seq.null a_seq + then return ((const . return) ()) + else do + let bufferIO :: IO BufferObject + bufferIO = (newArray . Fold.toList) a_seq >>= ptrToBuffer ArrayBuffer (Seq.length a_seq * 4) + + !buffer <- bufferIO + (log', file) <- loadObjFile obj :: IO ([String], ObjectFile GLfloat) + mapM_ putStrLn log' + let !treeF = trace "build tree" $ (basicBuildObject file :: BuilderM GLfloat ()) + + forestProg <- + loadProgramSafe' + "shaders/forest.vert" + "shaders/forest.frag" + noShader + + woodTexture <- SDL.Image.load tex >>= textureFromSurface + let (dx, dy) = (mapT2 $ (1 /) . fromIntegral) (textureSize woodTexture) + dXlocation <- get $ uniformLocation forestProg "dX" + dYlocation <- get $ uniformLocation forestProg "dY" + + [textureU, lightU, globalAmbientU, pjMatrixU, mvMatrixU, timeU, normalMatrixU] <- + getUniformsSafe forestProg ["texture", "light", "globalAmbient", "pjMatrix", "mvMatrix", "time", "normalMatrix"] + + obj' <- newDefaultGlyphObjectWithClosure treeF () $ \_ -> do + currentProgram $= Just forestProg + setupTexturing woodTexture textureU 0 + uniform dXlocation $= (Index1 $ (dx :: GLfloat)) + uniform dYlocation $= (Index1 $ (dy :: GLfloat)) + + bindBuffer ArrayBuffer $= Just buffer + + let declareAttr location nelem' offset = do + vertexAttribPointer location + $= ( ToFloat, + VertexArrayDescriptor + nelem' + Float + (fromIntegral $ (3 + 3 + 2 + 1 + 1) * sizeOf (0 :: GLfloat)) + (wordPtrToPtr offset) + ) + vertexAttribArray location $= Enabled + vertexAttributeDivisor location SV.$= 1 + + declareAttr (AttribLocation 10) 3 0 + declareAttr (AttribLocation 11) 3 (3 * 4) + declareAttr (AttribLocation 12) 2 (6 * 4) + declareAttr (AttribLocation 13) 1 (8 * 4) + declareAttr (AttribLocation 14) 1 (9 * 4) + + printErrors "forestClosure" + putStrLn $ "N trees = " ++! (Seq.length a_seq `div` 3) + let obj'' = setNumInstances obj' (Seq.length a_seq `div` 3) + + return $ \rc -> do + draw $ + (prepare obj'') $ \_ -> do uniform mvMatrixU $= rcMVMatrix rc uniform pjMatrixU $= rcPMatrix rc uniform lightU $= rcLightPos rc @@ -698,185 +739,205 @@ buildForestObject a_seq obj tex = buildWaterObject :: BuilderM GLfloat a -> IO (ResourcesClosure -> IO ()) buildWaterObject builder = do - waterProg <- loadProgramFullSafe' - (Just ("shaders/water.tcs","shaders/water.tes")) - noShader "shaders/water.vert" "shaders/water.frag" - waterTexture <- SDL.Image.load "textures/water.jpg" >>= textureFromSurface - skyTexture <- SDL.Image.load "textures/skybox_top.png" >>= textureFromSurface - skyNightTexture <- SDL.Image.load "textures/skybox_top_night.png" >>= textureFromSurface - location <- get (uniformLocation waterProg "texture") - skyLocation <- get (uniformLocation waterProg "skytex") - skyNightLocation <- get (uniformLocation waterProg "skynight") - obj <- (liftM (flip setPrimitiveMode Ex.Patches) $ newDefaultGlyphObjectWithClosure builder () $ \_ -> do - currentProgram $= Just waterProg - setupTexturing waterTexture location 0 - setupTexturing skyTexture skyLocation 1 - setupTexturing skyNightTexture skyNightLocation 2 - ) - [fogU] <- getUniformsSafe waterProg ["fog"] - return $ \rc -> do - draw $ prepare obj $ \_ -> do - cullFace $= Nothing - GL.patchVertices $= 4 - uniform (UniformLocation 4) $= rcPMatrix rc - uniform (UniformLocation 5) $= rcMVMatrix rc - uniform (UniformLocation 7) $= rcNormalMatrix rc - uniform (UniformLocation 8) $= rcLightPos rc - uniform (UniformLocation 9) $= Index1 (rcTime rc / 20.0); - uniform (UniformLocation 10) $= rcGlobalAmbient rc - bool <- (resourcesUnderWater $ rcResources rc) - if bool then - uniform fogU $= Index1 (0.9::GLfloat) else - uniform fogU $= Index1 (0.0::GLfloat) - - -makeResources :: SDL.Window -> BuilderM GLfloat b -> - Seq.Seq GLfloat -> Seq.Seq GLfloat -> - BuilderM GLfloat a -> Array (Int,Int) Tile -> - ArrIO.IOArray (Int,Int) GLfloat -> IO Resources + waterProg <- + loadProgramFullSafe' + (Just ("shaders/water.tcs", "shaders/water.tes")) + noShader + "shaders/water.vert" + "shaders/water.frag" + waterTexture <- SDL.Image.load "textures/water.jpg" >>= textureFromSurface + skyTexture <- SDL.Image.load "textures/skybox_top.png" >>= textureFromSurface + skyNightTexture <- SDL.Image.load "textures/skybox_top_night.png" >>= textureFromSurface + location <- get (uniformLocation waterProg "texture") + skyLocation <- get (uniformLocation waterProg "skytex") + skyNightLocation <- get (uniformLocation waterProg "skynight") + obj <- + ( liftM (flip setPrimitiveMode Ex.Patches) $ + newDefaultGlyphObjectWithClosure builder () $ \_ -> do + currentProgram $= Just waterProg + setupTexturing waterTexture location 0 + setupTexturing skyTexture skyLocation 1 + setupTexturing skyNightTexture skyNightLocation 2 + ) + [fogU] <- getUniformsSafe waterProg ["fog"] + return $ \rc -> do + draw $ + prepare obj $ \_ -> do + cullFace $= Nothing + GL.patchVertices $= 4 + uniform (UniformLocation 4) $= rcPMatrix rc + uniform (UniformLocation 5) $= rcMVMatrix rc + uniform (UniformLocation 7) $= rcNormalMatrix rc + uniform (UniformLocation 8) $= rcLightPos rc + uniform (UniformLocation 9) $= Index1 (rcTime rc / 20.0) + uniform (UniformLocation 10) $= rcGlobalAmbient rc + bool <- (resourcesUnderWater $ rcResources rc) + if bool + then uniform fogU $= Index1 (0.9 :: GLfloat) + else uniform fogU $= Index1 (0.0 :: GLfloat) + +makeResources :: + SDL.Window -> + BuilderM GLfloat b -> + Seq.Seq GLfloat -> + Seq.Seq GLfloat -> + BuilderM GLfloat a -> + Array (Int, Int) Tile -> + ArrIO.IOArray (Int, Int) GLfloat -> + IO Resources makeResources window builder forestB jungleB water arr waterarr = do - hSetBuffering stdout NoBuffering - let pMatrix' = perspectiveMatrix 50 1.8 0.1 100 - - stdgen <- newStdGen - let l_routines = sequence [ - skyboxObject, - (return $ \_ -> do + hSetBuffering stdout NoBuffering + let pMatrix' = perspectiveMatrix 50 1.8 0.1 100 + + stdgen <- newStdGen + let l_routines = + sequence + [ skyboxObject, + ( return $ \_ -> do vertexProgramPointSize $= Enabled - depthFunc $= Just Less), + depthFunc $= Just Less + ), buildTerrainObject builder, - (return $ \_-> do + ( return $ \_ -> do blend $= Disabled cullFace $= Just Back - blendFunc $= (GL.SrcAlpha,OneMinusSrcAlpha)), + blendFunc $= (GL.SrcAlpha, OneMinusSrcAlpha) + ), buildWaterObject water, buildForestObject forestB "tree.obj" "textures/wood_low.png", buildForestObject jungleB "jungletree.obj" "textures/jungle_tree.png" -- buildSnowObject arr stdgen -- cloudProgram - ] - Resources - <$> pure window - <*> do CameraPosition - <$> pure (Vec3 (10,10,-10)) - <*> pure 0 - <*> pure 0 - <*> do CameraPosition - <$> pure (Vec3 (0,0,0)) - <*> pure 0 - <*> pure 0 - <*> pure pMatrix' - <*> pure pMatrix' - <*> l_routines - <*> pure 1 + ] + Resources + <$> pure window + <*> do + CameraPosition + <$> pure (Vec3 (10, 10, -10)) <*> pure 0 - <*> pure arr - <*> pure return - <*> pure 1 - <*> pure 1 - <*> pure (Vec3 (0,0,0)) <*> pure 0 - <*> pure waterarr + <*> do + CameraPosition + <$> pure (Vec3 (0, 0, 0)) <*> pure 0 - <*> pure Oracle - <*> pure 0.033 + <*> pure 0 + <*> pure pMatrix' + <*> pure pMatrix' + <*> l_routines + <*> pure 1 + <*> pure 0 + <*> pure arr + <*> pure return + <*> pure 1 + <*> pure 1 + <*> pure (Vec3 (0, 0, 0)) + <*> pure 0 + <*> pure waterarr + <*> pure 0 + <*> pure Oracle + <*> pure 0.033 printErrors :: String -> IO () printErrors ctx = - get errors >>= mapM_ (putStrLn . (("GL["++ctx++"]: ")++) . show) + get errors >>= mapM_ (putStrLn . (("GL[" ++ ctx ++ "]: ") ++) . show) skyboxSides :: GLfloat -> BuilderM GLfloat () skyboxSides dist = do - let q = trianglesFromQuads $ - -- back - [(bTexture2(0,0), bVertex3 (-dist, dist, -dist)), - (bTexture2(0.25,0), bVertex3 ( dist, dist, -dist)), - (bTexture2(0.25,1), bVertex3 ( dist, -dist, -dist)), - (bTexture2(0,1), bVertex3 (-dist, -dist, -dist))] ++ - - -- front - [(bTexture2(0.75,0), bVertex3 (-dist, dist, dist)), - (bTexture2(0.5,0), bVertex3 ( dist, dist, dist)), - (bTexture2(0.5,1), bVertex3 ( dist, -dist, dist)), - (bTexture2(0.75,1), bVertex3 (-dist, -dist, dist))] ++ - - -- right - [(bTexture2(0.75,1), bVertex3 (-dist, -dist, dist)), - (bTexture2(0.75,0), bVertex3 (-dist, dist, dist)), - (bTexture2(1.0,0), bVertex3 (-dist, dist, -dist)), - (bTexture2(1.0,1), bVertex3 (-dist, -dist, -dist))] ++ - - -- left - [(bTexture2(0.5,1), bVertex3 ( dist, -dist, dist)), - (bTexture2(0.5,0), bVertex3 ( dist, dist, dist)), - (bTexture2(0.25,0) , bVertex3 ( dist, dist, -dist)), - (bTexture2(0.25,1) , bVertex3 ( dist, -dist, -dist))] - - in - mapM_ (uncurry (>>)) q + let q = + trianglesFromQuads $ + -- back + [ (bTexture2 (0, 0), bVertex3 (- dist, dist, - dist)), + (bTexture2 (0.25, 0), bVertex3 (dist, dist, - dist)), + (bTexture2 (0.25, 1), bVertex3 (dist, - dist, - dist)), + (bTexture2 (0, 1), bVertex3 (- dist, - dist, - dist)) + ] + ++ + -- front + [ (bTexture2 (0.75, 0), bVertex3 (- dist, dist, dist)), + (bTexture2 (0.5, 0), bVertex3 (dist, dist, dist)), + (bTexture2 (0.5, 1), bVertex3 (dist, - dist, dist)), + (bTexture2 (0.75, 1), bVertex3 (- dist, - dist, dist)) + ] + ++ + -- right + [ (bTexture2 (0.75, 1), bVertex3 (- dist, - dist, dist)), + (bTexture2 (0.75, 0), bVertex3 (- dist, dist, dist)), + (bTexture2 (1.0, 0), bVertex3 (- dist, dist, - dist)), + (bTexture2 (1.0, 1), bVertex3 (- dist, - dist, - dist)) + ] + ++ + -- left + [ (bTexture2 (0.5, 1), bVertex3 (dist, - dist, dist)), + (bTexture2 (0.5, 0), bVertex3 (dist, dist, dist)), + (bTexture2 (0.25, 0), bVertex3 (dist, dist, - dist)), + (bTexture2 (0.25, 1), bVertex3 (dist, - dist, - dist)) + ] + in mapM_ (uncurry (>>)) q + skyboxTop :: GLfloat -> BuilderM GLfloat () skyboxTop dist = do - mapM_ (uncurry (>>)) $ - trianglesFromQuads - [(bTexture2(1,0), bVertex3 ( -dist, dist, dist)), - (bTexture2(1,1), bVertex3 ( dist, dist, dist)), - (bTexture2(0,1), bVertex3 ( dist, dist, -dist)), - (bTexture2(0,0), bVertex3 ( -dist, dist, -dist))] + mapM_ (uncurry (>>)) $ + trianglesFromQuads + [ (bTexture2 (1, 0), bVertex3 (- dist, dist, dist)), + (bTexture2 (1, 1), bVertex3 (dist, dist, dist)), + (bTexture2 (0, 1), bVertex3 (dist, dist, - dist)), + (bTexture2 (0, 0), bVertex3 (- dist, dist, - dist)) + ] skyboxObject :: IO (ResourcesClosure -> IO ()) skyboxObject = do - prog <- loadProgramSafe' "shaders/sky.vert" "shaders/sky.frag" (Nothing::Maybe String) - texLoc <- get $ uniformLocation prog "texture" - texLocNight <- get $ uniformLocation prog "night_tex" - matLoc <- get $ uniformLocation prog "mvMatrix" - pmatLoc <- get $ uniformLocation prog "pjMatrix" - - glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_S $ fromIntegral GL_CLAMP_TO_EDGE - glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_T $ fromIntegral GL_CLAMP_TO_EDGE - l_texture <- SDL.Image.load "textures/skybox_sides.png" >>= textureFromSurface - glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_S $ fromIntegral GL_CLAMP_TO_EDGE - glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_T $ fromIntegral GL_CLAMP_TO_EDGE - l_texture2 <- SDL.Image.load "textures/skybox_sides_night.png" >>= textureFromSurface - glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_S $ fromIntegral GL_CLAMP_TO_EDGE - glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_T $ fromIntegral GL_CLAMP_TO_EDGE - l_textureTop <- SDL.Image.load "textures/skybox_top.png" >>= textureFromSurface - glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_S $ fromIntegral GL_CLAMP_TO_EDGE - glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_T $ fromIntegral GL_CLAMP_TO_EDGE - l_textureTopNight <- SDL.Image.load "textures/skybox_top_night.png" >>= textureFromSurface - - [lightposU,multU] <- mapM (get . uniformLocation prog) - ["lightpos","mult"] - topObj <- newDefaultGlyphObjectWithClosure (skyboxTop 1) () $ \_ -> do - setupTexturing l_textureTop texLoc 2 - setupTexturing l_textureTopNight texLocNight 3 - - obj <- newDefaultGlyphObjectWithClosure (skyboxSides 1) (matLoc,pmatLoc) $ \_ -> do - currentProgram $= Just prog - setupTexturing l_texture texLoc 0 - setupTexturing l_texture2 texLocNight 1 - printErrors "Skybox" - - let obj' = teardown obj $ \_ -> do - draw topObj - - return $ \rc -> do - depthFunc $= Nothing - cullFace $= Nothing - draw $ prepare obj' $ \this -> do - let (l_matLoc,l_pmatLoc) = getResources this - let (CameraPosition _ th ph) = rcCameraPos rc - uniform lightposU $= rcLightPos rc - uniform l_pmatLoc $= rcPMatrix rc - uniform l_matLoc $= buildMVMatrix (CameraPosition (Vec3 (0,0,0)) th ph) - uniform (UniformLocation 1) $= rcGlobalAmbient rc - bool <- (resourcesUnderWater $ rcResources rc) - if bool then - uniform multU $= Index1 (0.0::GLfloat) else - uniform multU $= Index1 (1.0::GLfloat) - - + prog <- loadProgramSafe' "shaders/sky.vert" "shaders/sky.frag" (Nothing :: Maybe String) + texLoc <- get $ uniformLocation prog "texture" + texLocNight <- get $ uniformLocation prog "night_tex" + matLoc <- get $ uniformLocation prog "mvMatrix" + pmatLoc <- get $ uniformLocation prog "pjMatrix" + + glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_S $ fromIntegral GL_CLAMP_TO_EDGE + glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_T $ fromIntegral GL_CLAMP_TO_EDGE + l_texture <- SDL.Image.load "textures/skybox_sides.png" >>= textureFromSurface + glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_S $ fromIntegral GL_CLAMP_TO_EDGE + glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_T $ fromIntegral GL_CLAMP_TO_EDGE + l_texture2 <- SDL.Image.load "textures/skybox_sides_night.png" >>= textureFromSurface + glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_S $ fromIntegral GL_CLAMP_TO_EDGE + glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_T $ fromIntegral GL_CLAMP_TO_EDGE + l_textureTop <- SDL.Image.load "textures/skybox_top.png" >>= textureFromSurface + glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_S $ fromIntegral GL_CLAMP_TO_EDGE + glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_T $ fromIntegral GL_CLAMP_TO_EDGE + l_textureTopNight <- SDL.Image.load "textures/skybox_top_night.png" >>= textureFromSurface + + [lightposU, multU] <- + mapM + (get . uniformLocation prog) + ["lightpos", "mult"] + topObj <- newDefaultGlyphObjectWithClosure (skyboxTop 1) () $ \_ -> do + setupTexturing l_textureTop texLoc 2 + setupTexturing l_textureTopNight texLocNight 3 + + obj <- newDefaultGlyphObjectWithClosure (skyboxSides 1) (matLoc, pmatLoc) $ \_ -> do + currentProgram $= Just prog + setupTexturing l_texture texLoc 0 + setupTexturing l_texture2 texLocNight 1 + printErrors "Skybox" + + let obj' = teardown obj $ \_ -> do + draw topObj + + return $ \rc -> do + depthFunc $= Nothing + cullFace $= Nothing + draw $ + prepare obj' $ \this -> do + let (l_matLoc, l_pmatLoc) = getResources this + let (CameraPosition _ th ph) = rcCameraPos rc + uniform lightposU $= rcLightPos rc + uniform l_pmatLoc $= rcPMatrix rc + uniform l_matLoc $= buildMVMatrix (CameraPosition (Vec3 (0, 0, 0)) th ph) + uniform (UniformLocation 1) $= rcGlobalAmbient rc + bool <- (resourcesUnderWater $ rcResources rc) + if bool + then uniform multU $= Index1 (0.0 :: GLfloat) + else uniform multU $= Index1 (1.0 :: GLfloat) prepareSkybox :: Mat4 GLfloat -> Mat4 GLfloat -> GlyphObject (Mat4 GLfloat -> Mat4 GLfloat -> IO ()) -> IO () prepareSkybox proj lookat obj = do - (getResources obj) proj lookat - + (getResources obj) proj lookat |