diff options
-rw-r--r-- | Data/ByteStringBuilder.hs | 15 | ||||
-rw-r--r-- | Final.hs | 629 | ||||
-rw-r--r-- | Graphics/Glyph/ArrayGenerator.hs | 41 | ||||
-rw-r--r-- | Graphics/Glyph/BufferBuilder.hs | 466 | ||||
-rw-r--r-- | Graphics/Glyph/ExtendedGL.hs | 11 | ||||
-rw-r--r-- | Graphics/Glyph/ExtendedGL/Base.hs | 124 | ||||
-rw-r--r-- | Graphics/Glyph/ExtendedGL/Framebuffers.hs | 137 | ||||
-rw-r--r-- | Graphics/Glyph/GLMath.hs | 431 | ||||
-rw-r--r-- | Graphics/Glyph/GeometryBuilder.hs | 249 | ||||
-rw-r--r-- | Graphics/Glyph/GlyphObject.hs | 189 | ||||
-rw-r--r-- | Graphics/Glyph/ObjLoader.hs | 166 | ||||
-rw-r--r-- | Graphics/Glyph/Shaders.hs | 144 | ||||
-rw-r--r-- | Graphics/Glyph/Textures.hs | 47 | ||||
-rw-r--r-- | Graphics/Glyph/Util.hs | 265 | ||||
-rw-r--r-- | Graphics/Rendering/HelpGL.hs | 12 | ||||
-rw-r--r-- | Graphics/SDL/SDLHelp.hs | 203 | ||||
-rw-r--r-- | Models.hs | 129 | ||||
-rw-r--r-- | Resources.hs | 1407 |
18 files changed, 2494 insertions, 2171 deletions
diff --git a/Data/ByteStringBuilder.hs b/Data/ByteStringBuilder.hs index 6f0222e..98b3db5 100644 --- a/Data/ByteStringBuilder.hs +++ b/Data/ByteStringBuilder.hs @@ -5,9 +5,10 @@ import Data.ByteString.Lazy.Char8 as BSLC import Data.Word data ByteStringBuilder a = ByteStringBuilder ByteString a + type Builder = ByteStringBuilder () -put :: ByteString -> Builder +put :: ByteString -> Builder put = flip ByteStringBuilder () putS :: String -> Builder @@ -30,13 +31,13 @@ instance Functor ByteStringBuilder where instance Applicative ByteStringBuilder where (<*>) afn aa = do - fn <- afn - a <- aa - return (fn a) + fn <- afn + a <- aa + return (fn a) pure = return instance Monad ByteStringBuilder where - ByteStringBuilder a _ >> ByteStringBuilder b c = ByteStringBuilder (a `append` b) c - a@(ByteStringBuilder _ b) >>= func = a >> func b - return = ByteStringBuilder BSL.empty + ByteStringBuilder a _ >> ByteStringBuilder b c = ByteStringBuilder (a `append` b) c + a@(ByteStringBuilder _ b) >>= func = a >> func b + return = ByteStringBuilder BSL.empty @@ -1,38 +1,30 @@ {-# LANGUAGE BangPatterns #-} -{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE ViewPatterns #-} module Main where -import Text.Printf -import Graphics.Rendering.OpenGL as GL -import SDL.Image as SDLImg -import SDL -import Graphics.SDL.SDLHelp -import Graphics.Glyph.Util import Control.Monad import Control.Monad.Writer - -import Graphics.Glyph.BufferBuilder - -import qualified Data.Map as Map -import Data.Word import Data.Array import Data.Array.IO - -import Data.Sequence as Seq -import Data.Sequence (Seq) -import Prelude as P - import Data.Bits - +import qualified Data.Map as Map +import Data.Sequence (Seq) +import Data.Sequence as Seq +import Data.Word +import Graphics.Glyph.BufferBuilder +import Graphics.Glyph.Util +import Graphics.Rendering.OpenGL as GL +import Graphics.SDL.SDLHelp import Resources -import System.Random - -import System.Environment -import qualified SDL +import SDL import qualified SDL - +import SDL.Image as SDLImg +import System.Environment +import System.Random +import Text.Printf +import Prelude as P {- - This function builds an array of tile from the heightmap and @@ -42,320 +34,357 @@ import qualified SDL - w is the minimum width of the two images and h is the minimum - height. -} -buildArray :: SDL.Surface -> SDL.Surface -> IO (Array (Int,Int) Tile) +buildArray :: SDL.Surface -> SDL.Surface -> IO (Array (Int, Int) Tile) buildArray terrain height = do - bpp <- fromIntegral <$> (getSurfaceBytesPerPixel terrain) :: IO Int - printf "Terrain BBP: %d\n" bpp - - - (V2 (fromIntegral -> w) (fromIntegral -> h)) <- SDL.surfaceDimensions terrain - {- Pick the minimum width and height between the two images -} - let {- Function that returns a Tile for an x y coordinate -} - conv x y = - let terrainVal = fromIntegral $ getPixelUnsafe x y terrain - {- The height is encoded as the sum of the color channels, to make life a litte - - easier on the heightmap reader. -} - sumit word = - ((word `shiftR` 8) .&. 0xFF) + - ((word `shiftR`16) .&. 0xFF) + - ((word `shiftR`24) .&. 0xFF) - - {- The value of the hightmap at the coordinate. I will promise - - the compmiler that my surfaces will not change. -} - heightVal = (fromIntegral.sumit) (getPixelUnsafe x y height) - - {- The value of the terrain map at thata location -} - terrainVal' = Map.findWithDefault Resources.Unknown terrainVal tileMap in - Tile terrainVal' heightVal - - {- build the list of Tiles to jam into the array -} - list = [conv x y | x <- [0..w-1], y <- [0..h-1]] - in return $ listArray ((0,0),(w-1,h-1)) list + bpp <- fromIntegral <$> (getSurfaceBytesPerPixel terrain) :: IO Int + printf "Terrain BBP: %d\n" bpp + + (V2 (fromIntegral -> w) (fromIntegral -> h)) <- SDL.surfaceDimensions terrain + {- Pick the minimum width and height between the two images -} + let {- Function that returns a Tile for an x y coordinate -} + conv x y = + let terrainVal = fromIntegral $ getPixelUnsafe x y terrain + {- The height is encoded as the sum of the color channels, to make life a litte + - easier on the heightmap reader. -} + sumit word = + ((word `shiftR` 8) .&. 0xFF) + + ((word `shiftR` 16) .&. 0xFF) + + ((word `shiftR` 24) .&. 0xFF) + + {- The value of the hightmap at the coordinate. I will promise + - the compmiler that my surfaces will not change. -} + heightVal = (fromIntegral . sumit) (getPixelUnsafe x y height) + + {- The value of the terrain map at thata location -} + terrainVal' = Map.findWithDefault Resources.Unknown terrainVal tileMap + in Tile terrainVal' heightVal + + {- build the list of Tiles to jam into the array -} + list = [conv x y | x <- [0 .. w -1], y <- [0 .. h -1]] + in return $ listArray ((0, 0), (w -1, h -1)) list {- This function takes the array generated in the function from above and - creates a new array that colors in the array with locations of bodies - of water and assigns an id to each of them. This allows for me to go - back and assign heights for the bodies of water. -} -colorArray :: Array (Int,Int) Tile -> IO (IOArray (Int,Int) Int) +colorArray :: Array (Int, Int) Tile -> IO (IOArray (Int, Int) Int) colorArray marr = do - - {- Very simple function that take splits a sequence - - into a head and a tail -} - let pollseq (Seq.viewl -> (head' :< tail')) = (head',tail') - pollseq _ = undefined - - let bnd@(_,(w,h)) = bounds marr - ret <- newArray bnd 0 - - {- Boolean funcion. Returns true if the - - tile at the position `place` is water - - and has not yet been assigned an id -} - let myfunction a_place = do - val <- readArray ret a_place - case marr ! a_place of - (Tile Water _) -> return $ val==0 - _ -> return False - - {- Uses a queue method to flood fill bodies - - of water and write that to an array -} - let floodfill :: (Int,Int) -> ((Int,Int) -> IO Bool) -> Int -> IO () - floodfill start func' val = do - let func t@(x,y) = if not (x <= w && x >= 0 && y <= h && y >= 0) then return False else func' t - {- Just magic. Does a flood fill -} - _ <- untilM2 (return . Seq.null) (Seq.singleton start) $ \queue -> do - let (head',tail') = pollseq queue - bool <- func head' - if not bool then return tail' else do - (_,tail2) <- untilM2 (liftM not . func . fst) (head',tail') $ \((x,y),queue') -> do - (ret <!> (x,y)) $= val - return ((x+1,y),queue' |> (x,y-1) |> (x,y+1)) - (_,tail3) <- untilM2 (liftM not . func . fst) (head',tail2) $ \((x,y),queue') -> do - (ret <!> (x,y)) $= val - return ((x-1,y), queue' |> (x,y-1) |> (x,y+1)) - return tail3 - return () - {- Iterates through all the points and does a flood fill on - - them -} - foldM_ (\val place -> do + {- Very simple function that take splits a sequence + - into a head and a tail -} + let pollseq (Seq.viewl -> (head' :< tail')) = (head', tail') + pollseq _ = undefined + + let bnd@(_, (w, h)) = bounds marr + ret <- newArray bnd 0 + + {- Boolean funcion. Returns true if the + - tile at the position `place` is water + - and has not yet been assigned an id -} + let myfunction a_place = do + val <- readArray ret a_place + case marr ! a_place of + (Tile Water _) -> return $ val == 0 + _ -> return False + + {- Uses a queue method to flood fill bodies + - of water and write that to an array -} + let floodfill :: (Int, Int) -> ((Int, Int) -> IO Bool) -> Int -> IO () + floodfill start func' val = do + let func t@(x, y) = if not (x <= w && x >= 0 && y <= h && y >= 0) then return False else func' t + {- Just magic. Does a flood fill -} + _ <- untilM2 (return . Seq.null) (Seq.singleton start) $ \queue -> do + let (head', tail') = pollseq queue + bool <- func head' + if not bool + then return tail' + else do + (_, tail2) <- untilM2 (liftM not . func . fst) (head', tail') $ \((x, y), queue') -> do + (ret <!> (x, y)) $= val + return ((x + 1, y), queue' |> (x, y -1) |> (x, y + 1)) + (_, tail3) <- untilM2 (liftM not . func . fst) (head', tail2) $ \((x, y), queue') -> do + (ret <!> (x, y)) $= val + return ((x -1, y), queue' |> (x, y -1) |> (x, y + 1)) + return tail3 + return () + {- Iterates through all the points and does a flood fill on + - them -} + foldM_ + ( \val place -> do bool <- myfunction place - if bool then do + if bool + then do floodfill place myfunction val - return $ val+1 - else return val - ) 1 [(x,y) | x <- [0..w], y <- [0..h]] - return ret + return $ val + 1 + else return val + ) + 1 + [(x, y) | x <- [0 .. w], y <- [0 .. h]] + return ret {- This function takes the two arrays from the functions above and generates - 2 things: - A map of water bodies ids to elevations (to detect if you are under water - A builder that will generate all of the quads for the water. -} -getWaterQuads :: Array (Int,Int) Tile -> IOArray (Int,Int) Int -> IO ( Map.Map Int GLfloat, BuilderM GLfloat () ) +getWaterQuads :: Array (Int, Int) Tile -> IOArray (Int, Int) Int -> IO (Map.Map Int GLfloat, BuilderM GLfloat ()) getWaterQuads marr arr = do - let (_,(w,h)) = bounds marr - - {- Iterates through the bodies of water and finds the lowest altitude - - of the land surrounding the water. Returns a type of body id - - to minx, miny, maxx, maxy and elevation -} - let elevationCacheIO :: IO (Map.Map Int (Int,Int,Int,Int,Int)) - elevationCacheIO = do - {- Tuple of functions that will be mapped with - - the application operator ($) -} - let tup = (min,max,max,min,min) - foldM (\themap (x,y) -> do - bodyID <- readArray arr (x,y) - if bodyID == 0 then return themap else do - let valid (aX,aY) = aX >= 0 && aX <= w && aY >= 0 && aY <= h - let neighbors (aX,aY) = P.filter valid $ map (zipWithT2 (+) (aX,aY)) - [ (1,0), - (0,1), (0,-1), - (-1,0) ] - let toelev aX = - let tile = marr ! aX in - (tileType tile == Water) ? 1000000000000 $ elevation tile - let elev = minimum $ map toelev (neighbors (x,y)) - let newmap = - Map.insertWith (zipWithT5 (P.$) . zipWithT5 (P.$) tup) - bodyID (elev,x,y,x,y) themap - return newmap - ) (Map.empty::Map.Map Int (Int,Int,Int,Int,Int)) [(x,y) | x <- [0..w], y <- [0..h]] - - elevMap <- elevationCacheIO - - {- A map between body id and elevation. Get rid of the bounding quad box -} - let elevMap2 = Map.map (\(elev,_,_,_,_) -> - fromIntegral elev / 10) elevMap - - let dat = Map.toList elevMap - {- Iterate through the map and draw the bounding quad - - for the body of water -} - return (elevMap2,sequence_ $ for dat $ \(_, (elev,maxx,maxy,minx,miny)) -> - let mxx = fromIntegral maxx + 1 - mnx = fromIntegral minx - 1 - mxy = fromIntegral maxy + 1 - mny = fromIntegral miny - 1 - relev = fromIntegral elev / 10 in - mapM_ bVertex3 - [(mxx,relev,mxy), - (mxx,relev,mny), - (mnx,relev,mny), - (mnx,relev,mxy)]) - - -printArray :: Array (Int,Int) Tile -> IO () + let (_, (w, h)) = bounds marr + + {- Iterates through the bodies of water and finds the lowest altitude + - of the land surrounding the water. Returns a type of body id + - to minx, miny, maxx, maxy and elevation -} + let elevationCacheIO :: IO (Map.Map Int (Int, Int, Int, Int, Int)) + elevationCacheIO = do + {- Tuple of functions that will be mapped with + - the application operator ($) -} + let tup = (min, max, max, min, min) + foldM + ( \themap (x, y) -> do + bodyID <- readArray arr (x, y) + if bodyID == 0 + then return themap + else do + let valid (aX, aY) = aX >= 0 && aX <= w && aY >= 0 && aY <= h + let neighbors (aX, aY) = + P.filter valid $ + map + (zipWithT2 (+) (aX, aY)) + [ (1, 0), + (0, 1), + (0, -1), + (-1, 0) + ] + let toelev aX = + let tile = marr ! aX + in (tileType tile == Water) ? 1000000000000 $ elevation tile + let elev = minimum $ map toelev (neighbors (x, y)) + let newmap = + Map.insertWith + (zipWithT5 (P.$) . zipWithT5 (P.$) tup) + bodyID + (elev, x, y, x, y) + themap + return newmap + ) + (Map.empty :: Map.Map Int (Int, Int, Int, Int, Int)) + [(x, y) | x <- [0 .. w], y <- [0 .. h]] + + elevMap <- elevationCacheIO + + {- A map between body id and elevation. Get rid of the bounding quad box -} + let elevMap2 = + Map.map + ( \(elev, _, _, _, _) -> + fromIntegral elev / 10 + ) + elevMap + + let dat = Map.toList elevMap + {- Iterate through the map and draw the bounding quad + - for the body of water -} + return + ( elevMap2, + sequence_ $ + for dat $ \(_, (elev, maxx, maxy, minx, miny)) -> + let mxx = fromIntegral maxx + 1 + mnx = fromIntegral minx - 1 + mxy = fromIntegral maxy + 1 + mny = fromIntegral miny - 1 + relev = fromIntegral elev / 10 + in mapM_ + bVertex3 + [ (mxx, relev, mxy), + (mxx, relev, mny), + (mnx, relev, mny), + (mnx, relev, mxy) + ] + ) + +printArray :: Array (Int, Int) Tile -> IO () printArray arr = do - let (_,(w,h)) = bounds arr - putStrLn $ "w=" ++! (w+1) - putStrLn $ "h=" ++! (h+1) - forM_ [0..h] $ \y -> do - forM_ [0..w] $ \x -> do - let lNext = arr ! (x,y) - putStr $ show $ tileType lNext - putStr " " - forM_ [0..w] $ \x -> do - let lNext = arr ! (x,y) - putStr $ elevShow $ elevation lNext - putStrLn "" - where elevShow x = - let len = P.length elevMap - nx = x `div` 5 in - if nx >= len then "=" else [elevMap !! nx] - elevMap = "`.,-~*<:!;%&#@0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" - -printShowArray :: (Show a) => IOArray (Int,Int) a -> IO () + let (_, (w, h)) = bounds arr + putStrLn $ "w=" ++! (w + 1) + putStrLn $ "h=" ++! (h + 1) + forM_ [0 .. h] $ \y -> do + forM_ [0 .. w] $ \x -> do + let lNext = arr ! (x, y) + putStr $ show $ tileType lNext + putStr " " + forM_ [0 .. w] $ \x -> do + let lNext = arr ! (x, y) + putStr $ elevShow $ elevation lNext + putStrLn "" + where + elevShow x = + let len = P.length elevMap + nx = x `div` 5 + in if nx >= len then "=" else [elevMap !! nx] + elevMap = "`.,-~*<:!;%&#@0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" + +printShowArray :: (Show a) => IOArray (Int, Int) a -> IO () printShowArray arr = do - (_,(w,h)) <- getBounds arr - putStrLn $ "w=" ++! (w+1) - putStrLn $ "h=" ++! (h+1) - forM_ [0..h] $ \y -> do - forM_ [0..w] $ \x -> do - lNext <- readArray arr (x,y) - putStr $ show lNext ++ " " - putStrLn "" + (_, (w, h)) <- getBounds arr + putStrLn $ "w=" ++! (w + 1) + putStrLn $ "h=" ++! (h + 1) + forM_ [0 .. h] $ \y -> do + forM_ [0 .. w] $ \x -> do + lNext <- readArray arr (x, y) + putStr $ show lNext ++ " " + putStrLn "" {- The colors each tile type is mapped to - as an array -} -toColor :: TileType -> (GLfloat,GLfloat,GLfloat,GLfloat) -toColor Tundra = (0.5,0.5,0.5,1.0) -toColor Mountains = (0.5,0.4,0.03,1.0) -toColor Grass = (0,0.3,0.0,1.0) -toColor Jungle = (0,1.0,0.0,1.0) -toColor Forest = (0,0.2,0.0,1.0) -toColor Beach = (0.7,0.7,0.6,1.0) -toColor Water = (0,0,1.0,1.0) -toColor Resources.Unknown = (0,0,0,0) +toColor :: TileType -> (GLfloat, GLfloat, GLfloat, GLfloat) +toColor Tundra = (0.5, 0.5, 0.5, 1.0) +toColor Mountains = (0.5, 0.4, 0.03, 1.0) +toColor Grass = (0, 0.3, 0.0, 1.0) +toColor Jungle = (0, 1.0, 0.0, 1.0) +toColor Forest = (0, 0.2, 0.0, 1.0) +toColor Beach = (0.7, 0.7, 0.6, 1.0) +toColor Water = (0, 0, 1.0, 1.0) +toColor Resources.Unknown = (0, 0, 0, 0) {- Map of color to TileType used for - parsing the terrain map -} tileMap :: Map.Map Word32 TileType tileMap = - let c = rgbToWord in - Map.insert (c 100 100 100) Tundra $ - Map.insert (c 128 100 20) Mountains $ - Map.insert (c 0 100 0) Grass $ - Map.insert (c 0 255 0) Jungle $ - Map.insert (c 0 50 0) Forest $ - Map.insert (c 255 255 255) Beach $ - Map.singleton (c 0 0 255) Water + let c = rgbToWord + in Map.insert (c 100 100 100) Tundra $ + Map.insert (c 128 100 20) Mountains $ + Map.insert (c 0 100 0) Grass $ + Map.insert (c 0 255 0) Jungle $ + Map.insert (c 0 50 0) Forest $ + Map.insert (c 255 255 255) Beach $ + Map.singleton (c 0 0 255) Water {- The function that generates the builder that will - generate the VAO for the terrain based on the heightmap -} -createBuilder :: Array (Int,Int) Tile -> BuilderM GLfloat () +createBuilder :: Array (Int, Int) Tile -> BuilderM GLfloat () createBuilder arr = do - let (_,(w,h)) = bounds arr - - let lst = concatMap (\(x,y) -> - let g (x',z',w') = (x', fromIntegral (elevation $ arr ! (x',z')) / 10.0, z', w') in - - [g (x, y ,1::Int), - g (x-1,y ,1), - g (x-1,y-1,1), - g (x, y-1,1)] ) - - [(x,y) | x <- [1..w], y <- [1..h]] - - inferingNormals $ - forM_ (trianglesFromQuads lst) $ \(x,y,z,_) -> do - let f = fromIntegral - - {- Store the texture to use in the color -} - let bUseTexture a = bColor4 (0,0,0,f a) + let (_, (w, h)) = bounds arr + + let lst = + concatMap + ( \(x, y) -> + let g (x', z', w') = (x', fromIntegral (elevation $ arr ! (x', z')) / 10.0, z', w') + in [ g (x, y, 1 :: Int), + g (x -1, y, 1), + g (x -1, y -1, 1), + g (x, y -1, 1) + ] + ) + [(x, y) | x <- [1 .. w], y <- [1 .. h]] + + inferingNormals $ + forM_ (trianglesFromQuads lst) $ \(x, y, z, _) -> do + let f = fromIntegral + + {- Store the texture to use in the color -} + let bUseTexture a = bColor4 (0, 0, 0, f a) + + bUseTexture $ fromEnum (tileType $ arr ! (x, z)) + bTexture2 (f x / 10.0, f z / 10.0) + bVertex3 (f x, y, f z) - bUseTexture $ fromEnum (tileType $ arr ! (x,z)) - bTexture2 (f x / 10.0, f z / 10.0) - bVertex3 (f x, y,f z) - {- Generates random locations for the trees inside of the terrain - - spots where trees may exist + - spots where trees may exist - - A MonadPlusBuilder is a Monad used to build monad pluses; in this - case a Sequence. -} -createLocations :: Array (Int,Int) Tile -> StdGen -> Int -> TileType -> Writer (Seq GLfloat) () +createLocations :: Array (Int, Int) Tile -> StdGen -> Int -> TileType -> Writer (Seq GLfloat) () createLocations arr gen density typ = do - let (_,(w,h)) = bounds arr - let getElev x y = if x >= w || y >= h || x < 0 || y < 0 then 0 else fromIntegral (elevation $ arr ! (x,y)) /10.0 - - {- Adds a random number of trees between 0 and density for the location -} - let run rs (x',y') = do - let (_:ntrees, t) = P.splitAt (head rs `mod` density + 1) rs - - when (isType x' y' typ) $ - {- Iterate and place n trees -} - forM_ ntrees $ \rand -> - let (a',b',c) = toTup rand - (x,y) = (int x' + f a', int y' + f b') :: (GLfloat,GLfloat) - [sx,sy,sz,rot,noise,shade] = (P.take 6 $ randomRs (0.0,1.0) $ mkStdGen c) - - {- Boiler for finding the correct elevation between vertices -} - h1 = getElev (floor x) (floor y) - h2 = getElev (floor x) (floor (y+1)) - h3 = getElev (floor (x+1)) (floor y) - h4 = getElev (floor (x+1)) (floor (y+1)) - u = fpart x - v = fpart y - mixu1 = mix h3 h1 u - mixu2 = mix h4 h2 u - newh = mix mixu2 mixu1 v in - - {- Add to the sequence of elements. This - - will be turned into a per-instance VAO -} - tell $ Seq.fromList [ - -- translation - x,newh-0.2,y, - -- scale - sx+0.5,sy+0.5,sz+0.5, - -- rotation - sin (rot*6.4), cos(rot*6.4), - -- noise - noise*6.4, - shade / 2 + 0.75 - ] - - {- Return the tail of the randomly generated numbers -} - return t - - foldM_ run (randoms gen) [(x,y) | x <- [1..w], y <- [1..h]] - - where isType x y t = tileType (arr ! (x,y)) == t - f x = (fromIntegral x - 128) / 128 * (sqrt 2 / 2) - toTup x = ( x .&. 0xFF , - (x `shiftR` 8) .&. 0xFF, - (x `shiftR` 16) .&. 0xFF) - + let (_, (w, h)) = bounds arr + let getElev x y = if x >= w || y >= h || x < 0 || y < 0 then 0 else fromIntegral (elevation $ arr ! (x, y)) / 10.0 + + {- Adds a random number of trees between 0 and density for the location -} + let run rs (x', y') = do + let (_ : ntrees, t) = P.splitAt (head rs `mod` density + 1) rs + + when (isType x' y' typ) $ + {- Iterate and place n trees -} + forM_ ntrees $ \rand -> + let (a', b', c) = toTup rand + (x, y) = (int x' + f a', int y' + f b') :: (GLfloat, GLfloat) + [sx, sy, sz, rot, noise, shade] = (P.take 6 $ randomRs (0.0, 1.0) $ mkStdGen c) + + {- Boiler for finding the correct elevation between vertices -} + h1 = getElev (floor x) (floor y) + h2 = getElev (floor x) (floor (y + 1)) + h3 = getElev (floor (x + 1)) (floor y) + h4 = getElev (floor (x + 1)) (floor (y + 1)) + u = fpart x + v = fpart y + mixu1 = mix h3 h1 u + mixu2 = mix h4 h2 u + newh = mix mixu2 mixu1 v + in {- Add to the sequence of elements. This + - will be turned into a per-instance VAO -} + tell $ + Seq.fromList + [ -- translation + x, + newh -0.2, + y, + -- scale + sx + 0.5, + sy + 0.5, + sz + 0.5, + -- rotation + sin (rot * 6.4), + cos (rot * 6.4), + -- noise + noise * 6.4, + shade / 2 + 0.75 + ] + + {- Return the tail of the randomly generated numbers -} + return t + + foldM_ run (randoms gen) [(x, y) | x <- [1 .. w], y <- [1 .. h]] + where + isType x y t = tileType (arr ! (x, y)) == t + f x = (fromIntegral x - 128) / 128 * (sqrt 2 / 2) + toTup x = + ( x .&. 0xFF, + (x `shiftR` 8) .&. 0xFF, + (x `shiftR` 16) .&. 0xFF + ) main :: IO () main = do - let doload str = sequence - [ SDLImg.load $ "maps/"++str++"_terrain.png", - SDLImg.load $ "maps/"++str++"_height.png" ] - args <- getArgs - - {- Load the terrain and heightmaps from SDL. -} - [terrain,height] <- - case args of - (ter:hei:_) -> sequence [SDLImg.load ter, SDLImg.load hei] - (m:_) -> doload m - _ -> sequence [SDLImg.load "maps/wonderland_terrain.png", SDLImg.load "maps/wonderland_height.png"] - - arr <- buildArray terrain height - coloredArr <- colorArray arr - - window <- simpleStartup "Terralloc" (1280,1024) - stgen <- newStdGen - stgen2 <- newStdGen - - {- Create the tree locations. Desity of 7 for the forest, 2 for the jungle - - since the jungle model is bigger -} - let !forestLocations = execWriter $ createLocations arr stgen 7 Forest - let !jungleLocations = execWriter $ createLocations arr stgen2 2 Jungle - - (mapping,water) <- getWaterQuads arr coloredArr - coloredArr2 <- mapArray (\idx -> if idx == 0 then -1 else Map.findWithDefault (-1) idx mapping) coloredArr - - printShowArray coloredArr2 - printArray arr - - {- Kick off SDL with the callbacks defined in Resources -} - makeResources window (createBuilder arr) forestLocations jungleLocations water arr coloredArr2 - >>= startPipeline reshape eventHandle displayHandle updateHandle; + let doload str = + sequence + [ SDLImg.load $ "maps/" ++ str ++ "_terrain.png", + SDLImg.load $ "maps/" ++ str ++ "_height.png" + ] + args <- getArgs + + {- Load the terrain and heightmaps from SDL. -} + [terrain, height] <- + case args of + (ter : hei : _) -> sequence [SDLImg.load ter, SDLImg.load hei] + (m : _) -> doload m + _ -> sequence [SDLImg.load "maps/wonderland_terrain.png", SDLImg.load "maps/wonderland_height.png"] + + arr <- buildArray terrain height + coloredArr <- colorArray arr + + window <- simpleStartup "Terralloc" (1280, 1024) + stgen <- newStdGen + stgen2 <- newStdGen + + {- Create the tree locations. Desity of 7 for the forest, 2 for the jungle + - since the jungle model is bigger -} + let !forestLocations = execWriter $ createLocations arr stgen 7 Forest + let !jungleLocations = execWriter $ createLocations arr stgen2 2 Jungle + + (mapping, water) <- getWaterQuads arr coloredArr + coloredArr2 <- mapArray (\idx -> if idx == 0 then -1 else Map.findWithDefault (-1) idx mapping) coloredArr + + printShowArray coloredArr2 + printArray arr + + {- Kick off SDL with the callbacks defined in Resources -} + makeResources window (createBuilder arr) forestLocations jungleLocations water arr coloredArr2 + >>= startPipeline reshape eventHandle displayHandle updateHandle diff --git a/Graphics/Glyph/ArrayGenerator.hs b/Graphics/Glyph/ArrayGenerator.hs index 16fe41f..088ccc7 100644 --- a/Graphics/Glyph/ArrayGenerator.hs +++ b/Graphics/Glyph/ArrayGenerator.hs @@ -1,9 +1,9 @@ {-# LANGUAGE UndecidableInstances #-} -module Graphics.Glyph.ArrayGenerator where -import qualified Data.Map as M +module Graphics.Glyph.ArrayGenerator where import Data.Array +import qualified Data.Map as M import Data.Maybe data ArrayTransaction ix val b = ArrayBuilderM_ (M.Map ix val) b @@ -13,33 +13,36 @@ instance (Ord ix) => Functor (ArrayTransaction ix a) where instance (Ord ix) => Applicative (ArrayTransaction ix a) where (<*>) afn aa = do - fn <- afn - a <- aa - return (fn a) + fn <- afn + a <- aa + return (fn a) pure = return instance (Ord ix) => Monad (ArrayTransaction ix a) where - return = ArrayBuilderM_ M.empty - (ArrayBuilderM_ map1 val) >>= f = - ArrayBuilderM_ (map1 `M.union` map2) val2 - where (ArrayBuilderM_ map2 val2) = f val + return = ArrayBuilderM_ M.empty + (ArrayBuilderM_ map1 val) >>= f = + ArrayBuilderM_ (map1 `M.union` map2) val2 + where + (ArrayBuilderM_ map2 val2) = f val class HasDefault a where - theDefault :: a + theDefault :: a instance (Num a) => HasDefault a where - theDefault = 0 -instance (HasDefault a, HasDefault b) => HasDefault (a,b) where - theDefault = (theDefault,theDefault) -instance (HasDefault a, HasDefault b, HasDefault c) => HasDefault (a,b,c) where - theDefault = (theDefault,theDefault,theDefault) + theDefault = 0 + +instance (HasDefault a, HasDefault b) => HasDefault (a, b) where + theDefault = (theDefault, theDefault) + +instance (HasDefault a, HasDefault b, HasDefault c) => HasDefault (a, b, c) where + theDefault = (theDefault, theDefault, theDefault) writeArray :: ix -> a -> ArrayTransaction ix a () writeArray index' val = ArrayBuilderM_ (M.singleton index' val) () -buildArray :: (Ix ix) => (ix,ix) -> e -> ArrayTransaction ix e () -> Array ix e +buildArray :: (Ix ix) => (ix, ix) -> e -> ArrayTransaction ix e () -> Array ix e buildArray bounds' def (ArrayBuilderM_ map' _) = - listArray bounds' [maybeLookup map' bound | bound <- range bounds'] - where maybeLookup map_ key = fromMaybe def (M.lookup key map_) - + listArray bounds' [maybeLookup map' bound | bound <- range bounds'] + where + maybeLookup map_ key = fromMaybe def (M.lookup key map_) diff --git a/Graphics/Glyph/BufferBuilder.hs b/Graphics/Glyph/BufferBuilder.hs index b23f6ba..8a41f9e 100644 --- a/Graphics/Glyph/BufferBuilder.hs +++ b/Graphics/Glyph/BufferBuilder.hs @@ -1,25 +1,25 @@ -{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE BangPatterns #-} -{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TemplateHaskell #-} + module Graphics.Glyph.BufferBuilder where -import Graphics.Rendering.OpenGL -import Foreign.Storable -import Foreign.Ptr -import Foreign.Marshal.Array import Data.Array.Storable import qualified Data.Foldable as Fold -import Data.Sequence as Seq import Data.Map as Map - -import Graphics.Glyph.Util +import Data.Sequence as Seq +import Foreign.Marshal.Array +import Foreign.Ptr +import Foreign.Storable import Graphics.Glyph.GLMath - +import Graphics.Glyph.Util +import Graphics.Rendering.OpenGL import System.IO.Unsafe import Unsafe.Coerce -data BufferBuilder3D = Plot BufferBuilder3D (GLfloat,GLfloat,GLfloat) Int Int | End +data BufferBuilder3D = Plot BufferBuilder3D (GLfloat, GLfloat, GLfloat) Int Int | End + bufferSize :: BufferBuilder3D -> Int bufferSize End = 0 bufferSize (Plot _ _ l _) = l @@ -31,78 +31,78 @@ nelem (Plot _ _ _ l) = l sizeofGLfloat :: Int sizeofGLfloat = 4 -simpleCube :: Num a => [(a,a,a)] -simpleCube = trianglesFromQuads [ - (-1, 1,-1) - , ( 1, 1,-1) - , ( 1,-1,-1) - , (-1,-1,-1) - - , (-1, 1, 1) - , ( 1, 1, 1) - , ( 1,-1, 1) - , (-1,-1, 1) - - , (-1, 1, 1) - , ( 1, 1, 1) - , ( 1, 1,-1) - , (-1, 1,-1) - - , (-1,-1, 1) - , ( 1,-1, 1) - , ( 1,-1,-1) - , (-1,-1,-1) - - , (-1,-1, 1) - , (-1, 1, 1) - , (-1, 1,-1) - , (-1,-1,-1) - - , ( 1,-1, 1) - , ( 1, 1, 1) - , ( 1, 1,-1) - , ( 1,-1,-1) +simpleCube :: Num a => [(a, a, a)] +simpleCube = + trianglesFromQuads + [ (-1, 1, -1), + (1, 1, -1), + (1, -1, -1), + (-1, -1, -1), + (-1, 1, 1), + (1, 1, 1), + (1, -1, 1), + (-1, -1, 1), + (-1, 1, 1), + (1, 1, 1), + (1, 1, -1), + (-1, 1, -1), + (-1, -1, 1), + (1, -1, 1), + (1, -1, -1), + (-1, -1, -1), + (-1, -1, 1), + (-1, 1, 1), + (-1, 1, -1), + (-1, -1, -1), + (1, -1, 1), + (1, 1, 1), + (1, 1, -1), + (1, -1, -1) ] class Monad a => IsModelBuilder b a where - plotVertex3 :: b -> b -> b -> a () - plotNormal :: b -> b -> b -> a () - plotTexture :: b -> b ->a () + plotVertex3 :: b -> b -> b -> a () + plotNormal :: b -> b -> b -> a () + plotTexture :: b -> b -> a () {- A state monad that keeps track of operations - and will compile them into a buffer -} data BuilderM b a = BuilderM (Builder (BuildDatum b)) a -data Builder b = Builder - !(Builder b) -- before - !(Builder b) -- after - | LeafBuilder !(Seq b) deriving Show + +data Builder b + = Builder + !(Builder b) -- before + !(Builder b) -- after + | LeafBuilder !(Seq b) + deriving (Show) instance IsModelBuilder GLfloat (BuilderM GLfloat) where - plotVertex3 x y z = bVertex3 (x,y,z) - plotNormal x y z = bNormal3 (x,y,z) - plotTexture x y = bTexture2 (x,y) - -data BuildDatum b = - VertexLink (b,b,b) | - NormalLink (b,b,b) | - ColorLink (b,b,b,b) | - TextureLink (b,b) deriving Show - -data CompiledBuild b = CompiledBuild { - bStride :: Int, - bEnabled :: (Bool,Bool,Bool), - nElems :: Int, + plotVertex3 x y z = bVertex3 (x, y, z) + plotNormal x y z = bNormal3 (x, y, z) + plotTexture x y = bTexture2 (x, y) + +data BuildDatum b + = VertexLink (b, b, b) + | NormalLink (b, b, b) + | ColorLink (b, b, b, b) + | TextureLink (b, b) + deriving (Show) + +data CompiledBuild b = CompiledBuild + { bStride :: Int, + bEnabled :: (Bool, Bool, Bool), + nElems :: Int, array :: Ptr b, arrayBytes :: Int -} + } bufferLength :: (Integral a) => CompiledBuild b -> a bufferLength = fromIntegral . nElems instance Show (CompiledBuild x) where - show (CompiledBuild stride enabled n ptr nbytes) = - "[CompiledBuild stride="++!stride++" enabled"++!enabled++" n="++!n++" ptr="++!ptr++" nbytes="++!nbytes++"]" + show (CompiledBuild stride enabled n ptr nbytes) = + "[CompiledBuild stride=" ++! stride ++ " enabled" ++! enabled ++ " n=" ++! n ++ " ptr=" ++! ptr ++ " nbytes=" ++! nbytes ++ "]" instance Functor (BuilderM t) where fmap f b = b >>= (return . f) @@ -115,206 +115,240 @@ instance Applicative (BuilderM t) where return (fn a) instance Monad (BuilderM t) where - (BuilderM !builder1 _) >> (BuilderM !builder2 ret) = - BuilderM (builder1 ><> builder2) ret - where - b1@(LeafBuilder !seq1) ><> b2@(LeafBuilder !seq2) - | Seq.length seq1 + Seq.length seq2 < 128 = LeafBuilder (seq1 >< seq2) - | otherwise = Builder b1 b2 - (Builder !b1 !b2) ><> leaf@(LeafBuilder !_) = - (Builder b1 (b2 ><> leaf)) - builder1' ><> builder2' = (Builder builder1' builder2') + (BuilderM !builder1 _) >> (BuilderM !builder2 ret) = + BuilderM (builder1 ><> builder2) ret + where + b1@(LeafBuilder !seq1) ><> b2@(LeafBuilder !seq2) + | Seq.length seq1 + Seq.length seq2 < 128 = LeafBuilder (seq1 >< seq2) + | otherwise = Builder b1 b2 + (Builder !b1 !b2) ><> leaf@(LeafBuilder !_) = + (Builder b1 (b2 ><> leaf)) + builder1' ><> builder2' = (Builder builder1' builder2') - b1@(BuilderM _ ret) >>= func = b1 >> func ret + b1@(BuilderM _ ret) >>= func = b1 >> func ret - return = BuilderM (LeafBuilder Seq.empty) + return = BuilderM (LeafBuilder Seq.empty) instance Functor Builder where - fmap f (Builder b1 b2) = (Builder (fmap f b1) (fmap f b2)) - fmap f (LeafBuilder seq') = (LeafBuilder (fmap f seq')) + fmap f (Builder b1 b2) = (Builder (fmap f b1) (fmap f b2)) + fmap f (LeafBuilder seq') = (LeafBuilder (fmap f seq')) instance Fold.Foldable Builder where - foldl f ini (Builder b1 b2) = - Fold.foldl f (Fold.foldl f ini b1) b2 - foldl f ini (LeafBuilder seq') = - Fold.foldl f ini seq' + foldl f ini (Builder b1 b2) = + Fold.foldl f (Fold.foldl f ini b1) b2 + foldl f ini (LeafBuilder seq') = + Fold.foldl f ini seq' - foldr f ini (Builder b1 b2) = - Fold.foldr f (Fold.foldr f ini b2) b1 - foldr f ini (LeafBuilder seq') = - Fold.foldr f ini seq' + foldr f ini (Builder b1 b2) = + Fold.foldr f (Fold.foldr f ini b2) b1 + foldr f ini (LeafBuilder seq') = + Fold.foldr f ini seq' -expandBuilder :: Builder a -> b -> (b -> a -> (b,[a])) -> Builder a +expandBuilder :: Builder a -> b -> (b -> a -> (b, [a])) -> Builder a expandBuilder builder ini f = snd $ expandBuilder' builder ini f - where expandBuilder' :: Builder a -> b -> (b -> a -> (b,[a])) -> (b,Builder a) - - expandBuilder' (Builder builder1 builder2) ini' f' = - let (snowball1,newBuilder1) = expandBuilder' builder1 ini' f' - (snowball2,newBuilder2) = expandBuilder' builder2 snowball1 f' in - (snowball2,Builder newBuilder1 newBuilder2) - - expandBuilder' (LeafBuilder seq1) initial func = - let (sequ,snow) = Fold.foldl' (\(seq', snowball) datum -> - let (snow',lst) = func snowball datum in - (seq' >< Seq.fromList lst,snow')) (Seq.empty,initial) seq1 in - (snow,LeafBuilder sequ) + where + expandBuilder' :: Builder a -> b -> (b -> a -> (b, [a])) -> (b, Builder a) + + expandBuilder' (Builder builder1 builder2) ini' f' = + let (snowball1, newBuilder1) = expandBuilder' builder1 ini' f' + (snowball2, newBuilder2) = expandBuilder' builder2 snowball1 f' + in (snowball2, Builder newBuilder1 newBuilder2) + expandBuilder' (LeafBuilder seq1) initial func = + let (sequ, snow) = + Fold.foldl' + ( \(seq', snowball) datum -> + let (snow', lst) = func snowball datum + in (seq' >< Seq.fromList lst, snow') + ) + (Seq.empty, initial) + seq1 + in (snow, LeafBuilder sequ) {- Add a vertex to the current builder -} -bVertex3 :: (a,a,a) -> BuilderM a () +bVertex3 :: (a, a, a) -> BuilderM a () bVertex3 vert = BuilderM (LeafBuilder (Seq.singleton $ VertexLink vert)) () -bTexture2 :: (a,a) -> BuilderM a () +bTexture2 :: (a, a) -> BuilderM a () bTexture2 tex = BuilderM (LeafBuilder (Seq.singleton $ TextureLink tex)) () -bNormal3 :: (a,a,a) -> BuilderM a () +bNormal3 :: (a, a, a) -> BuilderM a () bNormal3 norm = BuilderM (LeafBuilder (Seq.singleton $ NormalLink norm)) () -bColor4 :: (a,a,a,a) -> BuilderM a () +bColor4 :: (a, a, a, a) -> BuilderM a () bColor4 col = BuilderM (LeafBuilder (Seq.singleton $ ColorLink col)) () writeAndAvance :: (Storable a) => [a] -> Ptr a -> IO (Ptr a) -writeAndAvance (a:as) ptr = poke ptr a >> writeAndAvance as (advancePtr ptr 1) +writeAndAvance (a : as) ptr = poke ptr a >> writeAndAvance as (advancePtr ptr 1) writeAndAvance [] ptr = return ptr compilingBuilder :: (Storable b, Num b, Show b) => BuilderM b x -> IO (CompiledBuild b) compilingBuilder (BuilderM builder _) = do + putStrLn "COMPILING" + -- Size of the elements TODO unhardcode this + let sizeof = sizeOf $ builderElem builder + where + builderElem :: Builder (BuildDatum a) -> a + builderElem _ = unsafeCoerce (0 :: Int) + + {- Simply figure out what types of elementse + - exist in this buffer -} + let (bn, bc, bt, nVerts) = + Fold.foldl' + ( \(bn, bc, bt, len) ele -> + case ele of + NormalLink _ -> (True, bc, bt, len) + ColorLink _ -> (bn, True, bt, len) + TextureLink _ -> (bn, bc, True, len) + VertexLink _ -> (bn, bc, bt, len + 1) + ) + (False, False, False, 0) + builder + {- Calculate the stride; number of floats per element -} + let stride = (3 + (?) bn * 3 + (?) bc * 4 + (?) bt * 2) * sizeof + where + (?) True = 1 + (?) False = 0 + + let nbytes = stride * nVerts + putStrLn $ "Mallocing array of size: " ++! nbytes + array <- mallocArray nbytes + + -- Tuple + -- Pointer to current element, current normal/color/texture + putStrLn "Writing array buffer" + !_ <- + Fold.foldlM + ( \(ptr, cn, cc, ct) ele -> + -- trace ("foldl " ++! ele) $ + case ele of + NormalLink nn -> return (ptr, nn, cc, ct) + ColorLink nc -> return (ptr, cn, nc, ct) + TextureLink nt -> return (ptr, cn, cc, nt) + VertexLink vert -> do + ptr' <- + writeAndAvance (tp3 True vert) ptr + >>= writeAndAvance (tp3 bn cn) + >>= writeAndAvance (tp4 bc cc) + >>= writeAndAvance (tp2 bt ct) + return (ptr', cn, cc, ct) + ) + (array, (0, 0, 0), (0, 0, 0, 0), (0, 0)) + builder + putStrLn "Buffer written" + let !compiledRet = CompiledBuild stride (bn, bc, bt) nVerts array nbytes + putStrLn $ "COMPILE COMPLETE" ++! compiledRet + return compiledRet + where + tp2 True (a, b) = [a, b] + tp2 False _ = [] - putStrLn "COMPILING" - -- Size of the elements TODO unhardcode this - let sizeof = sizeOf $ builderElem builder - where builderElem :: Builder (BuildDatum a) -> a - builderElem _ = unsafeCoerce (0::Int) - - {- Simply figure out what types of elementse - - exist in this buffer -} - let (bn,bc,bt,nVerts) = Fold.foldl' (\(bn,bc,bt,len) ele -> - case ele of - NormalLink _ -> (True,bc,bt,len) - ColorLink _ -> (bn,True,bt,len) - TextureLink _ -> (bn,bc,True,len) - VertexLink _ -> (bn,bc,bt,len+1)) (False,False,False,0) builder - {- Calculate the stride; number of floats per element -} - let stride = (3 + (?)bn * 3 + (?)bc * 4 + (?)bt * 2) * sizeof - where (?) True = 1 - (?) False = 0 - - let nbytes = stride * nVerts - putStrLn $ "Mallocing array of size: " ++! nbytes - array <- mallocArray nbytes - - -- Tuple - -- Pointer to current element, current normal/color/texture - putStrLn "Writing array buffer" - !_ <- Fold.foldlM (\(ptr, cn, cc, ct) ele -> - -- trace ("foldl " ++! ele) $ - case ele of - NormalLink nn -> return (ptr,nn,cc,ct) - ColorLink nc -> return (ptr,cn,nc,ct) - TextureLink nt -> return (ptr,cn,cc,nt) - VertexLink vert -> do - ptr' <- writeAndAvance (tp3 True vert) ptr >>= - writeAndAvance (tp3 bn cn) >>= - writeAndAvance (tp4 bc cc) >>= - writeAndAvance (tp2 bt ct) - return (ptr',cn,cc,ct) ) ( array, (0,0,0), (0,0,0,0), (0,0) ) builder - putStrLn "Buffer written" - let !compiledRet = CompiledBuild stride (bn,bc,bt) nVerts array nbytes - putStrLn $ "COMPILE COMPLETE" ++! compiledRet - return compiledRet + tp3 True (a, b, c) = [a, b, c] + tp3 False _ = [] - where - tp2 True (a,b) = [a,b] - tp2 False _ = [] - - tp3 True (a,b,c) = [a,b,c] - tp3 False _ = [] - - tp4 True (a,b,c,d) = [a,b,c,d] - tp4 False _ = [] + tp4 True (a, b, c, d) = [a, b, c, d] + tp4 False _ = [] storableArrayToBuffer :: (Storable el) => BufferTarget -> StorableArray Int el -> IO BufferObject storableArrayToBuffer target arr = do - let sizeof = sizeOf $ unsafePerformIO (readArray arr 0) - [buffer] <- genObjectNames 1 - bindBuffer target $= Just buffer - len <- getBounds arr >>= (\(a,b) -> return $ (b - a) * sizeof ) - withStorableArray arr $ \ptr -> - bufferData target $= (fromIntegral len, ptr, StaticDraw) - return buffer + let sizeof = sizeOf $ unsafePerformIO (readArray arr 0) + [buffer] <- genObjectNames 1 + bindBuffer target $= Just buffer + len <- getBounds arr >>= (\(a, b) -> return $ (b - a) * sizeof) + withStorableArray arr $ \ptr -> + bufferData target $= (fromIntegral len, ptr, StaticDraw) + return buffer ptrToBuffer :: (Storable b) => BufferTarget -> Int -> Ptr b -> IO BufferObject ptrToBuffer target len ptr = do - -- len is length in bytes - [buffer] <- genObjectNames 1 - bindBuffer target $= Just buffer - bufferData target $= (fromIntegral len, ptr, StaticDraw) - return buffer + -- len is length in bytes + [buffer] <- genObjectNames 1 + bindBuffer target $= Just buffer + bufferData target $= (fromIntegral len, ptr, StaticDraw) + return buffer vertexArrayDescriptor :: CompiledBuild GLfloat -> VertexArrayDescriptor GLfloat vertexArrayDescriptor (CompiledBuild stride _ _ _ _) = VertexArrayDescriptor 3 Float (fromIntegral stride) (wordPtrToPtr 0) normalArrayDescriptor :: CompiledBuild GLfloat -> Maybe (VertexArrayDescriptor GLfloat) -normalArrayDescriptor (CompiledBuild stride (True,_,_) _ _ _) = - Just $ VertexArrayDescriptor 3 Float - (fromIntegral stride) (wordPtrToPtr (3*4)) -normalArrayDescriptor _ = Nothing +normalArrayDescriptor (CompiledBuild stride (True, _, _) _ _ _) = + Just $ + VertexArrayDescriptor + 3 + Float + (fromIntegral stride) + (wordPtrToPtr (3 * 4)) +normalArrayDescriptor _ = Nothing colorArrayDescriptor :: CompiledBuild GLfloat -> Maybe (VertexArrayDescriptor GLfloat) -colorArrayDescriptor (CompiledBuild stride tup@(_,True,_) _ _ _) = - Just $ VertexArrayDescriptor 4 Float - (fromIntegral stride) (wordPtrToPtr (offset tup)) - where offset (b1,_,_) = if b1 then (6*4) else (3*4) - -colorArrayDescriptor _ = Nothing +colorArrayDescriptor (CompiledBuild stride tup@(_, True, _) _ _ _) = + Just $ + VertexArrayDescriptor + 4 + Float + (fromIntegral stride) + (wordPtrToPtr (offset tup)) + where + offset (b1, _, _) = if b1 then (6 * 4) else (3 * 4) +colorArrayDescriptor _ = Nothing textureArrayDescriptor :: CompiledBuild GLfloat -> Maybe (VertexArrayDescriptor GLfloat) -textureArrayDescriptor (CompiledBuild stride tup@(_,_,True) _ _ _) = - Just $ VertexArrayDescriptor 2 Float - (fromIntegral stride) (wordPtrToPtr (offset tup)) - where offset (b1,b2,_) = (3 + (ifp b1 3) + (ifp b2 4)) * 4 - ifp b x = if b then x else 0 -textureArrayDescriptor _ = Nothing +textureArrayDescriptor (CompiledBuild stride tup@(_, _, True) _ _ _) = + Just $ + VertexArrayDescriptor + 2 + Float + (fromIntegral stride) + (wordPtrToPtr (offset tup)) + where + offset (b1, b2, _) = (3 + (ifp b1 3) + (ifp b2 4)) * 4 + ifp b x = if b then x else 0 +textureArrayDescriptor _ = Nothing + createBufferObject :: BufferTarget -> CompiledBuild GLfloat -> IO BufferObject createBufferObject target (CompiledBuild _ _ _ arr len) = ptrToBuffer target len arr mapListInsert :: (Ord k) => k -> a -> Map.Map k [a] -> Map.Map k [a] mapListInsert key val map = - flip (Map.insert key) map $ - case Map.lookup key map of - Nothing -> [val] - Just x -> (val:x) + flip (Map.insert key) map $ + case Map.lookup key map of + Nothing -> [val] + Just x -> (val : x) -inferingNormals :: (RealFloat a,Ord a,Show a) => BuilderM a b -> BuilderM a b +inferingNormals :: (RealFloat a, Ord a, Show a) => BuilderM a b -> BuilderM a b inferingNormals (BuilderM builder ret) = - let (normalMap,_,_) = Fold.foldl' (\(newMap, v1, v2) datum -> - case datum of - VertexLink w -> - case (v1,v2) of - (Just u, Just v) -> - let (Vec3 normal) = (Vec3 u <-> Vec3 v) × (Vec3 u <-> Vec3 w) in - (insertWith (zipWithT3 (+)) w normal newMap, Nothing, Nothing) - (Just u, Nothing) -> (newMap, v1, Just w) - (Nothing,Nothing) -> (newMap, Just w, Nothing) - _ -> (newMap,v1,v2) - ) (Map.empty,Nothing,Nothing) builder in - - let newBuilder = expandBuilder builder () $ \() datum -> - case datum of - VertexLink tup -> - let normalLink = NormalLink $ maybe (0,0,0) id $ Map.lookup tup normalMap in - ((),[normalLink, datum]) - _ -> ((),[datum]) in - - (BuilderM newBuilder ret) - + let (normalMap, _, _) = + Fold.foldl' + ( \(newMap, v1, v2) datum -> + case datum of + VertexLink w -> + case (v1, v2) of + (Just u, Just v) -> + let (Vec3 normal) = (Vec3 u <-> Vec3 v) × (Vec3 u <-> Vec3 w) + in (insertWith (zipWithT3 (+)) w normal newMap, Nothing, Nothing) + (Just u, Nothing) -> (newMap, v1, Just w) + (Nothing, Nothing) -> (newMap, Just w, Nothing) + _ -> (newMap, v1, v2) + ) + (Map.empty, Nothing, Nothing) + builder + in let newBuilder = expandBuilder builder () $ \() datum -> + case datum of + VertexLink tup -> + let normalLink = NormalLink $ maybe (0, 0, 0) id $ Map.lookup tup normalMap + in ((), [normalLink, datum]) + _ -> ((), [datum]) + in (BuilderM newBuilder ret) trianglesFromQuads :: [a] -> [a] -trianglesFromQuads (a:b:c:d:xs) = [a,b,c,a,c,d] ++ trianglesFromQuads xs +trianglesFromQuads (a : b : c : d : xs) = [a, b, c, a, c, d] ++ trianglesFromQuads xs trianglesFromQuads l = l -translating :: (Num a) => (a,a,a) -> BuilderM a b -> BuilderM a b +translating :: (Num a) => (a, a, a) -> BuilderM a b -> BuilderM a b translating trans (BuilderM builder ret) = do - BuilderM (flip fmap builder $ \datum -> - case datum of - VertexLink tup -> VertexLink $ zipWithT3 (+) tup trans - _ -> datum) ret + BuilderM + ( flip fmap builder $ \datum -> + case datum of + VertexLink tup -> VertexLink $ zipWithT3 (+) tup trans + _ -> datum + ) + ret diff --git a/Graphics/Glyph/ExtendedGL.hs b/Graphics/Glyph/ExtendedGL.hs index a056c5b..4d77924 100644 --- a/Graphics/Glyph/ExtendedGL.hs +++ b/Graphics/Glyph/ExtendedGL.hs @@ -1,8 +1,7 @@ -module Graphics.Glyph.ExtendedGL - ( - module All - ) where +module Graphics.Glyph.ExtendedGL + ( module All, + ) +where -import Graphics.Glyph.ExtendedGL.Framebuffers as All hiding (framebufferBasicParameteri) import Graphics.Glyph.ExtendedGL.Base as All - +import Graphics.Glyph.ExtendedGL.Framebuffers as All hiding (framebufferBasicParameteri) diff --git a/Graphics/Glyph/ExtendedGL/Base.hs b/Graphics/Glyph/ExtendedGL/Base.hs index 88566f4..9b50ddb 100644 --- a/Graphics/Glyph/ExtendedGL/Base.hs +++ b/Graphics/Glyph/ExtendedGL/Base.hs @@ -1,111 +1,117 @@ -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} -module Graphics.Glyph.ExtendedGL.Base where +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE UndecidableInstances #-} -import qualified Graphics.Rendering.OpenGL as GL -import Graphics.GL.Core43 -import Graphics.GL.Compatibility30 +module Graphics.Glyph.ExtendedGL.Base where +import Control.Monad +import Data.Proxy +import Data.StateVar +import Foreign.C.Types import Foreign.Marshal.Alloc import Foreign.Ptr import Foreign.Storable -import Foreign.C.Types - +import Graphics.GL.Compatibility30 +import Graphics.GL.Core43 +import qualified Graphics.Rendering.OpenGL as GL import System.IO.Unsafe -import Control.Monad - -import Data.StateVar import Unsafe.Coerce -import Data.Proxy -data ExPrimitiveMode = Points | Triangles | Lines | Patches deriving (Show,Enum) +data ExPrimitiveMode = Points | Triangles | Lines | Patches deriving (Show, Enum) class IsBindable a where - bind :: a -> IO () + bind :: a -> IO () + class IsGLEnumMarshallable a where - toGLEnum :: a -> GLenum + toGLEnum :: a -> GLenum + class IsGenerable a where - generate :: IO a + generate :: IO a + class IsWrappedPrimitive t a where - unwrap :: a -> t - wrap :: t -> a + unwrap :: a -> t + wrap :: t -> a + class HasIntegerParam t a where - parami :: t -> a -> SettableStateVar GLuint + parami :: t -> a -> SettableStateVar GLuint + class HasFloatParam t a where - paramf :: t -> a -> SettableStateVar GLfloat + paramf :: t -> a -> SettableStateVar GLfloat + class HasParamOfType b t a where - param :: t -> a -> SettableStateVar b + param :: t -> a -> SettableStateVar b class IsPrimitiveModeMarshallable a where - marshalPrimitiveMode :: a -> GLuint + marshalPrimitiveMode :: a -> GLuint castPrimitive :: forall a b t. (IsWrappedPrimitive t a, IsWrappedPrimitive t b) => Proxy t -> a -> b castPrimitive _ x = wrap unw - where - unw :: t - unw = unwrap x + where + unw :: t + unw = unwrap x instance (IsWrappedPrimitive a a) where - unwrap = id - wrap = id + unwrap = id + wrap = id + instance (IsWrappedPrimitive GLenum a) => IsGLEnumMarshallable a where - toGLEnum = unwrap + toGLEnum = unwrap instance IsPrimitiveModeMarshallable ExPrimitiveMode where - marshalPrimitiveMode x = case x of - Points -> GL_POINTS - Triangles -> GL_TRIANGLES - Lines -> GL_LINES - Patches -> GL_PATCHES + marshalPrimitiveMode x = case x of + Points -> GL_POINTS + Triangles -> GL_TRIANGLES + Lines -> GL_LINES + Patches -> GL_PATCHES instance IsPrimitiveModeMarshallable GL.PrimitiveMode where - marshalPrimitiveMode x = case x of - GL.Points -> 0x0 - GL.Lines -> 0x1 - GL.LineLoop -> 0x2 - GL.LineStrip -> 0x3 - GL.Triangles -> 0x4 - GL.TriangleStrip -> 0x5 - GL.TriangleFan -> 0x6 - GL.Quads -> 0x7 - GL.QuadStrip -> 0x8 - GL.Polygon -> 0x9 + marshalPrimitiveMode x = case x of + GL.Points -> 0x0 + GL.Lines -> 0x1 + GL.LineLoop -> 0x2 + GL.LineStrip -> 0x3 + GL.Triangles -> 0x4 + GL.TriangleStrip -> 0x5 + GL.TriangleFan -> 0x6 + GL.Quads -> 0x7 + GL.QuadStrip -> 0x8 + GL.Polygon -> 0x9 instance IsPrimitiveModeMarshallable GLuint where - marshalPrimitiveMode = id + marshalPrimitiveMode = id vertexAttributeDivisor :: GL.AttribLocation -> SettableStateVar GLuint vertexAttributeDivisor (GL.AttribLocation loc) = - makeSettableStateVar $ \val -> - glVertexAttribDivisor loc val + makeSettableStateVar $ \val -> + glVertexAttribDivisor loc val {- Sets the number of vertices per patch - for OpenGL -} patchVertices :: (Integral a) => SettableStateVar a -patchVertices = - makeSettableStateVar $ \val -> - glPatchParameteri GL_PATCH_VERTICES $ fromIntegral val +patchVertices = + makeSettableStateVar $ \val -> + glPatchParameteri GL_PATCH_VERTICES $ fromIntegral val {- Returns the maximum number of patches - for a tessilation shader -} maxPatchVertices :: IO CInt maxPatchVertices = - alloca $ \ptr -> do - glGetIntegerv GL_MAX_PATCH_VERTICES ptr - fromIntegral <$> peek ptr + alloca $ \ptr -> do + glGetIntegerv GL_MAX_PATCH_VERTICES ptr + fromIntegral <$> peek ptr getGLVersion :: IO String getGLVersion = - let lift2 (a,b) = do - x <- a ; y <- b ; return (x,y) - in - alloca $ \ptr1 -> alloca $ \ptr2 -> do + let lift2 (a, b) = do + x <- a + y <- b + return (x, y) + in alloca $ \ptr1 -> alloca $ \ptr2 -> do glGetIntegerv GL_MAJOR_VERSION ptr1 glGetIntegerv GL_MINOR_VERSION ptr2 - (v1,v2) <- lift2 (peek ptr1, peek ptr2) + (v1, v2) <- lift2 (peek ptr1, peek ptr2) return ("OpenGL " ++ show v1 ++ "." ++ show v2) coerced :: a -coerced = unsafeCoerce (0::Int) +coerced = unsafeCoerce (0 :: Int) diff --git a/Graphics/Glyph/ExtendedGL/Framebuffers.hs b/Graphics/Glyph/ExtendedGL/Framebuffers.hs index a6c2891..1de7781 100644 --- a/Graphics/Glyph/ExtendedGL/Framebuffers.hs +++ b/Graphics/Glyph/ExtendedGL/Framebuffers.hs @@ -1,109 +1,120 @@ -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE UndecidableInstances #-} module Graphics.Glyph.ExtendedGL.Framebuffers where -import Graphics.GL.Compatibility30 -import Graphics.GL.Core43 -import qualified Graphics.Rendering.OpenGL as GL - -import Graphics.Glyph.ExtendedGL.Base - +import Control.Monad +import Data.StateVar +import Foreign.C.Types import Foreign.Marshal.Alloc import Foreign.Ptr import Foreign.Storable -import Foreign.C.Types - -import Data.StateVar -import Control.Monad - +import Graphics.GL.Compatibility30 +import Graphics.GL.Core43 +import Graphics.Glyph.ExtendedGL.Base +import qualified Graphics.Rendering.OpenGL as GL import Unsafe.Coerce - -class ( - HasParamOfType GLuint FramebufferParameter a, +class + ( HasParamOfType GLuint FramebufferParameter a, HasIntegerParam GLenum a, IsGenerable a, - IsBindable a, IsWrappedPrimitive GLuint a) => IsFramebuffer a where - - -- this function MUST discard the argument - getType :: a -> GLenum + IsBindable a, + IsWrappedPrimitive GLuint a + ) => + IsFramebuffer a + where + -- this function MUST discard the argument + getType :: a -> GLenum framebufferBasicParameteri :: (IsFramebuffer a) => GLenum -> a -> GLenum -> SettableStateVar GLuint framebufferBasicParameteri typ fb enum = - makeSettableStateVar (\value -> do + makeSettableStateVar + ( \value -> do bind fb - glFramebufferParameteri typ enum $ fromIntegral value) + glFramebufferParameteri typ enum $ fromIntegral value + ) data Renderbuffer = Renderbuffer GLuint + instance IsWrappedPrimitive GLuint Renderbuffer where - unwrap (Renderbuffer x) = x + unwrap (Renderbuffer x) = x + instance IsGenerable Renderbuffer where - generate = alloca $ \ptr -> do - glGenRenderbuffers 1 ptr - liftM Renderbuffer $ peek ptr + generate = alloca $ \ptr -> do + glGenRenderbuffers 1 ptr + liftM Renderbuffer $ peek ptr + instance IsBindable Renderbuffer where - bind = glBindRenderbuffer GL_RENDERBUFFER . unwrap + bind = glBindRenderbuffer GL_RENDERBUFFER . unwrap + +data RenderbufferArgument + = DepthAttachment -data RenderbufferArgument = - DepthAttachment instance IsWrappedPrimitive GLenum RenderbufferArgument where - unwrap DepthAttachment = GL_DEPTH_ATTACHMENT + unwrap DepthAttachment = GL_DEPTH_ATTACHMENT renderBufferStorageRaw :: (IsGLEnumMarshallable a, IsGLEnumMarshallable b) => a -> b -> Int -> Int -> IO () -renderBufferStorageRaw typ enum w h = glRenderbufferStorage (toGLEnum typ) - (toGLEnum enum) (fromIntegral w) (fromIntegral h) -renderBufferStorage :: (IsGLEnumMarshallable a) => Renderbuffer -> SettableStateVar (a,Int,Int) -renderBufferStorage buffer = makeSettableStateVar $ \(en,w,h) -> do - bind buffer - renderBufferStorageRaw GL_RENDERBUFFER en w h - -frameBufferRenderBuffer :: forall a b. (IsFramebuffer a,IsGLEnumMarshallable b) => Renderbuffer -> b -> IO a +renderBufferStorageRaw typ enum w h = + glRenderbufferStorage + (toGLEnum typ) + (toGLEnum enum) + (fromIntegral w) + (fromIntegral h) + +renderBufferStorage :: (IsGLEnumMarshallable a) => Renderbuffer -> SettableStateVar (a, Int, Int) +renderBufferStorage buffer = makeSettableStateVar $ \(en, w, h) -> do + bind buffer + renderBufferStorageRaw GL_RENDERBUFFER en w h + +frameBufferRenderBuffer :: forall a b. (IsFramebuffer a, IsGLEnumMarshallable b) => Renderbuffer -> b -> IO a frameBufferRenderBuffer rb e = do - let enum :: GLenum - enum = getType test - unw :: GLuint - unw = unwrap rb - bind rb - glFramebufferRenderbuffer enum (toGLEnum e) GL_RENDERBUFFER (unwrap rb) - return $ wrap unw - where - test :: a - test = coerced + let enum :: GLenum + enum = getType test + unw :: GLuint + unw = unwrap rb + bind rb + glFramebufferRenderbuffer enum (toGLEnum e) GL_RENDERBUFFER (unwrap rb) + return $ wrap unw + where + test :: a + test = coerced data DrawFramebuffer = DrawFramebuffer GLuint + data FramebufferParameter = DefaultWidth | DefaultHeight instance IsWrappedPrimitive GLenum FramebufferParameter where - unwrap p = case p of - DefaultWidth -> GL_FRAMEBUFFER_DEFAULT_WIDTH - DefaultHeight -> GL_FRAMEBUFFER_DEFAULT_HEIGHT - wrap x | x == GL_FRAMEBUFFER_DEFAULT_WIDTH = DefaultWidth - | x == GL_FRAMEBUFFER_DEFAULT_HEIGHT = DefaultHeight - | otherwise = undefined + unwrap p = case p of + DefaultWidth -> GL_FRAMEBUFFER_DEFAULT_WIDTH + DefaultHeight -> GL_FRAMEBUFFER_DEFAULT_HEIGHT + wrap x + | x == GL_FRAMEBUFFER_DEFAULT_WIDTH = DefaultWidth + | x == GL_FRAMEBUFFER_DEFAULT_HEIGHT = DefaultHeight + | otherwise = undefined instance HasIntegerParam GLenum DrawFramebuffer where - parami p fb = framebufferBasicParameteri GL_DRAW_FRAMEBUFFER fb p + parami p fb = framebufferBasicParameteri GL_DRAW_FRAMEBUFFER fb p {- Has parameters of type GLuint which are acessable by the data FramebufferParameter for - the type DrawFramebuffer -} instance HasParamOfType GLuint FramebufferParameter DrawFramebuffer where - param = parami . toGLEnum + param = parami . toGLEnum instance IsGenerable DrawFramebuffer where - generate = alloca $ \ptr -> do - glGenFramebuffers 1 ptr - liftM DrawFramebuffer $ peek ptr + generate = alloca $ \ptr -> do + glGenFramebuffers 1 ptr + liftM DrawFramebuffer $ peek ptr instance IsBindable DrawFramebuffer where - bind (DrawFramebuffer fb) = glBindFramebuffer GL_DRAW_FRAMEBUFFER fb + bind (DrawFramebuffer fb) = glBindFramebuffer GL_DRAW_FRAMEBUFFER fb instance IsWrappedPrimitive GLuint DrawFramebuffer where - unwrap (DrawFramebuffer fb) = fb - wrap = DrawFramebuffer + unwrap (DrawFramebuffer fb) = fb + wrap = DrawFramebuffer instance IsFramebuffer DrawFramebuffer where - getType _ = GL_DRAW_FRAMEBUFFER + getType _ = GL_DRAW_FRAMEBUFFER diff --git a/Graphics/Glyph/GLMath.hs b/Graphics/Glyph/GLMath.hs index ac3e93a..7614cf7 100644 --- a/Graphics/Glyph/GLMath.hs +++ b/Graphics/Glyph/GLMath.hs @@ -1,44 +1,51 @@ -{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE MultiParamTypeClasses #-} + module Graphics.Glyph.GLMath where -import Graphics.Glyph.Mat4 -import qualified Graphics.Rendering.OpenGL as GL -import Graphics.Rendering.OpenGL (GLfloat,Uniform,Vertex3(..),uniform,UniformComponent) + import Data.Angle import Data.Maybe import Debug.Trace +import Graphics.Glyph.Mat4 +import Graphics.Rendering.OpenGL (GLfloat, Uniform, UniformComponent, Vertex3 (..), uniform) +import qualified Graphics.Rendering.OpenGL as GL + +data Vec2 a = Vec2 (a, a) deriving (Show, Eq) + +data Vec3 a = Vec3 (a, a, a) deriving (Show, Eq) -data Vec2 a = Vec2 (a,a) deriving (Show,Eq) -data Vec3 a = Vec3 (a,a,a) deriving (Show,Eq) -data Vec4 a = Vec4 (a,a,a,a) deriving (Show,Eq) +data Vec4 a = Vec4 (a, a, a, a) deriving (Show, Eq) instance UniformComponent a => Uniform (Vec3 a) where - uniform loc = GL.makeStateVar - (do - (Vertex3 x y z) <- - GL.get (uniform loc) - return (Vec3 (x,y,z)) ) - (\(Vec3 (x,y,z)) -> uniform loc GL.$= Vertex3 x y z) - uniformv _ = undefined + uniform loc = + GL.makeStateVar + ( do + (Vertex3 x y z) <- + GL.get (uniform loc) + return (Vec3 (x, y, z)) + ) + (\(Vec3 (x, y, z)) -> uniform loc GL.$= Vertex3 x y z) + uniformv _ = undefined instance UniformComponent a => Uniform (Vec4 a) where - uniform loc = GL.makeStateVar - (do - (GL.Vertex4 x y z w) <- - GL.get (uniform loc) - return (Vec4 (x,y,z,w)) ) - (\(Vec4 (x,y,z,w)) -> uniform loc GL.$= GL.Vertex4 x y z w) - uniformv _ = undefined + uniform loc = + GL.makeStateVar + ( do + (GL.Vertex4 x y z w) <- + GL.get (uniform loc) + return (Vec4 (x, y, z, w)) + ) + (\(Vec4 (x, y, z, w)) -> uniform loc GL.$= GL.Vertex4 x y z w) + uniformv _ = undefined class (Floating flT) => Vector flT b where - (<+>) :: b flT -> b flT -> b flT - (<->) :: b flT -> b flT -> b flT - norm :: b flT -> flT - normalize :: b flT -> b flT - vDot :: b flT -> b flT -> flT - vScale :: flT -> b flT -> b flT - vNegate :: b flT -> b flT - + (<+>) :: b flT -> b flT -> b flT + (<->) :: b flT -> b flT -> b flT + norm :: b flT -> flT + normalize :: b flT -> b flT + vDot :: b flT -> b flT -> flT + vScale :: flT -> b flT -> b flT + vNegate :: b flT -> b flT (<.>) :: (Vector a b) => b a -> b a -> a (<.>) = vDot @@ -47,168 +54,294 @@ class (Floating flT) => Vector flT b where (|||) = norm instance (Floating flT) => Vector flT Vec2 where - (<+>) (Vec2 (a,b)) (Vec2 (c,d)) = Vec2 (a+c,b+d) - (<->) (Vec2 (a,b)) (Vec2 (c,d)) = Vec2 (a-c,b-d) - vDot (Vec2 (a,b)) (Vec2 (c,d)) = a * c + b * d - vScale c (Vec2 (a,b)) = Vec2 (a*c,b*c) - norm (Vec2 (a,b)) = sqrt (a*a + b*b) - normalize vec@(Vec2 (a,b)) = - let n = norm vec in Vec2 (a/n,b/n) - vNegate (Vec2 (a,b)) = Vec2 (-a,-b) + (<+>) (Vec2 (a, b)) (Vec2 (c, d)) = Vec2 (a + c, b + d) + (<->) (Vec2 (a, b)) (Vec2 (c, d)) = Vec2 (a - c, b - d) + vDot (Vec2 (a, b)) (Vec2 (c, d)) = a * c + b * d + vScale c (Vec2 (a, b)) = Vec2 (a * c, b * c) + norm (Vec2 (a, b)) = sqrt (a * a + b * b) + normalize vec@(Vec2 (a, b)) = + let n = norm vec in Vec2 (a / n, b / n) + vNegate (Vec2 (a, b)) = Vec2 (- a, - b) instance (Floating flT) => Vector flT Vec3 where - (<+>) (Vec3 (a,b,c)) (Vec3 (d,e,f)) = Vec3 (a+d,b+e,c+f) - (<->) (Vec3 (a,b,c)) (Vec3 (d,e,f)) = Vec3 (a-d,b-e,c-f) - vDot (Vec3 (a,b,c)) (Vec3 (d,e,f)) = a * d + b * e + c * f - vScale x (Vec3 (a,b,c)) = Vec3 (a*x,b*x,c*x) - norm (Vec3 (a,b,c)) = sqrt (a*a + b*b + c*c) - normalize vec@(Vec3 (a,b,c)) = - let n = norm vec in Vec3 (a/n,b/n,c/n) - vNegate (Vec3 (a,b,c)) = Vec3 (-a,-b,-c) + (<+>) (Vec3 (a, b, c)) (Vec3 (d, e, f)) = Vec3 (a + d, b + e, c + f) + (<->) (Vec3 (a, b, c)) (Vec3 (d, e, f)) = Vec3 (a - d, b - e, c - f) + vDot (Vec3 (a, b, c)) (Vec3 (d, e, f)) = a * d + b * e + c * f + vScale x (Vec3 (a, b, c)) = Vec3 (a * x, b * x, c * x) + norm (Vec3 (a, b, c)) = sqrt (a * a + b * b + c * c) + normalize vec@(Vec3 (a, b, c)) = + let n = norm vec in Vec3 (a / n, b / n, c / n) + vNegate (Vec3 (a, b, c)) = Vec3 (- a, - b, - c) instance (Floating flT) => Vector flT Vec4 where - (<+>) (Vec4 (a,b,c,g)) (Vec4 (d,e,f,h)) = Vec4 (a+d,b+e,c+f,g+h) - (<->) (Vec4 (a,b,c,g)) (Vec4 (d,e,f,h)) = Vec4 (a-d,b-e,c-f,g-h) - vDot (Vec4 (a,b,c,g)) (Vec4 (d,e,f,h)) = a * d + b * e + c * f + g * h - vScale x (Vec4 (a,b,c,d)) = Vec4 (a*x,b*x,c*x,d*x) - norm (Vec4 (a,b,c,d)) = sqrt (a*a + b*b + c*c + d*d) - normalize vec@(Vec4 (a,b,c,d)) = - let n = norm vec in Vec4 (a/n,b/n,c/n,d/n) - vNegate (Vec4 (a,b,c,d)) = Vec4 (-a,-b,-c,-d) + (<+>) (Vec4 (a, b, c, g)) (Vec4 (d, e, f, h)) = Vec4 (a + d, b + e, c + f, g + h) + (<->) (Vec4 (a, b, c, g)) (Vec4 (d, e, f, h)) = Vec4 (a - d, b - e, c - f, g - h) + vDot (Vec4 (a, b, c, g)) (Vec4 (d, e, f, h)) = a * d + b * e + c * f + g * h + vScale x (Vec4 (a, b, c, d)) = Vec4 (a * x, b * x, c * x, d * x) + norm (Vec4 (a, b, c, d)) = sqrt (a * a + b * b + c * c + d * d) + normalize vec@(Vec4 (a, b, c, d)) = + let n = norm vec in Vec4 (a / n, b / n, c / n, d / n) + vNegate (Vec4 (a, b, c, d)) = Vec4 (- a, - b, - c, - d) cross :: (Num a) => Vec3 a -> Vec3 a -> Vec3 a -cross (Vec3 (u1,u2,u3)) (Vec3 (v1,v2,v3)) = - Vec3 ( u2*v3 - u3*v2, - u3*v1 - u1*v3, - u1*v2 - u2*v1 ) +cross (Vec3 (u1, u2, u3)) (Vec3 (v1, v2, v3)) = + Vec3 + ( u2 * v3 - u3 * v2, + u3 * v1 - u1 * v3, + u1 * v2 - u2 * v1 + ) + (×) :: (Num a) => Vec3 a -> Vec3 a -> Vec3 a (×) = cross lookAtMatrix :: Vec3 GLfloat -> Vec3 GLfloat -> Vec3 GLfloat -> Mat4 GLfloat lookAtMatrix e c u = - let f@(Vec3 (fx,fy,fz)) = normalize (c <-> e) - s@(Vec3 (sx,sy,sz)) = normalize (f × u) - u'@(Vec3 (ux,uy,uz)) = s × f in - Matrix4 (sx, ux, -fx, 0, - sy, uy, -fy, 0, - sz, uz, -fz, 0, - -(s<.>e) , -(u'<.>e), f<.>e, 1 ) + let f@(Vec3 (fx, fy, fz)) = normalize (c <-> e) + s@(Vec3 (sx, sy, sz)) = normalize (f × u) + u'@(Vec3 (ux, uy, uz)) = s × f + in Matrix4 + ( sx, + ux, + - fx, + 0, + sy, + uy, + - fy, + 0, + sz, + uz, + - fz, + 0, + - (s <.> e), + - (u' <.> e), + f <.> e, + 1 + ) orthoMatrix :: GLfloat -> GLfloat -> GLfloat -> GLfloat -> GLfloat -> GLfloat -> Mat4 GLfloat orthoMatrix top bot right left near far = - Matrix4 (2 / (right-left), 0, 0, - (right + left) / (right - left), - 0, 2 / (top-bot), 0, - (top+bot) / (top-bot), - 0, 0, -2 / (far-near), - (far+near) / (far - near), - 0, 0, 0, 1) + Matrix4 + ( 2 / (right - left), + 0, + 0, + - (right + left) / (right - left), + 0, + 2 / (top - bot), + 0, + - (top + bot) / (top - bot), + 0, + 0, + -2 / (far - near), + - (far + near) / (far - near), + 0, + 0, + 0, + 1 + ) + perspectiveMatrix :: GLfloat -> GLfloat -> GLfloat -> GLfloat -> Mat4 GLfloat {- as close to copied from glm as possible -} perspectiveMatrix fov asp zn zf = - let tanHalfFovy = tangent (Degrees fov/2) - res00 = 1 / (asp * tanHalfFovy) - res11 = 1 / tanHalfFovy - res22 = - (zf + zn) / (zf - zn) - res23 = - 1 - res32 = - (2 * zf * zn) / (zf - zn) in - trace ("res22=" ++ show res22) $ - Matrix4 (res00, 0, 0, 0, - 0, res11, 0, 0, - 0, 0, res22, res23, - 0, 0, res32, 0) + let tanHalfFovy = tangent (Degrees fov / 2) + res00 = 1 / (asp * tanHalfFovy) + res11 = 1 / tanHalfFovy + res22 = - (zf + zn) / (zf - zn) + res23 = - 1 + res32 = - (2 * zf * zn) / (zf - zn) + in trace ("res22=" ++ show res22) $ + Matrix4 + ( res00, + 0, + 0, + 0, + 0, + res11, + 0, + 0, + 0, + 0, + res22, + res23, + 0, + 0, + res32, + 0 + ) class VectorMatrix vecT matT where - vTranslate :: matT -> vecT -> matT - (-*|) :: matT -> vecT -> vecT + vTranslate :: matT -> vecT -> matT + (-*|) :: matT -> vecT -> vecT instance (Num a) => VectorMatrix (Vec3 a) (Mat3 a) where - vTranslate (Matrix3 (a00,a01,a02, - a10,a11,a12, - a20,a21,a22)) (Vec3 (a,b,c)) = - Matrix3 (a00,a01,a02+a, - a10,a11,a12+b, - a20,a21,a22+c) - - (Matrix3 (a00,a01,a02, - a10,a11,a12, - a20,a21,a22)) -*| (Vec3 (a,b,c)) = - Vec3 (a00 * a + a01 * b + a02 * c, - a10 * a + a11 * b + a12 * c, - a20 * a + a21 * b + a22 * c ) - - + vTranslate + ( Matrix3 + ( a00, + a01, + a02, + a10, + a11, + a12, + a20, + a21, + a22 + ) + ) + (Vec3 (a, b, c)) = + Matrix3 + ( a00, + a01, + a02 + a, + a10, + a11, + a12 + b, + a20, + a21, + a22 + c + ) + ( Matrix3 + ( a00, + a01, + a02, + a10, + a11, + a12, + a20, + a21, + a22 + ) + ) + -*| (Vec3 (a, b, c)) = + Vec3 + ( a00 * a + a01 * b + a02 * c, + a10 * a + a11 * b + a12 * c, + a20 * a + a21 * b + a22 * c + ) instance (Num a) => VectorMatrix (Vec4 a) (Mat4 a) where - vTranslate mat (Vec4 tmp) = translateMat4 mat tmp - mat -*| tmp = glslMatMul mat tmp + vTranslate mat (Vec4 tmp) = translateMat4 mat tmp + mat -*| tmp = glslMatMul mat tmp glslMatMul :: (Num a) => Mat4 a -> Vec4 a -> Vec4 a -glslMatMul (Matrix4 (m00,m01,m02,m03, - m10,m11,m12,m13, - m20,m21,m22,m23, - m30,m31,m32,m33)) (Vec4 (v0,v1,v2,v3)) = - Vec4 ( v0 * m00 + v1 * m10 + v2 * m20 + v3 * m30, - v0 * m01 + v1 * m11 + v2 * m21 + v3 * m31, - v0 * m02 + v1 * m12 + v2 * m22 + v3 * m32, - v0 * m03 + v1 * m13 + v2 * m23 + v3 * m33 ) +glslMatMul + ( Matrix4 + ( m00, + m01, + m02, + m03, + m10, + m11, + m12, + m13, + m20, + m21, + m22, + m23, + m30, + m31, + m32, + m33 + ) + ) + (Vec4 (v0, v1, v2, v3)) = + Vec4 + ( v0 * m00 + v1 * m10 + v2 * m20 + v3 * m30, + v0 * m01 + v1 * m11 + v2 * m21 + v3 * m31, + v0 * m02 + v1 * m12 + v2 * m22 + v3 * m32, + v0 * m03 + v1 * m13 + v2 * m23 + v3 * m33 + ) glslModelViewToNormalMatrix :: Mat4 GLfloat -> Mat3 GLfloat -glslModelViewToNormalMatrix = fromJust.inverse.transpose.trunc4 +glslModelViewToNormalMatrix = fromJust . inverse . transpose . trunc4 (==>) :: (Num a) => Mat4 a -> Vec4 a -> Mat4 a (==>) = glslMatTranslate + glslMatTranslate :: (Num a) => Mat4 a -> Vec4 a -> Mat4 a glslMatTranslate - mat@(Matrix4 (m00,m01,m02,m03, - m10,m11,m12,m13, - m20,m21,m22,m23, - m30,m31,m32,m33)) vec = - let (Vec4 (v0,v1,v2,v3)) = mat -*| vec in - Matrix4 (m00,m01,m02,m03, - m10,m11,m12,m13, - m20,m21,m22,m23, - m30+v0,m31+v1,m32+v2,m33+v3) - + mat@( Matrix4 + ( m00, + m01, + m02, + m03, + m10, + m11, + m12, + m13, + m20, + m21, + m22, + m23, + m30, + m31, + m32, + m33 + ) + ) + vec = + let (Vec4 (v0, v1, v2, v3)) = mat -*| vec + in Matrix4 + ( m00, + m01, + m02, + m03, + m10, + m11, + m12, + m13, + m20, + m21, + m22, + m23, + m30 + v0, + m31 + v1, + m32 + v2, + m33 + v3 + ) + rotationMatrix :: GLfloat -> Vec3 GLfloat -> Mat3 GLfloat -rotationMatrix ang (Vec3 (u,v,w)) = - let l = (u*u + v*v + w*w) - u2 = u*u - v2 = v*v - w2 = w*w in - Matrix3 ( - (u2 + (v2 + w2) * cos(ang)) / l, - (u * v * (1 - cos(ang)) - w * sqrt(l) * sin(ang)) / l, - (u * w * (1 - cos(ang)) + v * sqrt(l) * sin(ang)) / l, - - (u * v * (1 - cos(ang)) + w * sqrt(l) * sin(ang)) / l, - (v2 + (u2 + w2) * cos(ang)) / l, - (v * w * (1 - cos(ang)) - u * sqrt(l) * sin(ang)) / l, - - (u * w * (1 - cos(ang)) - v * sqrt(l) * sin(ang)) / l, - (v * w * (1 - cos(ang)) + u * sqrt(l) * sin(ang)) / l, - (w2 + (u2 + v2) * cos(ang)) / l +rotationMatrix ang (Vec3 (u, v, w)) = + let l = (u * u + v * v + w * w) + u2 = u * u + v2 = v * v + w2 = w * w + in Matrix3 + ( (u2 + (v2 + w2) * cos (ang)) / l, + (u * v * (1 - cos (ang)) - w * sqrt (l) * sin (ang)) / l, + (u * w * (1 - cos (ang)) + v * sqrt (l) * sin (ang)) / l, + (u * v * (1 - cos (ang)) + w * sqrt (l) * sin (ang)) / l, + (v2 + (u2 + w2) * cos (ang)) / l, + (v * w * (1 - cos (ang)) - u * sqrt (l) * sin (ang)) / l, + (u * w * (1 - cos (ang)) - v * sqrt (l) * sin (ang)) / l, + (v * w * (1 - cos (ang)) + u * sqrt (l) * sin (ang)) / l, + (w2 + (u2 + v2) * cos (ang)) / l ) zRotationMatrix :: GLfloat -> Mat3 GLfloat -zRotationMatrix ang = rotationMatrix ang (Vec3 (0,0,1)) +zRotationMatrix ang = rotationMatrix ang (Vec3 (0, 0, 1)) maybeNormalize :: (Vector f a, Eq f) => a f -> a f maybeNormalize x = if norm x == 0 then x else normalize x coordinateConvert :: Vec3 GLfloat -> Vec3 GLfloat -> Vec3 GLfloat -> Vec3 GLfloat coordinateConvert forward up' vector = - if vector == Vec3 (0,0,0) then vector else - let right = forward × up' - up = right × forward in - case (normalize forward, normalize up, normalize right, vector) of - (za,ya,xa,Vec3 (x,y,z)) -> (x `vScale` xa) <+> (y `vScale` ya) <+> (z `vScale` za) - + if vector == Vec3 (0, 0, 0) + then vector + else + let right = forward × up' + up = right × forward + in case (normalize forward, normalize up, normalize right, vector) of + (za, ya, xa, Vec3 (x, y, z)) -> (x `vScale` xa) <+> (y `vScale` ya) <+> (z `vScale` za) + rotateFrom :: Vec3 GLfloat -> Vec3 GLfloat -> Vec3 GLfloat -> Vec3 GLfloat rotateFrom vector relative newRelative = - if vector == Vec3 (0,0,0) then vector else - case (normalize relative, normalize newRelative) of - (r', n') -> - if r' == n' then vector else - let axis = r' × n' - ang = acos $ r' `vDot` n' in - rotationMatrix ang axis -*| vector - + if vector == Vec3 (0, 0, 0) + then vector + else case (normalize relative, normalize newRelative) of + (r', n') -> + if r' == n' + then vector + else + let axis = r' × n' + ang = acos $ r' `vDot` n' + in rotationMatrix ang axis -*| vector diff --git a/Graphics/Glyph/GeometryBuilder.hs b/Graphics/Glyph/GeometryBuilder.hs index 53c6681..0b87490 100644 --- a/Graphics/Glyph/GeometryBuilder.hs +++ b/Graphics/Glyph/GeometryBuilder.hs @@ -1,148 +1,156 @@ -{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE MultiParamTypeClasses #-} -module Graphics.Glyph.GeometryBuilder where - -import Data.Sequence as Seq -import Data.Maybe +{-# LANGUAGE TemplateHaskell #-} -import Graphics.Glyph.Util -import Graphics.Glyph.BufferBuilder +module Graphics.Glyph.GeometryBuilder where -import Data.ByteStringBuilder import Data.ByteString.Lazy import Data.ByteString.Lazy.Char8 as BSLC +import Data.ByteStringBuilder import Data.Foldable as Fold - +import Data.Maybe +import Data.Sequence as Seq +import Graphics.Glyph.BufferBuilder +import Graphics.Glyph.Util import Text.Printf data OutType = TriangleStrip | Triangles + instance Show OutType where - show TriangleStrip = "triangle_strip" - show Triangles = "triangle_strip" + show TriangleStrip = "triangle_strip" + show Triangles = "triangle_strip" buildSourceAsString :: GeometryBuilder a -> String buildSourceAsString = BSLC.unpack . buildSource buildSource :: GeometryBuilder a -> ByteString buildSource builder = - runBuilder $ do - putSLn "#version 150" - putSLn "#extension GL_ARB_explicit_attrib_location : enable" - putSLn "#extension GL_ARB_explicit_uniform_location : enable" - putSLn "layout(points) in ;" - - let isVertex (Vertex _ _ _ _) = True - isVertex _ = False - putSLn $ printf "layout(%s,max_vertices=%d) out ;" - (show $ maybeDefault TriangleStrip $ gOutType builder) - (Seq.length $ Seq.filter isVertex $ gList builder) - - forM_ (textureOut builder) $ putSLn.("out vec2 "++) . (++";") - forM_ (normalOut builder) $ putSLn.("out vec3 "++) . (++";") - forM_ (positionOut builder) $ putSLn.("out vec4 "++) . (++";") - - let pjMatStr = fromJust (pjMatrixUniform builder >||> Just "pjMatrix") - let mvMatStr = fromJust (mvMatrixUniform builder >||> Just "mvMatrix") - - Fold.mapM_ (putSLn.("uniform mat4 "++).(++";")) [pjMatStr, mvMatStr] - - putSLn "void main() {" - - let vertexOutF = - case positionOut builder of - Nothing -> - printf "\tgl_Position = %s * (gl_in[0].gl_Position + %s * vec4(%f,%f,%f,%f));" - pjMatStr mvMatStr - Just str -> - printf "\tgl_Position = %s * (%s = gl_in[0].gl_Position + %s * vec4(%f,%f,%f,%f));" - pjMatStr str mvMatStr - let normalOutF = case normalOut builder of - Nothing -> const3 "" - Just str -> printf "\t%s = -inverse(transpose(mat3(%s))) * vec3(%f,%f,%f);" str mvMatStr - - let textureOutF = case textureOut builder of - Nothing -> const2 "" - Just str -> printf "\t%s = vec2(%f,%f);" str - - forM_ (gList builder) $ \datum -> - case datum of - Vertex x y z w -> putSLn $ vertexOutF x y z w - Normal x y z -> putSLn $ normalOutF x y z - Texture x y -> putSLn $ textureOutF x y - EmitVertex -> putSLn "\tEmitVertex();" - EndPrimitive -> putSLn "\tEndPrimitive();" - putSLn "}" - -data GeometryDatum = - Vertex Float Float Float Float | - Texture Float Float | - Normal Float Float Float | - EmitVertex | - EndPrimitive - -data GeometryBuilder a = GeometryBuilder { - gList :: (Seq GeometryDatum), - + runBuilder $ do + putSLn "#version 150" + putSLn "#extension GL_ARB_explicit_attrib_location : enable" + putSLn "#extension GL_ARB_explicit_uniform_location : enable" + putSLn "layout(points) in ;" + + let isVertex (Vertex _ _ _ _) = True + isVertex _ = False + putSLn $ + printf + "layout(%s,max_vertices=%d) out ;" + (show $ maybeDefault TriangleStrip $ gOutType builder) + (Seq.length $ Seq.filter isVertex $ gList builder) + + forM_ (textureOut builder) $ putSLn . ("out vec2 " ++) . (++ ";") + forM_ (normalOut builder) $ putSLn . ("out vec3 " ++) . (++ ";") + forM_ (positionOut builder) $ putSLn . ("out vec4 " ++) . (++ ";") + + let pjMatStr = fromJust (pjMatrixUniform builder >||> Just "pjMatrix") + let mvMatStr = fromJust (mvMatrixUniform builder >||> Just "mvMatrix") + + Fold.mapM_ (putSLn . ("uniform mat4 " ++) . (++ ";")) [pjMatStr, mvMatStr] + + putSLn "void main() {" + + let vertexOutF = + case positionOut builder of + Nothing -> + printf + "\tgl_Position = %s * (gl_in[0].gl_Position + %s * vec4(%f,%f,%f,%f));" + pjMatStr + mvMatStr + Just str -> + printf + "\tgl_Position = %s * (%s = gl_in[0].gl_Position + %s * vec4(%f,%f,%f,%f));" + pjMatStr + str + mvMatStr + let normalOutF = case normalOut builder of + Nothing -> const3 "" + Just str -> printf "\t%s = -inverse(transpose(mat3(%s))) * vec3(%f,%f,%f);" str mvMatStr + + let textureOutF = case textureOut builder of + Nothing -> const2 "" + Just str -> printf "\t%s = vec2(%f,%f);" str + + forM_ (gList builder) $ \datum -> + case datum of + Vertex x y z w -> putSLn $ vertexOutF x y z w + Normal x y z -> putSLn $ normalOutF x y z + Texture x y -> putSLn $ textureOutF x y + EmitVertex -> putSLn "\tEmitVertex();" + EndPrimitive -> putSLn "\tEndPrimitive();" + putSLn "}" + +data GeometryDatum + = Vertex Float Float Float Float + | Texture Float Float + | Normal Float Float Float + | EmitVertex + | EndPrimitive + +data GeometryBuilder a = GeometryBuilder + { gList :: (Seq GeometryDatum), gOutType :: Maybe OutType, pjMatrixUniform :: Maybe String, mvMatrixUniform :: Maybe String, maxVerts :: Maybe Int, - textureOut :: Maybe String, normalOut :: Maybe String, positionOut :: Maybe String, gRet :: a -} + } generating :: OutType -> GeometryBuilder () -> GeometryBuilder () -generating TriangleStrip builder = builder { gOutType = Just TriangleStrip } +generating TriangleStrip builder = builder {gOutType = Just TriangleStrip} generating Triangles builder = do - let (nSeq,_) = - Fold.foldl' (\(tSeq,cnt) datum -> - case datum of + let (nSeq, _) = + Fold.foldl' + ( \(tSeq, cnt) datum -> + case datum of EmitVertex -> - if cnt == (2::Int) then (tSeq |> datum |> EndPrimitive, 0) + if cnt == (2 :: Int) + then (tSeq |> datum |> EndPrimitive, 0) else (tSeq |> datum, cnt + 1) - _ -> (tSeq |> datum,cnt) - ) (Seq.empty, 0) (gList builder) + _ -> (tSeq |> datum, cnt) + ) + (Seq.empty, 0) + (gList builder) - builder { - gOutType = Just Triangles, + builder + { gOutType = Just Triangles, gList = nSeq } projectionMatrixUniform :: String -> GeometryBuilder () -projectionMatrixUniform str = (return ()) { pjMatrixUniform = (Just str) } +projectionMatrixUniform str = (return ()) {pjMatrixUniform = (Just str)} modelViewMatrixUniform :: String -> GeometryBuilder () -modelViewMatrixUniform str = (return ()) { mvMatrixUniform = (Just str) } +modelViewMatrixUniform str = (return ()) {mvMatrixUniform = (Just str)} maxVerticies :: Int -> GeometryBuilder () -maxVerticies i = (return ()) { maxVerts = (Just i) } +maxVerticies i = (return ()) {maxVerts = (Just i)} textureOutput :: String -> GeometryBuilder () -textureOutput str = (return ()) { textureOut = (Just str) } +textureOutput str = (return ()) {textureOut = (Just str)} normalOutput :: String -> GeometryBuilder () -normalOutput str = (return ()) { normalOut = (Just str) } +normalOutput str = (return ()) {normalOut = (Just str)} positionOutput :: String -> GeometryBuilder () -positionOutput str = (return ()) { positionOut = (Just str) } +positionOutput str = (return ()) {positionOut = (Just str)} gVertex4 :: Float -> Float -> Float -> Float -> GeometryBuilder () -gVertex4 x y z w = (return ()) { gList = Seq.singleton $ Vertex x y z w } +gVertex4 x y z w = (return ()) {gList = Seq.singleton $ Vertex x y z w} gNormal3 :: Float -> Float -> Float -> GeometryBuilder () -gNormal3 x y z = (return ()) { gList = (Seq.singleton $ Normal x y z) } +gNormal3 x y z = (return ()) {gList = (Seq.singleton $ Normal x y z)} gTexture2 :: Float -> Float -> GeometryBuilder () -gTexture2 x y = (return ()) { gList = (Seq.singleton $ Texture x y) } +gTexture2 x y = (return ()) {gList = (Seq.singleton $ Texture x y)} gEmitVertex :: GeometryBuilder () -gEmitVertex = (return ()) { gList = (Seq.singleton $ EmitVertex) } +gEmitVertex = (return ()) {gList = (Seq.singleton $ EmitVertex)} gEndPrimitive :: GeometryBuilder () -gEndPrimitive = (return ()) { gList = Seq.singleton $ EndPrimitive } +gEndPrimitive = (return ()) {gList = Seq.singleton $ EndPrimitive} gVertex4E :: Float -> Float -> Float -> Float -> GeometryBuilder () gVertex4E x y z w = gVertex4 x y z w >> gEmitVertex @@ -152,38 +160,39 @@ instance Functor GeometryBuilder where instance Applicative GeometryBuilder where (<*>) afn aa = do - fn <- afn - a <- aa - return (fn a) + fn <- afn + a <- aa + return (fn a) pure = return instance Monad GeometryBuilder where - aB >> bB = GeometryBuilder - (gList aB >< gList bB) - (select gOutType gOutType) - (select pjMatrixUniform pjMatrixUniform) - (select mvMatrixUniform mvMatrixUniform) - (select maxVerts maxVerts) - (select textureOut textureOut) - (select normalOut normalOut) - (select positionOut positionOut) - (gRet bB) - where select f1 f2 = (f1 bB) >||> (f2 aB) - aB >>= func = aB >> func (gRet aB) - return = GeometryBuilder - Seq.empty - Nothing - Nothing - Nothing - Nothing - Nothing - Nothing - Nothing - + aB >> bB = + GeometryBuilder + (gList aB >< gList bB) + (select gOutType gOutType) + (select pjMatrixUniform pjMatrixUniform) + (select mvMatrixUniform mvMatrixUniform) + (select maxVerts maxVerts) + (select textureOut textureOut) + (select normalOut normalOut) + (select positionOut positionOut) + (gRet bB) + where + select f1 f2 = (f1 bB) >||> (f2 aB) + aB >>= func = aB >> func (gRet aB) + return = + GeometryBuilder + Seq.empty + Nothing + Nothing + Nothing + Nothing + Nothing + Nothing + Nothing instance IsModelBuilder Float GeometryBuilder where - plotVertex3 x y z = gVertex4E x y z 0 - plotNormal = gNormal3 - plotTexture = gTexture2 - + plotVertex3 x y z = gVertex4E x y z 0 + plotNormal = gNormal3 + plotTexture = gTexture2 diff --git a/Graphics/Glyph/GlyphObject.hs b/Graphics/Glyph/GlyphObject.hs index db7b47c..a9f5c60 100644 --- a/Graphics/Glyph/GlyphObject.hs +++ b/Graphics/Glyph/GlyphObject.hs @@ -1,10 +1,10 @@ -module Graphics.Glyph.GlyphObject ( - GlyphObject, +module Graphics.Glyph.GlyphObject + ( GlyphObject, getBufferObject, getCompiledData, getVertexAttribute, getNormalAttribute, - getColorAttribute , + getColorAttribute, getTextureAttribute, getResources, getSetupRoutine, @@ -14,39 +14,44 @@ module Graphics.Glyph.GlyphObject ( setCompiledData, setVertexAttribute, setNormalAttribute, - setColorAttribute , + setColorAttribute, setTextureAttribute, setResources, setSetupRoutine, setTeardownRoutine, setPrimitiveMode, - prepare, teardown, - Drawable, draw, newGlyphObject, + prepare, + teardown, + Drawable, + draw, + newGlyphObject, newDefaultGlyphObject, startClosure, newDefaultGlyphObjectWithClosure, - drawInstances, numInstances, setNumInstances -) where + drawInstances, + numInstances, + setNumInstances, + ) +where +import Control.Applicative +import Control.Monad +import Data.Maybe import Graphics.Glyph.BufferBuilder +import Graphics.Glyph.ExtendedGL as Ex import Graphics.Glyph.Util import Graphics.Rendering.OpenGL as GL -import Graphics.Glyph.ExtendedGL as Ex - -import Control.Monad -import Control.Applicative -import Data.Maybe class Drawable a where - -- mvMat -> pMat -> obj -> IO () - draw :: a -> IO () + -- mvMat -> pMat -> obj -> IO () + draw :: a -> IO () -data GlyphObject a = GlyphObject { - bufferObject :: BufferObject, -- buffer +data GlyphObject a = GlyphObject + { bufferObject :: BufferObject, -- buffer compiledData :: (CompiledBuild GLfloat), -- compiled data vertexAttribute :: AttribLocation, -- vertex attribute normalAttribute :: (Maybe AttribLocation), -- normal attrib - colorAttribute :: (Maybe AttribLocation), -- color attrib + colorAttribute :: (Maybe AttribLocation), -- color attrib textureAttribute :: (Maybe AttribLocation), -- texture attrib resources :: a, -- Resources setupRoutine :: (Maybe (GlyphObject a -> IO ())), -- Setup @@ -54,7 +59,7 @@ data GlyphObject a = GlyphObject { teardownRoutine :: (Maybe (GlyphObject a -> IO ())), -- Tear down primitiveMode :: ExPrimitiveMode, numInstances :: Int -} + } getBufferObject :: GlyphObject a -> BufferObject getBufferObject = bufferObject @@ -68,8 +73,8 @@ getVertexAttribute = vertexAttribute getNormalAttribute :: GlyphObject a -> (Maybe AttribLocation) getNormalAttribute = normalAttribute -getColorAttribute :: GlyphObject a -> (Maybe AttribLocation) -getColorAttribute = colorAttribute +getColorAttribute :: GlyphObject a -> (Maybe AttribLocation) +getColorAttribute = colorAttribute getTextureAttribute :: GlyphObject a -> (Maybe AttribLocation) getTextureAttribute = textureAttribute @@ -122,91 +127,97 @@ setPrimitiveMode o a = o {primitiveMode = a} setNumInstances :: GlyphObject a -> Int -> GlyphObject a setNumInstances o a = o {numInstances = a} - -newGlyphObject :: BuilderM GLfloat x -> - AttribLocation -> - Maybe AttribLocation -> - Maybe AttribLocation -> - Maybe AttribLocation -> - a -> - Maybe (GlyphObject a -> IO ()) -> - Maybe (GlyphObject a -> IO ()) -> - ExPrimitiveMode -> - IO (GlyphObject a) - +newGlyphObject :: + BuilderM GLfloat x -> + AttribLocation -> + Maybe AttribLocation -> + Maybe AttribLocation -> + Maybe AttribLocation -> + a -> + Maybe (GlyphObject a -> IO ()) -> + Maybe (GlyphObject a -> IO ()) -> + ExPrimitiveMode -> + IO (GlyphObject a) newGlyphObject builder vertAttr normAttr colorAttr textureAttr res setup tear mode = do - compiled <- compilingBuilder builder - buffer <- createBufferObject ArrayBuffer compiled - return $ GlyphObject buffer compiled vertAttr normAttr colorAttr textureAttr res setup Nothing tear mode 1 + compiled <- compilingBuilder builder + buffer <- createBufferObject ArrayBuffer compiled + return $ GlyphObject buffer compiled vertAttr normAttr colorAttr textureAttr res setup Nothing tear mode 1 -prepare :: GlyphObject a -> (GlyphObject a -> IO()) -> GlyphObject a +prepare :: GlyphObject a -> (GlyphObject a -> IO ()) -> GlyphObject a prepare a b = setSetupRoutine2 a (Just b) -startClosure :: GlyphObject a -> (GlyphObject a -> IO()) -> GlyphObject a +startClosure :: GlyphObject a -> (GlyphObject a -> IO ()) -> GlyphObject a startClosure a b = setSetupRoutine a (Just b) -teardown :: GlyphObject a -> (GlyphObject a -> IO()) -> GlyphObject a +teardown :: GlyphObject a -> (GlyphObject a -> IO ()) -> GlyphObject a teardown a b = setTeardownRoutine a (Just b) instance Drawable (GlyphObject a) where - draw = drawInstances <..> numInstances + draw = drawInstances <..> numInstances drawInstances :: Int -> GlyphObject a -> IO () drawInstances n obj@(GlyphObject bo co vAttr nAttr cAttr tAttr _ setup1 setup2 tearDown p _) = do - {- Setup whatever we need for the object to draw itself -} - maybe (return ()) (Prelude.$obj) setup1 - maybe (return ()) (Prelude.$obj) setup2 - - {- Get the array descriptors for the possible - - parts -} - let vad = vertexArrayDescriptor co - let nad = normalArrayDescriptor co - let cad = colorArrayDescriptor co - let tad = textureArrayDescriptor co - - bindBuffer ArrayBuffer $= Just bo - let enabled = catMaybes $ - map liftMaybe [(Just vAttr,Just vad), (nAttr, nad), (cAttr,cad), (tAttr,tad)] - - forM_ enabled $ \(attr, ad) -> do - vertexAttribPointer attr $= (ToFloat, ad) - vertexAttribArray attr $= Enabled - - let p' = case p of - Ex.Points -> GL.Points - Ex.Lines -> GL.Lines - Ex.Triangles -> GL.Triangles - Ex.Patches -> GL.Patches - - drawArraysInstanced p' 0 (bufferLength co) $ fromIntegral n - - forM_ enabled $ \(attr, _) -> do - vertexAttribArray attr $= Disabled - - {- Tear down whatever the object needs -} - maybe (return ()) (Prelude.$ obj) tearDown - where liftMaybe (Just a, Just b) = Just (a,b) - liftMaybe _ = Nothing + {- Setup whatever we need for the object to draw itself -} + maybe (return ()) (Prelude.$ obj) setup1 + maybe (return ()) (Prelude.$ obj) setup2 + + {- Get the array descriptors for the possible + - parts -} + let vad = vertexArrayDescriptor co + let nad = normalArrayDescriptor co + let cad = colorArrayDescriptor co + let tad = textureArrayDescriptor co + + bindBuffer ArrayBuffer $= Just bo + let enabled = + catMaybes $ + map liftMaybe [(Just vAttr, Just vad), (nAttr, nad), (cAttr, cad), (tAttr, tad)] + + forM_ enabled $ \(attr, ad) -> do + vertexAttribPointer attr $= (ToFloat, ad) + vertexAttribArray attr $= Enabled + + let p' = case p of + Ex.Points -> GL.Points + Ex.Lines -> GL.Lines + Ex.Triangles -> GL.Triangles + Ex.Patches -> GL.Patches + + drawArraysInstanced p' 0 (bufferLength co) $ fromIntegral n + + forM_ enabled $ \(attr, _) -> do + vertexAttribArray attr $= Disabled + + {- Tear down whatever the object needs -} + maybe (return ()) (Prelude.$ obj) tearDown + where + liftMaybe (Just a, Just b) = Just (a, b) + liftMaybe _ = Nothing instance (Show a) => Show (GlyphObject a) where - show (GlyphObject _ co vAttr nAttr cAttr tAttr res _ _ _ p n) = - "[GlyphObject compiled=" ++! co ++ " vertAttr=" ++! vAttr ++ - " normalAttr="++!nAttr++" colorAttr="++!cAttr++" textureAttr="++!tAttr++" res="++!res++" PrimitiveMode="++!p++" instances="++!n++"]" + show (GlyphObject _ co vAttr nAttr cAttr tAttr res _ _ _ p n) = + "[GlyphObject compiled=" ++! co ++ " vertAttr=" ++! vAttr + ++ " normalAttr=" ++! nAttr + ++ " colorAttr=" ++! cAttr + ++ " textureAttr=" ++! tAttr + ++ " res=" ++! res + ++ " PrimitiveMode=" ++! p + ++ " instances=" ++! n + ++ "]" newDefaultGlyphObject :: BuilderM GLfloat x -> a -> IO (GlyphObject a) newDefaultGlyphObject builder resources = - newGlyphObject builder - (AttribLocation 0) -- vertex - (Just $ AttribLocation 1) -- normal - (Just $ AttribLocation 2) -- color - (Just $ AttribLocation 3) -- texture - resources - Nothing -- setup - Nothing -- teardown - Ex.Triangles -- primitive + newGlyphObject + builder + (AttribLocation 0) -- vertex + (Just $ AttribLocation 1) -- normal + (Just $ AttribLocation 2) -- color + (Just $ AttribLocation 3) -- texture + resources + Nothing -- setup + Nothing -- teardown + Ex.Triangles -- primitive newDefaultGlyphObjectWithClosure :: BuilderM GLfloat x -> a -> (GlyphObject a -> IO ()) -> IO (GlyphObject a) newDefaultGlyphObjectWithClosure builder res func = - liftM (flip startClosure func) $ newDefaultGlyphObject builder res - - + liftM (flip startClosure func) $ newDefaultGlyphObject builder res diff --git a/Graphics/Glyph/ObjLoader.hs b/Graphics/Glyph/ObjLoader.hs index b392a26..9acaf48 100644 --- a/Graphics/Glyph/ObjLoader.hs +++ b/Graphics/Glyph/ObjLoader.hs @@ -1,37 +1,36 @@ module Graphics.Glyph.ObjLoader where -import Graphics.Glyph.BufferBuilder -import Graphics.Glyph.Util -import Debug.Trace - -import Data.List.Split import Control.Monad -import Data.Either import Data.Array -import System.IO -import qualified Data.Map as M - import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy.Char8 as C +import Data.Either +import Data.List.Split +import qualified Data.Map as M +import Debug.Trace +import Graphics.Glyph.BufferBuilder +import Graphics.Glyph.Util +import System.IO data ObjectFile a = ObjectFile [ObjectStatement a] -data ObjectStatement a = - Nop | - VertexStatement (a,a,a) | - TextureStatement (a,a) | - VertexNormalStatement (a,a,a) | - UseMaterialStatement (String) | - MaterialLibraryStatement String | - FaceStatement [(Int,Int,Int)] deriving Show +data ObjectStatement a + = Nop + | VertexStatement (a, a, a) + | TextureStatement (a, a) + | VertexNormalStatement (a, a, a) + | UseMaterialStatement (String) + | MaterialLibraryStatement String + | FaceStatement [(Int, Int, Int)] + deriving (Show) foldl2 :: a -> [b] -> (a -> b -> a) -> a -foldl2 a b c = foldl c a b +foldl2 a b c = foldl c a b isNop :: ObjectStatement a -> Bool -isNop x = case x of - Nop -> True - _ -> False +isNop x = case x of + Nop -> True + _ -> False isVertex :: ObjectStatement a -> Bool isVertex (VertexStatement _) = True @@ -47,77 +46,80 @@ isTexture _ = False basicBuildObject :: (Floating b, IsModelBuilder b a) => ObjectFile b -> a () basicBuildObject (ObjectFile list) = - let fromList lst = listArray (0,length lst-1) lst in - - -- Set up the lists as arrays for fast access - let vertexList = fromList $ map (\stmt -> - case stmt of - (VertexStatement v) -> v - _ -> (0,0,0)) (filter isVertex list) in - - let normalList = fromList $ map (\stmt -> - case stmt of - (VertexNormalStatement v) -> v - _ -> (0,0,0)) (filter isNormal list) in - - let textureList = fromList $ map (\stmt -> + let fromList lst = listArray (0, length lst -1) lst + in -- Set up the lists as arrays for fast access + let vertexList = + fromList $ + map + ( \stmt -> + case stmt of + (VertexStatement v) -> v + _ -> (0, 0, 0) + ) + (filter isVertex list) + in let normalList = + fromList $ + map + ( \stmt -> case stmt of - (TextureStatement v) -> v - _ -> (0,0)) (filter isTexture list) in - - forM_ list $ \stmt -> - case stmt of - (FaceStatement arr) -> - forM_ arr $ \(a,b,c) -> do - when (c >= 0) (uncurry3 plotNormal $ normalList ! (c-1)) - when (b >= 0) (uncurry plotTexture $ textureList ! (b-1)) - when (a >= 0) (uncurry3 plotVertex3 $ vertexList ! (a-1)) - _ -> return () - + (VertexNormalStatement v) -> v + _ -> (0, 0, 0) + ) + (filter isNormal list) + in let textureList = + fromList $ + map + ( \stmt -> + case stmt of + (TextureStatement v) -> v + _ -> (0, 0) + ) + (filter isTexture list) + in forM_ list $ \stmt -> + case stmt of + (FaceStatement arr) -> + forM_ arr $ \(a, b, c) -> do + when (c >= 0) (uncurry3 plotNormal $ normalList ! (c -1)) + when (b >= 0) (uncurry plotTexture $ textureList ! (b -1)) + when (a >= 0) (uncurry3 plotVertex3 $ vertexList ! (a -1)) + _ -> return () loadObjFromBytestring :: (Read b) => L.ByteString -> ([String], ObjectFile b) loadObjFromBytestring _contents = - let contents::[L.ByteString] ; contents = C.split '\n' _contents in - let mys2n str = case str of - "" -> -1 - _ -> read str in - - let s2t s = case splitOn "/" s of - [a,b,c] -> Just (mapT3 mys2n (a,b,c)) - [a,b] -> Just (mapT3 mys2n (a,b,"")) - [a] -> Just (mapT3 mys2n (a,"","")) - _ -> Nothing in - - let compiled = - map (\(num,line) -> case words $ C.unpack line of - - [] -> Right Nop -- This is an empty line - (('#':_):_) -> Right Nop -- This is a comment, so use a 'nop' - ("o":_) -> Right Nop -- Not really of use - - ["v",x,y,z] -> Right $ VertexStatement ( (read x), (read y), (read z)) - ["vt",x,y] -> Right $ TextureStatement ( (read x), (read y)) - ["vn",x,y,z] -> Right $ VertexNormalStatement ( (read x), (read y), (read z)) - ["usemtl", mtl] -> Right $ UseMaterialStatement mtl - ["mtllib", lib] -> Right $ MaterialLibraryStatement lib - - ("f":_tail) -> case mapM s2t _tail of - Just lst -> Right $ FaceStatement lst - _ -> Left $ foldl (++) "" ["Syntax error in face value on line ", show num, " `", C.unpack line, "'" ] - - _ -> Left $ foldl (++) "" ["Unrecognized Sequence on line ", show num, " `", C.unpack line, "'" ] - - ) (zip [(1::Int)..] contents) in - - ( lefts compiled, ObjectFile (filter (not.isNop) $ rights compiled) ) - + let contents :: [L.ByteString]; contents = C.split '\n' _contents + in let mys2n str = case str of + "" -> -1 + _ -> read str + in let s2t s = case splitOn "/" s of + [a, b, c] -> Just (mapT3 mys2n (a, b, c)) + [a, b] -> Just (mapT3 mys2n (a, b, "")) + [a] -> Just (mapT3 mys2n (a, "", "")) + _ -> Nothing + in let compiled = + map + ( \(num, line) -> case words $ C.unpack line of + [] -> Right Nop -- This is an empty line + (('#' : _) : _) -> Right Nop -- This is a comment, so use a 'nop' + ("o" : _) -> Right Nop -- Not really of use + ["v", x, y, z] -> Right $ VertexStatement ((read x), (read y), (read z)) + ["vt", x, y] -> Right $ TextureStatement ((read x), (read y)) + ["vn", x, y, z] -> Right $ VertexNormalStatement ((read x), (read y), (read z)) + ["usemtl", mtl] -> Right $ UseMaterialStatement mtl + ["mtllib", lib] -> Right $ MaterialLibraryStatement lib + ("f" : _tail) -> case mapM s2t _tail of + Just lst -> Right $ FaceStatement lst + _ -> Left $ foldl (++) "" ["Syntax error in face value on line ", show num, " `", C.unpack line, "'"] + _ -> Left $ foldl (++) "" ["Unrecognized Sequence on line ", show num, " `", C.unpack line, "'"] + ) + (zip [(1 :: Int) ..] contents) + in (lefts compiled, ObjectFile (filter (not . isNop) $ rights compiled)) loadObjFromHandle :: (Read b) => Handle -> IO ([String], ObjectFile b) loadObjFromHandle = loadObjFromHandleWithFilter id loadObjFromHandleWithFilter :: (Read b) => (L.ByteString -> L.ByteString) -> Handle -> IO ([String], ObjectFile b) loadObjFromHandleWithFilter _filter handle = - liftM (loadObjFromBytestring . _filter) (L.hGetContents handle) + liftM (loadObjFromBytestring . _filter) (L.hGetContents handle) loadObjFile :: (Read b) => FilePath -> IO ([String], ObjectFile b) loadObjFile = loadObjFileWithFilter id diff --git a/Graphics/Glyph/Shaders.hs b/Graphics/Glyph/Shaders.hs index 6b3ddde..b87129c 100644 --- a/Graphics/Glyph/Shaders.hs +++ b/Graphics/Glyph/Shaders.hs @@ -1,12 +1,12 @@ module Graphics.Glyph.Shaders where -import Graphics.Rendering.OpenGL +import Control.Monad import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as BSL -import Control.Monad -import Data.Maybe import Data.List as List +import Data.Maybe import Graphics.Glyph.Util +import Graphics.Rendering.OpenGL {- Load a shader from a file giving the type of the shader - to load. @@ -15,41 +15,41 @@ import Graphics.Glyph.Util - and Just if the shader did compile -} class IsShaderSource a where - loadShader :: ShaderType -> a -> IO (String, Maybe Shader) + loadShader :: ShaderType -> a -> IO (String, Maybe Shader) instance IsShaderSource FilePath where - loadShader typ path = loadShaderBS path typ =<< BS.readFile path + loadShader typ path = loadShaderBS path typ =<< BS.readFile path instance IsShaderSource BS.ByteString where - loadShader = loadShaderBS "Inlined" + loadShader = loadShaderBS "Inlined" instance IsShaderSource BSL.ByteString where - loadShader typ = loadShader typ . toStrict - where toStrict = BS.concat . BSL.toChunks + loadShader typ = loadShader typ . toStrict + where + toStrict = BS.concat . BSL.toChunks noShader :: Maybe String noShader = Nothing loadShaderBS :: String -> ShaderType -> BS.ByteString -> IO (String, Maybe Shader) loadShaderBS ctx typ src = do - shader <- createShader typ - shaderSourceBS shader $= src - compileShader shader - - ok <- get (compileStatus shader) - infoLog <- get (shaderInfoLog shader) + shader <- createShader typ + shaderSourceBS shader $= src + compileShader shader - unless ok $ - deleteObjectNames [shader] + ok <- get (compileStatus shader) + infoLog <- get (shaderInfoLog shader) - if not ok then - return ( unlines $ map ((ctx ++ " " ++ show typ ++ ": ")++) $ lines infoLog, Nothing ) - else return ( infoLog, Just shader ); + unless ok $ + deleteObjectNames [shader] + if not ok + then return (unlines $ map ((ctx ++ " " ++ show typ ++ ": ") ++) $ lines infoLog, Nothing) + else return (infoLog, Just shader) {- Load multiple shaders -} -loadShaders :: (IsShaderSource a) => [(ShaderType,a)] -> IO [(String, Maybe Shader)] -loadShaders = mapM ( uncurry loadShader ) +loadShaders :: (IsShaderSource a) => [(ShaderType, a)] -> IO [(String, Maybe Shader)] +loadShaders = mapM (uncurry loadShader) {- Return the sucessfully complied shaders - as a new array of working shaders -} @@ -59,60 +59,72 @@ workingShaders = mapMaybe snd {- Create a program from a list of working shaders -} createShaderProgram :: [Shader] -> IO (String, Maybe Program) createShaderProgram shaders = do - p <- createProgram - mapM_ (attachShader p) shaders - linkProgram p + p <- createProgram + mapM_ (attachShader p) shaders + linkProgram p - ok <- get $ linkStatus p - info <- get $ programInfoLog p + ok <- get $ linkStatus p + info <- get $ programInfoLog p - unless ok $ - deleteObjectNames [p] + unless ok $ + deleteObjectNames [p] - return ( info, not ok ? Nothing $ Just p ) + return (info, not ok ? Nothing $ Just p) {- Creates a shader program, but will only build the program if all the - shaders compiled correctly -} -createShaderProgramSafe :: [(String,Maybe Shader)] -> IO (String, Maybe Program) -createShaderProgramSafe shaders = - not (List.all (isJust.snd) shaders) ? - return (concatMap fst shaders, Nothing) $ - createShaderProgram $ workingShaders shaders - - -getUniformLocationsSafe :: Program -> [String] -> IO [ Maybe UniformLocation ] +createShaderProgramSafe :: [(String, Maybe Shader)] -> IO (String, Maybe Program) +createShaderProgramSafe shaders = + not (List.all (isJust . snd) shaders) + ? return (concatMap fst shaders, Nothing) + $ createShaderProgram $ workingShaders shaders + +getUniformLocationsSafe :: Program -> [String] -> IO [Maybe UniformLocation] getUniformLocationsSafe prog uniforms = - forM uniforms $ \uniform -> do - tmp <- get $ uniformLocation prog uniform - case tmp of - UniformLocation (-1) -> return $ Nothing - _ -> return $Just tmp + forM uniforms $ \uniform -> do + tmp <- get $ uniformLocation prog uniform + case tmp of + UniformLocation (-1) -> return $ Nothing + _ -> return $ Just tmp loadProgramFullSafe :: - (IsShaderSource tc, - IsShaderSource te, - IsShaderSource g, - IsShaderSource v, - IsShaderSource f) => Maybe (tc,te) -> Maybe g -> v -> f -> IO (Maybe Program) + ( IsShaderSource tc, + IsShaderSource te, + IsShaderSource g, + IsShaderSource v, + IsShaderSource f + ) => + Maybe (tc, te) -> + Maybe g -> + v -> + f -> + IO (Maybe Program) loadProgramFullSafe tess geometry vert frag = do - let (ts1,ts2) = distribMaybe tess - shaders <- sequence $ catMaybes [ - Just $ loadShader VertexShader vert, - Just $ loadShader FragmentShader frag, - liftM (loadShader GeometryShader) geometry, - liftM (loadShader TessControlShader) ts1, - liftM (loadShader TessEvaluationShader) ts2] - (linklog,maybeProg) <- createShaderProgramSafe shaders - if isNothing maybeProg then do - putStrLn "Failed to link program" - putStrLn linklog - return Nothing - else return maybeProg - + let (ts1, ts2) = distribMaybe tess + shaders <- + sequence $ + catMaybes + [ Just $ loadShader VertexShader vert, + Just $ loadShader FragmentShader frag, + liftM (loadShader GeometryShader) geometry, + liftM (loadShader TessControlShader) ts1, + liftM (loadShader TessEvaluationShader) ts2 + ] + (linklog, maybeProg) <- createShaderProgramSafe shaders + if isNothing maybeProg + then do + putStrLn "Failed to link program" + putStrLn linklog + return Nothing + else return maybeProg loadProgramSafe :: - (IsShaderSource a, - IsShaderSource b, - IsShaderSource c) => - a -> b -> Maybe c -> IO (Maybe Program) -loadProgramSafe vert frag geom = loadProgramFullSafe (Nothing::Maybe(String,String)) geom vert frag + ( IsShaderSource a, + IsShaderSource b, + IsShaderSource c + ) => + a -> + b -> + Maybe c -> + IO (Maybe Program) +loadProgramSafe vert frag geom = loadProgramFullSafe (Nothing :: Maybe (String, String)) geom vert frag diff --git a/Graphics/Glyph/Textures.hs b/Graphics/Glyph/Textures.hs index ec3e12f..538c87a 100644 --- a/Graphics/Glyph/Textures.hs +++ b/Graphics/Glyph/Textures.hs @@ -6,33 +6,40 @@ import Data.Word import Graphics.GL.Compatibility30 import Graphics.Rendering.OpenGL -data Pixels = - PixelsRGB (Int,Int) (StorableArray Int Word8) | - PixelsRGBA (Int,Int) (StorableArray Int Word8) +data Pixels + = PixelsRGB (Int, Int) (StorableArray Int Word8) + | PixelsRGBA (Int, Int) (StorableArray Int Word8) pixelsArray :: Pixels -> StorableArray Int Word8 -pixelsArray (PixelsRGB _ a) = a +pixelsArray (PixelsRGB _ a) = a pixelsArray (PixelsRGBA _ a) = a + -- construct a new 2d array of pixels makePixelsRGB :: (Int, Int) -> IO Pixels -makePixelsRGB a@(w,h) = liftM (PixelsRGB a) (newArray_ (0,w*h-1)) +makePixelsRGB a@(w, h) = liftM (PixelsRGB a) (newArray_ (0, w * h -1)) -- convert a list of rgb values to an array -newPixelsFromListRGB :: (Int, Int) -> [(Word8,Word8,Word8)] -> IO Pixels -newPixelsFromListRGB a@(w,h) lst = liftM (PixelsRGB a) $ (newListArray (0,w*h*3) . - concatMap (\(x,y,z)->[x,y,z])) lst - -newPixelsFromListRGBA :: (Int, Int) -> [(Word8,Word8,Word8,Word8)] -> IO Pixels -newPixelsFromListRGBA a@(w,h) lst = liftM (PixelsRGBA a) $ newListArray (0,w*h*4) - (concatMap (\(x,y,z,q)->[x,y,z,q]) lst) +newPixelsFromListRGB :: (Int, Int) -> [(Word8, Word8, Word8)] -> IO Pixels +newPixelsFromListRGB a@(w, h) lst = + liftM (PixelsRGB a) $ + ( newListArray (0, w * h * 3) + . concatMap (\(x, y, z) -> [x, y, z]) + ) + lst + +newPixelsFromListRGBA :: (Int, Int) -> [(Word8, Word8, Word8, Word8)] -> IO Pixels +newPixelsFromListRGBA a@(w, h) lst = + liftM (PixelsRGBA a) $ + newListArray + (0, w * h * 4) + (concatMap (\(x, y, z, q) -> [x, y, z, q]) lst) attachPixelsToTexture :: Pixels -> TextureObject -> IO () attachPixelsToTexture pixels tex = - withStorableArray (pixelsArray pixels) $ \ptr -> do - textureBinding Texture2D $= Just tex - case pixels of - PixelsRGB (w,h) _ -> glTexImage2D GL_TEXTURE_2D 0 3 (f w) (f h) 0 GL_RGB GL_UNSIGNED_BYTE ptr - PixelsRGBA (w,h) _ -> glTexImage2D GL_TEXTURE_2D 0 4 (f w) (f h) 0 GL_RGBA GL_UNSIGNED_BYTE ptr - where f = fromIntegral - - + withStorableArray (pixelsArray pixels) $ \ptr -> do + textureBinding Texture2D $= Just tex + case pixels of + PixelsRGB (w, h) _ -> glTexImage2D GL_TEXTURE_2D 0 3 (f w) (f h) 0 GL_RGB GL_UNSIGNED_BYTE ptr + PixelsRGBA (w, h) _ -> glTexImage2D GL_TEXTURE_2D 0 4 (f w) (f h) 0 GL_RGBA GL_UNSIGNED_BYTE ptr + where + f = fromIntegral diff --git a/Graphics/Glyph/Util.hs b/Graphics/Glyph/Util.hs index 90640a4..79fd5c6 100644 --- a/Graphics/Glyph/Util.hs +++ b/Graphics/Glyph/Util.hs @@ -3,21 +3,17 @@ module Graphics.Glyph.Util where +import Control.Exception +import Control.Monad import Data.Angle -import Graphics.Rendering.OpenGL -import Data.Maybe +import Data.Array.MArray import Data.Char import Data.Either - -import Control.Exception -import Control.Monad - import Data.Foldable as Fold - -import Foreign.Ptr +import Data.Maybe import Foreign.Marshal.Alloc - -import Data.Array.MArray +import Foreign.Ptr +import Graphics.Rendering.OpenGL if' :: Bool -> a -> a -> a if' True a _ = a @@ -30,31 +26,31 @@ flipIf :: a -> a -> Bool -> a flipIf a b c = if c then a else b int :: (Integral a, Num b) => a -> b -int = fromIntegral +int = fromIntegral -uncurry7 :: (a -> b -> c -> d -> e -> f -> g -> h) -> (a,b,c,d,e,f,g) -> h -uncurry7 func (a,b,c,d,e,f,g) = func a b c d e f g +uncurry7 :: (a -> b -> c -> d -> e -> f -> g -> h) -> (a, b, c, d, e, f, g) -> h +uncurry7 func (a, b, c, d, e, f, g) = func a b c d e f g -uncurry6 :: (a -> b -> c -> d -> e -> f -> g) -> (a,b,c,d,e,f) -> g -uncurry6 func (a,b,c,d,e,f) = func a b c d e f +uncurry6 :: (a -> b -> c -> d -> e -> f -> g) -> (a, b, c, d, e, f) -> g +uncurry6 func (a, b, c, d, e, f) = func a b c d e f -uncurry5 :: (a -> b -> c -> d -> e -> f) -> (a,b,c,d,e) -> f -uncurry5 func (a,b,c,d,e) = func a b c d e +uncurry5 :: (a -> b -> c -> d -> e -> f) -> (a, b, c, d, e) -> f +uncurry5 func (a, b, c, d, e) = func a b c d e -uncurry4 :: (a -> b -> c -> d -> e) -> (a,b,c,d) -> e -uncurry4 func (a,b,c,d) = func a b c d +uncurry4 :: (a -> b -> c -> d -> e) -> (a, b, c, d) -> e +uncurry4 func (a, b, c, d) = func a b c d -uncurry3 :: (a -> b -> c -> e) -> (a,b,c) -> e -uncurry3 func (a,b,c) = func a b c +uncurry3 :: (a -> b -> c -> e) -> (a, b, c) -> e +uncurry3 func (a, b, c) = func a b c const2 :: a -> b -> c -> a -const2 = const.const +const2 = const . const const3 :: a -> b -> c -> d -> a -const3 = const2.const +const3 = const2 . const const4 :: a -> b -> c -> d -> e -> a -const4 = const3.const +const4 = const3 . const gsin :: (Floating a) => a -> a gsin = sine . Degrees @@ -63,76 +59,76 @@ gcos :: (Floating a) => a -> a gcos = cosine . Degrees toEuclidian :: (Floating a) => (a, a, a) -> (a, a, a) -toEuclidian (r, th, ph) = ( - -r * gsin th * gcos ph, - r * gsin ph, - r * gcos th * gcos ph - ) +toEuclidian (r, th, ph) = + ( - r * gsin th * gcos ph, + r * gsin ph, + r * gcos th * gcos ph + ) -mapT2 :: (a -> b) -> (a,a) -> (b,b) +mapT2 :: (a -> b) -> (a, a) -> (b, b) mapT2 f (a, b) = (f a, f b) -mapT3 :: (a -> b) -> (a,a,a) -> (b,b,b) +mapT3 :: (a -> b) -> (a, a, a) -> (b, b, b) mapT3 f (a, b, c) = (f a, f b, f c) -mapT4 :: (a -> b) -> (a,a,a,a) -> (b,b,b,b) +mapT4 :: (a -> b) -> (a, a, a, a) -> (b, b, b, b) mapT4 f (a, b, c, d) = (f a, f b, f c, f d) -mapT5 :: (a -> b) -> (a,a,a,a,a) -> (b,b,b,b,b) +mapT5 :: (a -> b) -> (a, a, a, a, a) -> (b, b, b, b, b) mapT5 f (a, b, c, d, e) = (f a, f b, f c, f d, f e) -mapT6 :: (a -> b) -> (a,a,a,a,a,a) -> (b,b,b,b,b,b) +mapT6 :: (a -> b) -> (a, a, a, a, a, a) -> (b, b, b, b, b, b) mapT6 f (a, b, c, d, e, _f) = (f a, f b, f c, f d, f e, f _f) -mapT7 :: (a -> b) -> (a,a,a,a,a,a,a) -> (b,b,b,b,b,b,b) +mapT7 :: (a -> b) -> (a, a, a, a, a, a, a) -> (b, b, b, b, b, b, b) mapT7 f (a, b, c, d, e, _f, g) = (f a, f b, f c, f d, f e, f _f, f g) -foldT2 :: (a -> b -> a) -> a -> (b,b) -> a -foldT2 f ini (x,y) = ini `f` x `f` y +foldT2 :: (a -> b -> a) -> a -> (b, b) -> a +foldT2 f ini (x, y) = ini `f` x `f` y -foldT3 :: (a -> b -> a) -> a -> (b,b,b) -> a -foldT3 f ini (x,y,z) = ini `f` x `f` y `f` z +foldT3 :: (a -> b -> a) -> a -> (b, b, b) -> a +foldT3 f ini (x, y, z) = ini `f` x `f` y `f` z -foldT4 :: (a -> b -> a) -> a -> (b,b,b,b) -> a -foldT4 f ini (x,y,z,w) = ini `f` x `f` y `f` z `f` w +foldT4 :: (a -> b -> a) -> a -> (b, b, b, b) -> a +foldT4 f ini (x, y, z, w) = ini `f` x `f` y `f` z `f` w -foldT5 :: (a -> b -> a) -> a -> (b,b,b,b,b) -> a -foldT5 f ini (x,y,z,w,v) = ini `f` x `f` y `f` z `f` w `f` v +foldT5 :: (a -> b -> a) -> a -> (b, b, b, b, b) -> a +foldT5 f ini (x, y, z, w, v) = ini `f` x `f` y `f` z `f` w `f` v -tup2Len :: (Real a,Floating b) => (a,a) -> b -tup2Len = sqrt . foldT2 (+) 0 . mapT2 ((**2).toFloating) +tup2Len :: (Real a, Floating b) => (a, a) -> b +tup2Len = sqrt . foldT2 (+) 0 . mapT2 ((** 2) . toFloating) -tup3Len :: (Real a,Floating b) => (a,a,a) -> b -tup3Len = sqrt . foldT3 (+) 0 . mapT3 ((**2).toFloating) +tup3Len :: (Real a, Floating b) => (a, a, a) -> b +tup3Len = sqrt . foldT3 (+) 0 . mapT3 ((** 2) . toFloating) -tup4Len :: (Real a,Floating b) => (a,a,a,a) -> b -tup4Len = sqrt . foldT4 (+) 0 . mapT4 ((**2).toFloating) +tup4Len :: (Real a, Floating b) => (a, a, a, a) -> b +tup4Len = sqrt . foldT4 (+) 0 . mapT4 ((** 2) . toFloating) -tup5Len :: (Real a,Floating b) => (a,a,a,a,a) -> b -tup5Len = sqrt . foldT5 (+) 0 . mapT5 ((**2).toFloating) +tup5Len :: (Real a, Floating b) => (a, a, a, a, a) -> b +tup5Len = sqrt . foldT5 (+) 0 . mapT5 ((** 2) . toFloating) -expand3 :: a -> (a,a,a) -expand3 t = (t,t,t) +expand3 :: a -> (a, a, a) +expand3 t = (t, t, t) -expand4 :: a -> (a,a,a,a) -expand4 t = (t,t,t,t) +expand4 :: a -> (a, a, a, a) +expand4 t = (t, t, t, t) -expand5 :: a -> (a,a,a,a,a) -expand5 t = (t,t,t,t,t) +expand5 :: a -> (a, a, a, a, a) +expand5 t = (t, t, t, t, t) -expand6 :: a -> (a,a,a,a,a) -expand6 t = (t,t,t,t,t) +expand6 :: a -> (a, a, a, a, a) +expand6 t = (t, t, t, t, t) -zipWithT2 :: (a -> b -> c) -> (a,a) -> (b,b) -> (c,c) +zipWithT2 :: (a -> b -> c) -> (a, a) -> (b, b) -> (c, c) zipWithT2 fu (a, b) (d, e) = (fu a d, fu b e) -zipWithT3 :: (a -> b -> c) -> (a,a,a) -> (b,b,b) -> (c,c,c) +zipWithT3 :: (a -> b -> c) -> (a, a, a) -> (b, b, b) -> (c, c, c) zipWithT3 fu (a, b, c) (d, e, f) = (fu a d, fu b e, fu c f) -zipWithT4 :: (a -> b -> c) -> (a,a,a,a) -> (b,b,b,b) -> (c,c,c,c) +zipWithT4 :: (a -> b -> c) -> (a, a, a, a) -> (b, b, b, b) -> (c, c, c, c) zipWithT4 fu (a, b, c, d) (e, f, g, h) = (fu a e, fu b f, fu c g, fu d h) -zipWithT5 :: (a -> b -> c) -> (a,a,a,a,a) -> (b,b,b,b,b) -> (c,c,c,c,c) +zipWithT5 :: (a -> b -> c) -> (a, a, a, a, a) -> (b, b, b, b, b) -> (c, c, c, c, c) zipWithT5 fu (a, b, c, d, i) (e, f, g, h, j) = (fu a e, fu b f, fu c g, fu d h, fu i j) toFloating :: (Real a, Floating b) => a -> b @@ -142,26 +138,25 @@ toFloating = fromRational . toRational (!!%) lst idx = lst !! (idx `mod` length lst) (++!) :: (Show a) => String -> a -> String -(++!) str = (str++) . show +(++!) str = (str ++) . show -clamp :: (Ord a) => a -> (a, a) -> a +clamp :: (Ord a) => a -> (a, a) -> a clamp var (low, high) = min (max var low) high -floatVertex :: (GLfloat,GLfloat,GLfloat) -> Vertex3 GLdouble +floatVertex :: (GLfloat, GLfloat, GLfloat) -> Vertex3 GLdouble floatVertex tup = uncurry3 Vertex3 (mapT3 toFloating tup) -floatVector :: (GLfloat,GLfloat,GLfloat) -> Vector3 GLdouble +floatVector :: (GLfloat, GLfloat, GLfloat) -> Vector3 GLdouble floatVector tup = uncurry3 Vector3 (mapT3 toFloating tup) -- Maps a function across a list, except this function -- can also be given a state variable like how foldl -- works -mapWith :: (s -> a -> (b,s)) -> s -> [a] -> ([b], s) -mapWith func state (x:xs) = - let (x',s') = func state x in - let (l,s) = mapWith func s' xs in (x':l, s) - -mapWith _ s [] = ([],s) +mapWith :: (s -> a -> (b, s)) -> s -> [a] -> ([b], s) +mapWith func state (x : xs) = + let (x', s') = func state x + in let (l, s) = mapWith func s' xs in (x' : l, s) +mapWith _ s [] = ([], s) {- Useful function that accepts two functions - and applies the third argument to both. Useful for @@ -178,18 +173,17 @@ mapWith _ s [] = ([],s) {- Instance where a monad can deconstruct - when the operation has failed -} class (Monad m) => MonadHasFailure m where - isFail :: m a -> Bool + isFail :: m a -> Bool instance MonadHasFailure Maybe where - isFail = isNothing + isFail = isNothing instance MonadHasFailure [] where - isFail = null + isFail = null instance MonadHasFailure (Either a) where - isFail (Left _) = True - isFail _ = False - + isFail (Left _) = True + isFail _ = False {- A way of chaining together commands such - that the first function in the chain that @@ -202,49 +196,52 @@ instance MonadHasFailure (Either a) where -} (>|>) :: (MonadHasFailure m) => (a -> m c) -> (a -> m c) -> a -> m c (>|>) f1 f2 a = - let res = f1 a in - isFail res ? f2 a $ res + let res = f1 a + in isFail res ? f2 a $ res (>||>) :: (MonadHasFailure m) => m a -> m a -> m a (>||>) a b - | isFail a = b - | otherwise = a + | isFail a = b + | otherwise = a whileM_ :: (Monad m) => (a -> Bool) -> m a -> a -> m a whileM_ func routine start = do - case func start of - True -> routine >>= whileM_ func routine - False -> return start + case func start of + True -> routine >>= whileM_ func routine + False -> return start whileM :: (Monad m) => (a -> Bool) -> m a -> a -> m [a] whileM bool routine' start' = - whileM' bool routine' start' [] - where - whileM' func routine start lst = do - case func start of - True -> do - next <- routine - whileM' func routine next (lst ++ [start]) - False -> return lst + whileM' bool routine' start' [] + where + whileM' func routine start lst = do + case func start of + True -> do + next <- routine + whileM' func routine next (lst ++ [start]) + False -> return lst untilM_ :: (Monad m) => (a -> Bool) -> m a -> m a untilM_ func routine = do - start <- routine - if' (func start) - (untilM_ func routine) - (return start) + start <- routine + if' + (func start) + (untilM_ func routine) + (return start) untilM :: (Monad m) => (a -> Bool) -> m a -> m [a] untilM func' routine' = - untilM' func' routine' [] - where untilM' func routine lst = do - start <- routine - if' (func start) - (untilM' func routine (lst ++ [start])) - (return lst) + untilM' func' routine' [] + where + untilM' func routine lst = do + start <- routine + if' + (func start) + (untilM' func routine (lst ++ [start])) + (return lst) dFold :: [a] -> b -> (a -> a -> b -> b) -> b -dFold (x1:x2:xs) next func = dFold (x2:xs) (func x1 x2 next) func +dFold (x1 : x2 : xs) next func = dFold (x2 : xs) (func x1 x2 next) func dFold _ next _ = next (!>>) :: a -> (a -> b) -> b @@ -259,17 +256,19 @@ dFold _ next _ = next (<..>) :: (b -> a -> c) -> (a -> b) -> a -> c (<..>) f1 f2 a = f1 (f2 a) a -toHex :: (Integral a,Show a) => a -> String -toHex n | n == 0 = "" - | otherwise = - let (quot',rem') = n `divMod` 16 in - toHex quot' ++ [index' !! fromIntegral rem'] - where index' = "0123456789ABCDEFGHIJKlMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +toHex :: (Integral a, Show a) => a -> String +toHex n + | n == 0 = "" + | otherwise = + let (quot', rem') = n `divMod` 16 + in toHex quot' ++ [index' !! fromIntegral rem'] + where + index' = "0123456789ABCDEFGHIJKlMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" average :: (Fold.Foldable a, Real c, Fractional b) => a c -> b average lst = - let (sum',count) = Fold.foldl' (\(sum_,count_) x -> (sum_ + x, count_ + 1)) (0,0) lst in - realToFrac sum' / count + let (sum', count) = Fold.foldl' (\(sum_, count_) x -> (sum_ + x, count_ + 1)) (0, 0) lst + in realToFrac sum' / count maybeDefault :: a -> Maybe a -> a maybeDefault a b = fromJust $ b >||> Just a @@ -278,7 +277,7 @@ maybeDefaultM :: (Monad m) => Maybe a -> (a -> m ()) -> m () -> m () maybeDefaultM Nothing _ a = a maybeDefaultM (Just a) b _ = b a -data MonadPlusBuilder a b = MonadPlusBuilder a b +data MonadPlusBuilder a b = MonadPlusBuilder a b plusM :: a -> MonadPlusBuilder a () plusM a = MonadPlusBuilder a () @@ -287,7 +286,7 @@ runMonadPlusBuilder :: MonadPlusBuilder a b -> a runMonadPlusBuilder (MonadPlusBuilder !a _) = a instance (MonadPlus a) => Functor (MonadPlusBuilder (a b)) where - fmap f b = b >>= return . f + fmap f b = b >>= return . f instance (MonadPlus a) => Applicative (MonadPlusBuilder (a b)) where (<*>) afn aa = do @@ -297,28 +296,29 @@ instance (MonadPlus a) => Applicative (MonadPlusBuilder (a b)) where pure = return instance (MonadPlus a) => Monad (MonadPlusBuilder (a b)) where - return = MonadPlusBuilder mzero - MonadPlusBuilder a1 _ >> MonadPlusBuilder a2 b = MonadPlusBuilder (a1 `mplus` a2) b - builder@(MonadPlusBuilder _ b) >>= f = builder >> f b + return = MonadPlusBuilder mzero + MonadPlusBuilder a1 _ >> MonadPlusBuilder a2 b = MonadPlusBuilder (a1 `mplus` a2) b + builder@(MonadPlusBuilder _ b) >>= f = builder >> f b untilM2 :: (Monad m) => (a -> m Bool) -> a -> (a -> m a) -> m a untilM2 cond ini bod = do - bool <- cond ini - if bool then return ini - else bod ini >>= \newini -> untilM2 cond newini bod + bool <- cond ini + if bool + then return ini + else bod ini >>= \newini -> untilM2 cond newini bod (<!>) :: (MArray a e IO, Ix i) => a i e -> i -> StateVar e -(<!>) arr idx = - let setter = writeArray arr idx - getter = readArray arr idx in - makeStateVar getter setter +(<!>) arr idx = + let setter = writeArray arr idx + getter = readArray arr idx + in makeStateVar getter setter for :: [a] -> (a -> b) -> [b] for = flip map -distribMaybe :: Maybe (a,b) -> (Maybe a, Maybe b) -distribMaybe Nothing = (Nothing,Nothing) -distribMaybe (Just (a,b)) = (Just a, Just b) +distribMaybe :: Maybe (a, b) -> (Maybe a, Maybe b) +distribMaybe Nothing = (Nothing, Nothing) +distribMaybe (Just (a, b)) = (Just a, Just b) whenM :: IO Bool -> IO () -> IO () whenM b = (>>=) b . flip when @@ -327,7 +327,7 @@ mix :: (Floating a) => a -> a -> a -> a mix a b c = a * c + b * (1 - c) fpart :: (RealFrac a) => a -> a -fpart x = x - (fromIntegral (floor x::Int)) +fpart x = x - (fromIntegral (floor x :: Int)) ifNaN :: (RealFloat a) => a -> a -> a ifNaN reg def = if' (isNaN reg) def reg @@ -336,11 +336,12 @@ everyN :: Int -> [a] -> [a] everyN _ [] = [] everyN n (x : xs) = x : (everyN n $ drop n xs) -chunkList :: [a] -> [(a,a)] +chunkList :: [a] -> [(a, a)] chunkList l = zip [x | x <- everyN 1 l] [x | x <- everyN 1 (tail l)] -chunkList3 :: [a] -> [(a,a,a)] -chunkList3 l = zip3 +chunkList3 :: [a] -> [(a, a, a)] +chunkList3 l = + zip3 [x | x <- everyN 2 l] [x | x <- everyN 2 (tail l)] [x | x <- everyN 2 (tail $ tail l)] diff --git a/Graphics/Rendering/HelpGL.hs b/Graphics/Rendering/HelpGL.hs index 938147e..201c3a6 100644 --- a/Graphics/Rendering/HelpGL.hs +++ b/Graphics/Rendering/HelpGL.hs @@ -1,16 +1,12 @@ -module Graphics.Rendering.HelpGL -( emptyRGBATexture ) -where - -import Graphics.Rendering.OpenGL as GL -import Foreign.Ptr +module Graphics.Rendering.HelpGL (emptyRGBATexture) where import Foreign.Marshal.Array +import Foreign.Ptr +import Graphics.Rendering.OpenGL as GL (?) :: (Integral a, Num b) => () -> a -> b (?) _ = fromIntegral - emptyRGBATexture :: Int -> Int -> IO () emptyRGBATexture w h = - texImage2D Texture2D NoProxy 0 RGBA' (TextureSize2D (()?w) (()?h)) 0 (PixelData RGBA UnsignedByte nullPtr) + texImage2D Texture2D NoProxy 0 RGBA' (TextureSize2D (() ?w) (() ?h)) 0 (PixelData RGBA UnsignedByte nullPtr) diff --git a/Graphics/SDL/SDLHelp.hs b/Graphics/SDL/SDLHelp.hs index 72159d1..40ce820 100644 --- a/Graphics/SDL/SDLHelp.hs +++ b/Graphics/SDL/SDLHelp.hs @@ -1,34 +1,37 @@ -{-# LANGUAGE OverloadedStrings, LambdaCase, ViewPatterns, RankNTypes #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE ViewPatterns #-} + module Graphics.SDL.SDLHelp where -import Data.Word import Control.Monad -import Graphics.Glyph.Util - -import SDL as SDL -import SDL.Video.Renderer (SurfacePixelFormat(..)) - +import Data.Bits +import Data.Word +import Foreign.Ptr +import Foreign.Storable import Graphics.GL.Compatibility30 +import Graphics.Glyph.Util import Graphics.Rendering.OpenGL as GL - -import Foreign.Storable -import Foreign.Ptr -import Data.Bits - -import System.IO.Unsafe -import System.Endian -import System.Exit +import SDL as SDL import SDL.Raw (getSurfaceColorMod) import qualified SDL.Raw.Types +import SDL.Video.Renderer (SurfacePixelFormat (..)) +import System.Endian +import System.Exit +import System.IO.Unsafe -data TextureData = TextureData { - textureSize :: (Int,Int), - textureObject :: TextureObject } deriving Show - -data TextureData3D = TextureData3D { - textureSize3D :: (Int,Int,Int), - textureObject3D :: TextureObject } deriving Show +data TextureData = TextureData + { textureSize :: (Int, Int), + textureObject :: TextureObject + } + deriving (Show) +data TextureData3D = TextureData3D + { textureSize3D :: (Int, Int, Int), + textureObject3D :: TextureObject + } + deriving (Show) bindSurfaceToTexture :: SDL.Surface -> TextureObject -> IO TextureData bindSurfaceToTexture surf to = do @@ -43,74 +46,76 @@ bindSurfaceToTexture surf to = do fi :: (Integral a, Integral b) => a -> b fi = fromIntegral -textureFromPointer3D :: Ptr Word8 -> (Int,Int,Int) -> TextureObject -> IO TextureData3D -textureFromPointer3D ptr (w,h,d) to = do - textureBinding Texture3D $= Just to - glTexImage3D GL_TEXTURE_3D 0 3 (f w) (f h) (f d) 0 GL_RGB GL_UNSIGNED_BYTE ptr - return $ TextureData3D (w,h,d) to - where f = fromIntegral +textureFromPointer3D :: Ptr Word8 -> (Int, Int, Int) -> TextureObject -> IO TextureData3D +textureFromPointer3D ptr (w, h, d) to = do + textureBinding Texture3D $= Just to + glTexImage3D GL_TEXTURE_3D 0 3 (f w) (f h) (f d) 0 GL_RGB GL_UNSIGNED_BYTE ptr + return $ TextureData3D (w, h, d) to + where + f = fromIntegral textureFromSurface :: SDL.Surface -> IO TextureData textureFromSurface surf = makeTexture >>= (bindSurfaceToTexture surf >=> return) makeTexture3D :: IO TextureObject makeTexture3D = do - texobj <- liftM head $ genObjectNames 1 - textureBinding Texture3D $= Just texobj - textureFilter Texture3D $= ((Linear', Nothing), Linear') - return texobj + texobj <- liftM head $ genObjectNames 1 + textureBinding Texture3D $= Just texobj + textureFilter Texture3D $= ((Linear', Nothing), Linear') + return texobj makeTexture :: IO TextureObject makeTexture = do - texobj <- liftM head $ genObjectNames 1 - textureBinding Texture2D $= Just texobj - textureFilter Texture2D $= ((Linear', Nothing), Linear') - return texobj + texobj <- liftM head $ genObjectNames 1 + textureBinding Texture2D $= Just texobj + textureFilter Texture2D $= ((Linear', Nothing), Linear') + return texobj getPixel :: Int -> Int -> SDL.Surface -> IO Word32 getPixel x y surf = do - bpp <- fromIntegral <$> getSurfaceBytesPerPixel surf - ptr <- (surfacePixels surf >>= return.castPtr) :: IO (Ptr Word8) - (V2 w h) <- SDL.surfaceDimensions surf - let newPtr = ptr `plusPtr` (y * bpp * fromIntegral w) `plusPtr` (x * bpp) - - ret <- case bpp of - -- bytes = R G B A - 1 -> liftM fromIntegral $ peek (castPtr newPtr :: Ptr Word8) - 2 -> liftM fromIntegral $ peek (castPtr newPtr :: Ptr Word16) - 3 -> do - ord1 <- liftM fromIntegral $ peek (castPtr newPtr :: Ptr Word16) - ord2 <- liftM fromIntegral $ peek (castPtr (newPtr `plusPtr` 2) :: Ptr Word8) - return $ ((ord1 `shiftL` 16) + (ord2 `shiftL` 8)) + 0xFF - 4 -> do - liftM fromIntegral $ peek (castPtr newPtr :: Ptr Word32) - _ -> error "Unrecognized format" - - return $ toBE32 ret + bpp <- fromIntegral <$> getSurfaceBytesPerPixel surf + ptr <- (surfacePixels surf >>= return . castPtr) :: IO (Ptr Word8) + (V2 w h) <- SDL.surfaceDimensions surf + let newPtr = ptr `plusPtr` (y * bpp * fromIntegral w) `plusPtr` (x * bpp) + + ret <- case bpp of + -- bytes = R G B A + 1 -> liftM fromIntegral $ peek (castPtr newPtr :: Ptr Word8) + 2 -> liftM fromIntegral $ peek (castPtr newPtr :: Ptr Word16) + 3 -> do + ord1 <- liftM fromIntegral $ peek (castPtr newPtr :: Ptr Word16) + ord2 <- liftM fromIntegral $ peek (castPtr (newPtr `plusPtr` 2) :: Ptr Word8) + return $ ((ord1 `shiftL` 16) + (ord2 `shiftL` 8)) + 0xFF + 4 -> do + liftM fromIntegral $ peek (castPtr newPtr :: Ptr Word32) + _ -> error "Unrecognized format" + + return $ toBE32 ret getPixelUnsafe :: Int -> Int -> SDL.Surface -> Word32 getPixelUnsafe x y surf = unsafePerformIO $ getPixel x y surf rgbToWord :: Word8 -> Word8 -> Word8 -> Word32 rgbToWord r g b = - let tW32 x = (fromIntegral x) :: Word32 in - ( (tW32 r) `shiftL` 24) + - ( (tW32 g) `shiftL` 16) + - ( (tW32 b) `shiftL` 8) + - 0xFF + let tW32 x = (fromIntegral x) :: Word32 + in ((tW32 r) `shiftL` 24) + + ((tW32 g) `shiftL` 16) + + ((tW32 b) `shiftL` 8) + + 0xFF wordToPixel :: Word32 -> Color4 Word8 wordToPixel word = - Color4 (fromIntegral $ word .&. 0xFF) - (fromIntegral $ (word `shiftR` 8) .&. 0xFF) - (fromIntegral $ (word `shiftR` 16) .&. 0xFF) - (fromIntegral $ (word `shiftR` 24) .&. 0xFF) + Color4 + (fromIntegral $ word .&. 0xFF) + (fromIntegral $ (word `shiftR` 8) .&. 0xFF) + (fromIntegral $ (word `shiftR` 16) .&. 0xFF) + (fromIntegral $ (word `shiftR` 24) .&. 0xFF) getRGBA :: SDL.Surface -> Int -> Int -> IO (Color4 Word8) getRGBA surf x y = liftM wordToPixel $ getPixel x y surf -simpleStartup :: String -> (Int,Int) -> IO SDL.Window -simpleStartup name' (w,h) = do +simpleStartup :: String -> (Int, Int) -> IO SDL.Window +simpleStartup name' (w, h) = do SDL.initialize [SDL.InitVideo] SDL.HintRenderScaleQuality $= SDL.ScaleLinear renderQuality <- SDL.get SDL.HintRenderScaleQuality @@ -131,47 +136,51 @@ simpleStartup name' (w,h) = do defaultReshape :: Int -> Int -> a -> IO a defaultReshape w h ret = do - let size = Size (fromIntegral w) (fromIntegral h) - viewport $=(Position 0 0, size) - -- _ <- SDL.setVideoMode w h 32 [SDL.OpenGL, SDL.Resizable, SDL.DoubleBuf] - return ret + let size = Size (fromIntegral w) (fromIntegral h) + viewport $= (Position 0 0, size) + -- _ <- SDL.setVideoMode w h 32 [SDL.OpenGL, SDL.Resizable, SDL.DoubleBuf] + return ret startPipeline :: forall a. (Int -> Int -> a -> IO a) -> (SDL.EventPayload -> a -> IO a) -> (a -> IO a) -> (a -> IO a) -> a -> IO () startPipeline reshapeH eventH displayH updateH ini = do - let pumpEvents' res = do - evs <- SDL.pollEvents - foldM (\res (SDL.eventPayload -> ev) -> case ev of - SDL.QuitEvent -> exitSuccess >> return res - _ -> eventH ev res) res evs - -- case ev of - -- Quit -> do - -- putStrLn "Exit event." - -- exitSuccess - -- SDL.NoEvent -> return res - -- VideoResize w h -> reshapeH w h res >>= pumpEvents' - -- _ -> eventH ev res >>= pumpEvents' - runPipeline val = do - res <- pumpEvents' val >>= displayH - updateH res >>= runPipeline - - -- -- TODO unhardcode this - reshapeH 1920 1080 ini >>= runPipeline + let pumpEvents' res = do + evs <- SDL.pollEvents + foldM + ( \res (SDL.eventPayload -> ev) -> case ev of + SDL.QuitEvent -> exitSuccess >> return res + _ -> eventH ev res + ) + res + evs + -- case ev of + -- Quit -> do + -- putStrLn "Exit event." + -- exitSuccess + -- SDL.NoEvent -> return res + -- VideoResize w h -> reshapeH w h res >>= pumpEvents' + -- _ -> eventH ev res >>= pumpEvents' + runPipeline val = do + res <- pumpEvents' val >>= displayH + updateH res >>= runPipeline + + -- -- TODO unhardcode this + reshapeH 1920 1080 ini >>= runPipeline setupTexturing :: TextureData -> UniformLocation -> Int -> IO () setupTexturing (TextureData _ to) tu unit = do - texture Texture2D $= Enabled - activeTexture $= TextureUnit (fromIntegral unit) - textureBinding Texture2D $= Just to - uniform tu $= Index1 (fromIntegral unit::GLint) + texture Texture2D $= Enabled + activeTexture $= TextureUnit (fromIntegral unit) + textureBinding Texture2D $= Just to + uniform tu $= Index1 (fromIntegral unit :: GLint) setupTexturing3D :: TextureData3D -> UniformLocation -> Int -> IO () setupTexturing3D (TextureData3D _ to) tu unit = do - texture Texture3D $= Enabled - activeTexture $= TextureUnit (fromIntegral unit) - textureBinding Texture3D $= Just to - uniform tu $= Index1 (fromIntegral unit::GLint) + texture Texture3D $= Enabled + activeTexture $= TextureUnit (fromIntegral unit) + textureBinding Texture3D $= Just to + uniform tu $= Index1 (fromIntegral unit :: GLint) getSurfaceBytesPerPixel :: SDL.Surface -> IO Word8 getSurfaceBytesPerPixel (SDL.Surface ptr _) = do - SDL.Raw.Types.pixelFormatBytesPerPixel <$> - (peek . SDL.Raw.Types.surfaceFormat =<< peek ptr) + SDL.Raw.Types.pixelFormatBytesPerPixel + <$> (peek . SDL.Raw.Types.surfaceFormat =<< peek ptr) @@ -1,20 +1,18 @@ module Models where -import Graphics.Glyph.GeometryBuilder -import Graphics.Glyph.BufferBuilder - import Control.Monad import Data.ByteString.Lazy - +import Graphics.Glyph.BufferBuilder import Graphics.Glyph.GLMath +import Graphics.Glyph.GeometryBuilder import Graphics.Glyph.ObjLoader -square :: (Num b,IsModelBuilder b a) => b -> a () +square :: (Num b, IsModelBuilder b a) => b -> a () square dist = do - plotVertex3 dist dist 0 - plotVertex3 (-dist) dist 0 - plotVertex3 (-dist) (-dist) 0 - plotVertex3 dist (-dist) 0 + plotVertex3 dist dist 0 + plotVertex3 (- dist) dist 0 + plotVertex3 (- dist) (- dist) 0 + plotVertex3 dist (- dist) 0 getBS :: GeometryBuilder () -> ByteString getBS = buildSource @@ -27,62 +25,63 @@ treeShader = buildSource tree triangle :: GeometryBuilder () triangle = - generating Triangles $ do - projectionMatrixUniform "pjMatrix" - modelViewMatrixUniform "mvMatrix" - textureOutput "texposition" - normalOutput "normal" - positionOutput "frag_position" - - gVertex4E 1 0 0 0 - gVertex4E 0 1 0 0 - gVertex4E 0 0 1 0 + generating Triangles $ do + projectionMatrixUniform "pjMatrix" + modelViewMatrixUniform "mvMatrix" + textureOutput "texposition" + normalOutput "normal" + positionOutput "frag_position" + + gVertex4E 1 0 0 0 + gVertex4E 0 1 0 0 + gVertex4E 0 0 1 0 tree :: GeometryBuilder () tree = - generating TriangleStrip $ do - projectionMatrixUniform "pjMatrix" - modelViewMatrixUniform "mvMatrix" - textureOutput "texposition" - normalOutput "normal" - positionOutput "frag_position" - - let r = 0.045 - let h = 0.4 - - - forM_ [0..6.4] $ \th -> do - let vertex x y z = do - gNormal3 x 0 z - gVertex4E x y z 0 - - let c = r * cos th - let s = r * sin th - - let c2 = r * (cos $ th + 1.0) - let s2 = r * (sin $ th + 1.0) - - let texX = th / 6.4 / 2.0 - let texX2 = (th+1.0) / 6.4 / 2.0 - - let quads = trianglesFromQuads - [(gTexture2 texX 0 >> vertex c 0 s), - (gTexture2 texX 1 >> vertex c h s), - (gTexture2 texX2 1 >> vertex c2 h s2), - (gTexture2 texX2 0 >> vertex c2 0 s2)] - - sequence_ quads - - forM_ [0..6.4] $ \th -> do - let vertex x y z = do - gNormal3 x 0 z - gVertex4E x y z 0 - - let c = r * 4 * cos th - let s = r * 4 * sin th - let texX = th / 6.4 / 2.0 + 0.5 - - gTexture2 texX 1 - vertex 0 (h*2) 0 - gTexture2 texX 0 - vertex s (h/4) c + generating TriangleStrip $ do + projectionMatrixUniform "pjMatrix" + modelViewMatrixUniform "mvMatrix" + textureOutput "texposition" + normalOutput "normal" + positionOutput "frag_position" + + let r = 0.045 + let h = 0.4 + + forM_ [0 .. 6.4] $ \th -> do + let vertex x y z = do + gNormal3 x 0 z + gVertex4E x y z 0 + + let c = r * cos th + let s = r * sin th + + let c2 = r * (cos $ th + 1.0) + let s2 = r * (sin $ th + 1.0) + + let texX = th / 6.4 / 2.0 + let texX2 = (th + 1.0) / 6.4 / 2.0 + + let quads = + trianglesFromQuads + [ (gTexture2 texX 0 >> vertex c 0 s), + (gTexture2 texX 1 >> vertex c h s), + (gTexture2 texX2 1 >> vertex c2 h s2), + (gTexture2 texX2 0 >> vertex c2 0 s2) + ] + + sequence_ quads + + forM_ [0 .. 6.4] $ \th -> do + let vertex x y z = do + gNormal3 x 0 z + gVertex4E x y z 0 + + let c = r * 4 * cos th + let s = r * 4 * sin th + let texX = th / 6.4 / 2.0 + 0.5 + + gTexture2 texX 1 + vertex 0 (h * 2) 0 + gTexture2 texX 0 + vertex s (h / 4) c 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 |