From 11fca081b1241e1915f357fa40baa3e97aceb823 Mon Sep 17 00:00:00 2001 From: Josh Rahm Date: Sat, 3 Dec 2022 01:03:52 -0700 Subject: Start reviving this ancient project. (It's pretty cool). Got it to compile using Stack. Skybox works, but nothing else really does. I think this is a problem with how the program is interpreting the surface pixels when calculating the map terrain and elevation. I think some TLC is in order. --- Resources.hs | 301 ++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 186 insertions(+), 115 deletions(-) (limited to 'Resources.hs') diff --git a/Resources.hs b/Resources.hs index 30d129b..009bdac 100644 --- a/Resources.hs +++ b/Resources.hs @@ -1,9 +1,9 @@ {-# LANGUAGE BangPatterns #-} -{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE LambdaCase #-} module Resources where -import Graphics.UI.SDL as SDL -import Graphics.UI.SDL.Image as SDLImg +import qualified SDL +import qualified SDL.Image import Foreign.Storable import Foreign.Ptr @@ -19,14 +19,13 @@ import Graphics.Glyph.Mat4 import Graphics.Glyph.Util import Graphics.Glyph.ExtendedGL as Ex import Graphics.Rendering.OpenGL as GL -import Graphics.Rendering.OpenGL.Raw.Core31 +import Graphics.GL.Compatibility30 import Control.Applicative import Control.Monad import Data.Angle import Data.Function -import Data.Setters import qualified Data.Sequence as Seq import qualified Data.Foldable as Fold import Data.Maybe @@ -35,15 +34,22 @@ import Debug.Trace import System.Exit import qualified Data.Array.IO as ArrIO -import TileShow - import Data.Array import qualified Data.StateVar as SV {- Types of terrain which are possible -} data TileType = Forest | Beach | Water | Grass | Jungle | Mountains | Tundra | Unknown deriving (Enum,Eq) -$(makeShow ''TileType) +instance Show TileType where + 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 @@ -64,7 +70,7 @@ data CameraPosition = CameraPosition { {- The central data type for rendering - the scene. Contains the 'global' information -} data Resources = Resources { - rSurface :: SDL.Surface, + rWindow :: SDL.Window, rPosition :: CameraPosition, rDPosition :: CameraPosition, @@ -85,6 +91,49 @@ data Resources = Resources { waterArray :: ArrIO.IOArray (Int,Int) GLfloat } +setRSurface :: SDL.Window -> Resources -> Resources +setRSurface x r = r { rWindow = x } + +setRPosition :: CameraPosition -> Resources -> Resources +setRPosition x r = r { rPosition = x } + +setRDPosition :: CameraPosition -> Resources -> Resources +setRDPosition x r = r { rDPosition = x } + +setPMatrix :: Mat4 GLfloat -> Resources -> Resources +setPMatrix x r = r { pMatrix = x } + +setMvMatrix :: Mat4 GLfloat -> Resources -> Resources +setMvMatrix x r = r { mvMatrix = x } + +setRoutines :: [ResourcesClosure -> IO ()] -> Resources -> Resources +setRoutines x r = r { routines = x } + +setSpeed :: GLfloat -> Resources -> Resources +setSpeed x r = r { speed = x } + +setTimeSpeed :: Int -> Resources -> Resources +setTimeSpeed x r = r { timeSpeed = x } + +setTime :: Int -> Resources -> Resources +setTime x r = r { time = 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 } + +setSpeedFactor :: GLfloat -> Resources -> Resources +setSpeedFactor x r = r { speedFactor = x } + +setDDown :: GLfloat -> Resources -> Resources +setDDown x r = r { dDown = x } + +setWaterArray :: ArrIO.IOArray (Int,Int) GLfloat -> Resources -> Resources +setWaterArray x r = r { waterArray = x } + + {- Central data type for rendering each frame -} data ResourcesClosure = ResourcesClosure { rcMVMatrix :: Mat4 GLfloat @@ -98,8 +147,6 @@ data ResourcesClosure = ResourcesClosure { , rcResources :: Resources } -$(declareSetters ''Resources) - {- A function that makes the resources data first - person -} firstPerson :: Resources -> IO Resources @@ -153,80 +200,104 @@ buildMVMatrix (CameraPosition eye th ph) = {- Called after each frame to crunch throught the - events -} -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 - - KeyDown (Keysym SDLK_LSHIFT _ _) -> do - return $ (setSpeed <..> ((*3) . speed)) res - KeyUp (Keysym SDLK_LSHIFT _ _) -> do - return $ (setSpeed <..> ((/3) . speed)) res - - _ -> return res +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 1 + (SDL.Released, SDL.ScancodeW) -> setPh 0 + (SDL.Pressed, SDL.ScancodeA) -> setTh (-1) + (SDL.Released, SDL.ScancodeA) -> setTh 0 + (SDL.Pressed, SDL.ScancodeS) -> setPh (-1) + (SDL.Released, SDL.ScancodeS) -> setPh 0 + (SDL.Pressed, SDL.ScancodeD) -> setTh 1 + (SDL.Released, SDL.ScancodeD) -> setTh 0 + (SDL.Pressed, SDL.ScancodeI) -> \res -> return $ setSpeed (speedFactor res) res + (SDL.Released, SDL.ScancodeI) -> return . setSpeed 0 + (SDL.Pressed, SDL.ScancodeK) -> \res -> return $ setSpeed (0 - speedFactor res) res + (SDL.Released, SDL.ScancodeK) -> return . setSpeed 0 + _ -> return + _ -> return + + where + 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 + -- 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 + + -- 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 @@ -246,7 +317,6 @@ displayHandle resources = do clearColor $= Color4 0 0 0 0 clear [ColorBuffer, DepthBuffer] - SDL.flip $ rSurface resources printErrors "Display" @@ -262,7 +332,7 @@ displayHandle resources = do in mapM_ (Prelude.$rc) $ routines resources - SDL.glSwapBuffers + SDL.glSwapWindow (rWindow resources) return resources cameraToEuclidian :: CameraPosition -> Vec3 GLfloat @@ -323,7 +393,7 @@ buildTerrainObject builder = do 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 ++ "]" - load str >>= textureFromSurface >>= return . (,) location + 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" @@ -394,7 +464,7 @@ buildForestObject a_seq obj tex = forestProg <- loadProgramSafe' "shaders/forest.vert" "shaders/forest.frag" noShader - woodTexture <- load tex >>= textureFromSurface + woodTexture <- SDL.Image.load tex >>= textureFromSurface let (dx,dy) = (mapT2 $ (1/).fromIntegral) (textureSize woodTexture) dXlocation <- get $ uniformLocation forestProg "dX" dYlocation <- get $ uniformLocation forestProg "dY" @@ -426,7 +496,7 @@ buildForestObject a_seq obj tex = printErrors "forestClosure" putStrLn $ "N trees = " ++! (Seq.length a_seq `div` 3) - let obj'' = setNumInstances (Seq.length a_seq `div` 3) obj' + let obj'' = setNumInstances obj' (Seq.length a_seq `div` 3) return $ \rc -> do draw $ (prepare obj'') $ \_ -> do @@ -442,13 +512,13 @@ buildWaterObject builder = do waterProg <- loadProgramFullSafe' (Just ("shaders/water.tcs","shaders/water.tes")) noShader "shaders/water.vert" "shaders/water.frag" - waterTexture <- load "textures/water.jpg" >>= textureFromSurface - skyTexture <- load "textures/skybox_top.png" >>= textureFromSurface - skyNightTexture <- load "textures/skybox_top_night.png" >>= textureFromSurface + 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 (setPrimitiveMode Ex.Patches) $ newDefaultGlyphObjectWithClosure builder () $ \_ -> do + obj <- (liftM (flip setPrimitiveMode Ex.Patches) $ newDefaultGlyphObjectWithClosure builder () $ \_ -> do currentProgram $= Just waterProg setupTexturing waterTexture location 0 setupTexturing skyTexture skyLocation 1 @@ -458,7 +528,7 @@ buildWaterObject builder = do return $ \rc -> do draw $ prepare obj $ \_ -> do cullFace $= Nothing - patchVertices SV.$= (4::Int) + GL.patchVertices $= 4 uniform (UniformLocation 4) $= rcPMatrix rc uniform (UniformLocation 5) $= rcMVMatrix rc uniform (UniformLocation 7) $= rcNormalMatrix rc @@ -471,11 +541,11 @@ buildWaterObject builder = do uniform fogU $= Index1 (0.0::GLfloat) -makeResources :: SDL.Surface -> BuilderM GLfloat b -> +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 surf builder forestB jungleB water arr waterarr = do +makeResources window builder forestB jungleB water arr waterarr = do let pMatrix' = perspectiveMatrix 50 1.8 0.1 100 let l_routines = sequence [ @@ -494,7 +564,7 @@ makeResources surf builder forestB jungleB water arr waterarr = do -- cloudProgram ] Resources - <$> pure surf + <$> pure window <*> do CameraPosition <$> pure (Vec3 (10,10,2)) <*> pure 0 @@ -565,18 +635,18 @@ skyboxObject = do 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 <- 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 <- 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 <- 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 <- load "textures/skybox_top_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_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"] @@ -585,13 +655,14 @@ skyboxObject = do 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" + currentProgram $= Just prog + setupTexturing l_texture texLoc 0 + setupTexturing l_texture2 texLocNight 1 + printErrors "Skybox" let obj' = teardown obj $ \_ -> do - draw topObj + draw topObj + return $ \rc -> do depthFunc $= Nothing cullFace $= Nothing -- cgit