diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2022-12-03 02:18:25 -0700 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2022-12-03 02:18:25 -0700 |
commit | ecf90db5ffada1890e759c5a7e91c13ec15a02bd (patch) | |
tree | bb102d9d8aeeecdb6d36b63a5b5ec0623d2d8f4d | |
parent | d7fb5d4551a93b4756db62f494b761c0cef2fda7 (diff) | |
parent | a60702dd882768e7f5b7fcadd39253ac8de9114f (diff) | |
download | terralloc-ecf90db5ffada1890e759c5a7e91c13ec15a02bd.tar.gz terralloc-ecf90db5ffada1890e759c5a7e91c13ec15a02bd.tar.bz2 terralloc-ecf90db5ffada1890e759c5a7e91c13ec15a02bd.zip |
Merge remote-tracking branch 'origin/snow'
-rw-r--r-- | Final.hs | 2 | ||||
-rw-r--r-- | Graphics/Glyph/GLMath.hs | 378 | ||||
-rw-r--r-- | Graphics/Glyph/Util.hs | 15 | ||||
-rw-r--r-- | Graphics/SDL/SDLHelp.hs | 1 | ||||
-rw-r--r-- | Resources.hs | 266 | ||||
-rw-r--r-- | maps/goliath_height.png | bin | 0 -> 27219 bytes | |||
-rw-r--r-- | maps/goliath_terrain.png | bin | 0 -> 3414 bytes | |||
-rw-r--r-- | maps/svalbard_height.png | bin | 2908 -> 19903 bytes | |||
-rw-r--r-- | maps/svalbard_terrain.png | bin | 1862 -> 1946 bytes | |||
-rw-r--r-- | package.yaml | 1 | ||||
-rw-r--r-- | shaders/snow.frag | 13 | ||||
-rw-r--r-- | shaders/snow.geom | 26 | ||||
-rw-r--r-- | shaders/snow.vert | 20 |
13 files changed, 519 insertions, 203 deletions
@@ -127,6 +127,7 @@ colorArray marr = do - 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 marr arr = do let (_,(w,h)) = bounds marr @@ -351,6 +352,7 @@ main = do (mapping,water) <- getWaterQuads arr coloredArr coloredArr2 <- mapArray (\idx -> if idx == 0 then -1 else Map.findWithDefault (-1) idx mapping) coloredArr + printShowArray coloredArr2 printArray arr diff --git a/Graphics/Glyph/GLMath.hs b/Graphics/Glyph/GLMath.hs index b1df4c5..ac3e93a 100644 --- a/Graphics/Glyph/GLMath.hs +++ b/Graphics/Glyph/GLMath.hs @@ -1,170 +1,214 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleInstances #-} 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 - - data Vec2 a = Vec2 (a,a) deriving Show - data Vec3 a = Vec3 (a,a,a) deriving Show - data Vec4 a = Vec4 (a,a,a,a) deriving Show - - 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 - - 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 - - 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 - - - (<.>) :: (Vector a b) => b a -> b a -> a - (<.>) = vDot - - (|||) :: (Vector a b) => b a -> a - (|||) = 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) - - 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) - - 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) - - 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 ) - (×) :: (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 ) - - 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) - 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) - - class VectorMatrix vecT matT where - 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 ) - - - - - instance (Num a) => VectorMatrix (Vec4 a) (Mat4 a) where - 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 ) - - glslModelViewToNormalMatrix :: Mat4 GLfloat -> Mat3 GLfloat - 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) - +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 + +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) + +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 + +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 + +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 + + +(<.>) :: (Vector a b) => b a -> b a -> a +(<.>) = vDot + +(|||) :: (Vector a b) => b a -> a +(|||) = 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) + +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) + +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) + +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 ) +(×) :: (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 ) + +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) +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) + +class VectorMatrix vecT matT where + 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 ) + + + + +instance (Num a) => VectorMatrix (Vec4 a) (Mat4 a) where + 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 ) + +glslModelViewToNormalMatrix :: Mat4 GLfloat -> Mat3 GLfloat +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) + +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 + ) + +zRotationMatrix :: GLfloat -> Mat3 GLfloat +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) + +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 + diff --git a/Graphics/Glyph/Util.hs b/Graphics/Glyph/Util.hs index 1c1269d..90640a4 100644 --- a/Graphics/Glyph/Util.hs +++ b/Graphics/Glyph/Util.hs @@ -329,3 +329,18 @@ mix a b c = a * c + b * (1 - c) fpart :: (RealFrac a) => a -> a fpart x = x - (fromIntegral (floor x::Int)) +ifNaN :: (RealFloat a) => a -> a -> a +ifNaN reg def = if' (isNaN reg) def reg + +everyN :: Int -> [a] -> [a] +everyN _ [] = [] +everyN n (x : xs) = x : (everyN n $ drop n xs) + +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 + [x | x <- everyN 2 l] + [x | x <- everyN 2 (tail l)] + [x | x <- everyN 2 (tail $ tail l)] diff --git a/Graphics/SDL/SDLHelp.hs b/Graphics/SDL/SDLHelp.hs index 9c65c83..72159d1 100644 --- a/Graphics/SDL/SDLHelp.hs +++ b/Graphics/SDL/SDLHelp.hs @@ -138,7 +138,6 @@ defaultReshape w h ret = do 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 diff --git a/Resources.hs b/Resources.hs index 009bdac..d446796 100644 --- a/Resources.hs +++ b/Resources.hs @@ -36,6 +36,12 @@ 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 {- Types of terrain which are possible -} data TileType = Forest | Beach | Water | Grass | Jungle | Mountains | @@ -80,17 +86,32 @@ data Resources = Resources { routines :: [ResourcesClosure -> IO ()], - speed :: GLfloat, timeSpeed :: Int, time :: Int, 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 } + +setThreadDiff :: Double -> Resources -> Resources +setThreadDiff f r = r { threadDiff = f } + setRSurface :: SDL.Window -> Resources -> Resources setRSurface x r = r { rWindow = x } @@ -109,8 +130,8 @@ setMvMatrix x r = r { mvMatrix = x } setRoutines :: [ResourcesClosure -> IO ()] -> Resources -> Resources setRoutines x r = r { routines = x } -setSpeed :: GLfloat -> Resources -> Resources -setSpeed x r = r { speed = x } +setSpeedDirection :: Vec3 GLfloat -> Resources -> Resources +setSpeedDirection x r = r { speedDirection = x } setTimeSpeed :: Int -> Resources -> Resources setTimeSpeed x r = r { timeSpeed = x } @@ -133,6 +154,29 @@ setDDown x r = r { dDown = 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) + +cameraForward :: CameraPosition -> Vec3 GLfloat +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 + +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 + +data CameraMode = Oracle | FirstPerson deriving Eq {- Central data type for rendering each frame -} data ResourcesClosure = ResourcesClosure { @@ -151,7 +195,7 @@ data ResourcesClosure = ResourcesClosure { - person -} firstPerson :: Resources -> IO Resources firstPerson res = - let (CameraPosition (Vec3 (x,curh,y)) th ph) = rPosition 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) ) @@ -162,19 +206,21 @@ firstPerson res = v = y - (int $ (floor y::Int)) mixu1 = mix h3 h1 u mixu2 = mix h4 h2 u - newh = mix mixu2 mixu1 v + 0.2 + 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 $ - if (newh+0.2 > droph) then - setRPosition (CameraPosition (Vec3 (x,newh,y)) th ph) $ - setDDown 0 $ - if speed res > speedFactor res then - (setSpeed <..> speedFactor) res - else res + 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 setRPosition (CameraPosition (Vec3 (x, droph, y)) th ph) $ - setDDown (dDown res + 0.05) res + setDDown (dDown res + 0.03) res {- A function which will explode if a uniform - does not exist for the shader given, otherwis, @@ -192,11 +238,9 @@ getUniformsSafe prog uniforms = {- Builds an model view matrix given the - camera position of the scene -} buildMVMatrix :: CameraPosition -> Mat4 GLfloat -buildMVMatrix (CameraPosition eye th ph) = - let up = if ph' >= 90 && ph' < 270 then Vec3 (0,-1,0) else Vec3 (0,1,0) - where ph' = (floor ph::Int) `mod` 360 in - let lookat = eye <+> (Vec3 $ toEuclidian (1,th,ph)) in - lookAtMatrix eye lookat up +buildMVMatrix camera@(CameraPosition eye _ _) = + let lookat = eye <+> cameraForward camera in + lookAtMatrix eye lookat (cameraUp camera) {- Called after each frame to crunch throught the - events -} @@ -204,28 +248,66 @@ eventHandle :: SDL.EventPayload -> Resources -> IO Resources eventHandle event = case event of SDL.KeyboardEvent e -> case (SDL.keyboardEventKeyMotion e, SDL.keysymScancode (SDL.keyboardEventKeysym e)) of - (SDL.Pressed, SDL.ScancodeW) -> setPh 1 + (SDL.Pressed, SDL.ScancodeW) -> setPh 2 (SDL.Released, SDL.ScancodeW) -> setPh 0 - (SDL.Pressed, SDL.ScancodeA) -> setTh (-1) + (SDL.Pressed, SDL.ScancodeA) -> setTh (-2) (SDL.Released, SDL.ScancodeA) -> setTh 0 - (SDL.Pressed, SDL.ScancodeS) -> setPh (-1) + (SDL.Pressed, SDL.ScancodeS) -> setPh (-2) (SDL.Released, SDL.ScancodeS) -> setPh 0 - (SDL.Pressed, SDL.ScancodeD) -> setTh 1 + (SDL.Pressed, SDL.ScancodeD) -> setTh 2 (SDL.Released, SDL.ScancodeD) -> setTh 0 - (SDL.Pressed, SDL.ScancodeI) -> \res -> return $ setSpeed (speedFactor res) res - (SDL.Released, SDL.ScancodeI) -> return . setSpeed 0 - (SDL.Pressed, SDL.ScancodeK) -> \res -> return $ setSpeed (0 - speedFactor res) res - (SDL.Released, SDL.ScancodeK) -> return . setSpeed 0 + (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 @@ -291,6 +373,65 @@ eventHandle event = case event of -- 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 @@ -302,6 +443,7 @@ eventHandle event = case event of {- 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 @@ -333,13 +475,25 @@ displayHandle resources = do in mapM_ (Prelude.$rc) $ routines resources SDL.glSwapWindow (rWindow resources) - return 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) resourcesVelocity :: Resources -> Vec3 GLfloat -resourcesVelocity res = speed res `vScale` cameraToEuclidian (rPosition res) +resourcesVelocity res = getSpeed res `vScale` cameraToEuclidian (rPosition res) resourcesUnderWater :: Resources -> IO Bool resourcesUnderWater res = do @@ -355,8 +509,8 @@ updateHandle res = do let new = ((+) `on` (Prelude.$ res)) timeSpeed time in setTime new res where (CameraPosition x y z) `cAdd` (CameraPosition _ y' z') = - let x' = speed res `vScale` (V.normalize $ Vec3 $ toEuclidian (1,y, z)) in - (CameraPosition (x <+> x') (y + y') (z + z')) + let x' = getVelocity res in + CameraPosition (x <+> x') (y + y') (z + z') reshape :: Int -> Int -> Resources -> IO Resources reshape w h res = @@ -449,6 +603,41 @@ buildTerrainObject builder = do -- uniform lightposU $= rcLightPos rc -- setupTexturing3D density densityU 0 +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 ()) +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 buildForestObject :: Seq.Seq GLfloat -> String -> String -> IO (ResourcesClosure -> IO ()) buildForestObject a_seq obj tex = @@ -533,7 +722,7 @@ buildWaterObject builder = do 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 9) $= Index1 (rcTime rc / 20.0); uniform (UniformLocation 10) $= rcGlobalAmbient rc bool <- (resourcesUnderWater $ rcResources rc) if bool then @@ -546,8 +735,10 @@ makeResources :: SDL.Window -> BuilderM GLfloat b -> 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 @@ -558,15 +749,16 @@ makeResources window builder forestB jungleB water arr waterarr = do blend $= Enabled cullFace $= Just Back blendFunc $= (GL.SrcAlpha,OneMinusSrcAlpha)), + buildWaterObject water, buildForestObject forestB "tree.obj" "textures/wood_low.png", buildForestObject jungleB "jungletree.obj" "textures/jungle_tree.png", - buildWaterObject water + buildSnowObject arr stdgen -- cloudProgram ] Resources <$> pure window <*> do CameraPosition - <$> pure (Vec3 (10,10,2)) + <$> pure (Vec3 (10,10,-10)) <*> pure 0 <*> pure 0 <*> do CameraPosition @@ -576,14 +768,18 @@ makeResources window builder forestB jungleB water arr waterarr = do <*> pure pMatrix' <*> pure pMatrix' <*> l_routines - <*> pure 0 <*> 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 = diff --git a/maps/goliath_height.png b/maps/goliath_height.png Binary files differnew file mode 100644 index 0000000..5e982e8 --- /dev/null +++ b/maps/goliath_height.png diff --git a/maps/goliath_terrain.png b/maps/goliath_terrain.png Binary files differnew file mode 100644 index 0000000..5c288bd --- /dev/null +++ b/maps/goliath_terrain.png diff --git a/maps/svalbard_height.png b/maps/svalbard_height.png Binary files differindex 7670da1..656226a 100644 --- a/maps/svalbard_height.png +++ b/maps/svalbard_height.png diff --git a/maps/svalbard_terrain.png b/maps/svalbard_terrain.png Binary files differindex 5afd0b4..edc7f65 100644 --- a/maps/svalbard_terrain.png +++ b/maps/svalbard_terrain.png diff --git a/package.yaml b/package.yaml index 7aab7c5..e82ad36 100644 --- a/package.yaml +++ b/package.yaml @@ -26,4 +26,5 @@ dependencies: - filepath - StateVar - split + - time diff --git a/shaders/snow.frag b/shaders/snow.frag new file mode 100644 index 0000000..d494633 --- /dev/null +++ b/shaders/snow.frag @@ -0,0 +1,13 @@ +#version 150 +#extension GL_ARB_explicit_attrib_location : enable +#extension GL_ARB_explicit_uniform_location : enable + +layout(location = 0) out vec4 frag_color ; + +in float rad ; + +uniform vec4 globalAmbient ; + +void main() { + frag_color = vec4( 1.0,1.0,1.0,(9 - rad*rad)/9) * vec4(normalize(globalAmbient.xyz),globalAmbient.a) ; +} diff --git a/shaders/snow.geom b/shaders/snow.geom new file mode 100644 index 0000000..116a59d --- /dev/null +++ b/shaders/snow.geom @@ -0,0 +1,26 @@ +#version 150 +layout(points) in; +layout(triangle_strip, max_vertices=28) out; + +out float rad ; + +void vertex( vec3 pos ) { + gl_Position = gl_in[0].gl_Position + vec4(pos,0.0) ; + EmitVertex() ; +} + +void main( ) { + float r = 0.008 ; + float th = 0.00 ; + for( ; th < 6.3 ; th += 0.5 ) { + rad = 3 ; + vertex( vec3(r*sin(th),r*cos(th),0.0) ) ; + rad = 0.0 ; + vertex( vec3(0.0,0.0,0.0) ) ; + } + th = 0 ; + rad = 3 ; + vertex( vec3(r*sin(th),r*cos(th),0.0) ) ; + // vertex( vector[0] ) ; + EndPrimitive(); +} diff --git a/shaders/snow.vert b/shaders/snow.vert new file mode 100644 index 0000000..535c26a --- /dev/null +++ b/shaders/snow.vert @@ -0,0 +1,20 @@ +#version 150 +#extension GL_ARB_explicit_attrib_location : enable +#extension GL_ARB_explicit_uniform_location : enable + +layout(location = 0) in vec3 in_position ; +layout(location = 2) in vec3 in_range ; + +uniform mat4 pjMatrix ; +uniform mat4 mvMatrix ; + +uniform float time ; + +void main() { + float tmp = in_position.y + time ; + float ipart ; + float fpart = modf( tmp, ipart ) ; + float newy = in_range.y - (int(ipart) % int(in_range.y) + fpart) + in_range.x ; + vec3 newp = vec3( in_position.x, newy, in_position.z ) ; + gl_Position = pjMatrix * (mvMatrix * vec4(newp,1.0)) ; +} |