pioneers/src/Map/Map.hs
Stefan Dresselhaus 306381c4ed little cleanup
- some formatting
- changed y/z-Coords on Map (y is height now, map is in x/z-plane)
2014-01-02 13:02:01 +01:00

158 lines
5.5 KiB
Haskell

{-# LANGUAGE OverloadedStrings #-}
module Map.Map
where
import System.Random
import Data.Array.IArray
import Data.Text as T
import Prelude as P
import Graphics.Rendering.OpenGL.Raw.Core31.Types (GLfloat)
data TileType =
Grass
| Sand
| Water
| Mountain
deriving (Show, Eq)
type MapEntry = (
Float, -- ^ Height
TileType
)
type PlayMap = Array (Int, Int) MapEntry
lineHeight :: GLfloat
lineHeight = 0.8660254
-- | getMap returns the map as List of Vertices (rendered as triangles).
-- This promises to hold True for length v == length c == length n in
-- getMap -> (v,c,n) with length v `mod` 3 == 0.
--
-- v are Vertices, c are Colors and n are Normals.
getMap :: IO ([GLfloat], [GLfloat], [GLfloat])
getMap = do
map' <- testmap
return $ unzip3 $ generateTriangles map'
generateTriangles :: PlayMap -> [(GLfloat, GLfloat, GLfloat)]
generateTriangles map' =
let ((xl,yl),(xh,yh)) = bounds map' in
P.concat [P.concat $ P.map (generateFirstTriLine map' y) [xl .. xh - 2]
++ P.map (generateSecondTriLine map' (y == yh) y) [xl .. xh - 2]
| y <- [yl..yh]]
generateFirstTriLine :: PlayMap -> Int -> Int -> [(GLfloat, GLfloat, GLfloat)]
generateFirstTriLine map' y x =
P.concat $
if even x then
[ lookupVertex map' x y,
lookupVertex map' (x + 1) y,
lookupVertex map' (x + 2) y
]
else
[ lookupVertex map' x y,
lookupVertex map' (x + 2) y,
lookupVertex map' (x + 1) y
]
generateSecondTriLine :: PlayMap -> Bool -> Int -> Int -> [(GLfloat, GLfloat, GLfloat)]
generateSecondTriLine map' False y x =
P.concat $
if even x then
[ lookupVertex map' x (y + 1),
lookupVertex map' (x + 2) (y + 1),
lookupVertex map' (x + 1) y
]
else
[ lookupVertex map' x y,
lookupVertex map' (x + 1) (y + 1),
lookupVertex map' (x + 2) y
]
generateSecondTriLine _ True _ _ = []
lookupVertex :: PlayMap -> Int -> Int -> [(GLfloat, GLfloat, GLfloat)]
lookupVertex map' x y =
let
(cr, cg, cb) = colorLookup map' (x,y)
(vx, vy, vz) = coordLookup (x,y) $ heightLookup map' (x,y)
(nx, ny, nz) = (0.0, 1.0, 0.0) :: (GLfloat, GLfloat, GLfloat)
--TODO: calculate normals correctly!
in
[
(vx, cr, nx),
(vy, cg, ny),
(vz, cb, nz)
]
heightLookup :: PlayMap -> (Int,Int) -> GLfloat
heightLookup hs t = if inRange (bounds hs) t then fromRational $ toRational h else 0.0
where
(h,_) = hs ! t
colorLookup :: PlayMap -> (Int,Int) -> (GLfloat, GLfloat, GLfloat)
colorLookup hs t = if inRange (bounds hs) t then c else (0.0, 0.0, 0.0)
where
(_,tp) = hs ! t
c = case tp of
Water -> (0.5, 0.5, 1)
Sand -> (0.9, 0.85, 0.7)
Grass -> (0.3, 0.9, 0.1)
Mountain -> (0.5, 0.5, 0.5)
coordLookup :: (Int,Int) -> GLfloat -> (GLfloat, GLfloat, GLfloat)
coordLookup (x,z) y =
if even x then
(fromIntegral $ x `div` 2, y, fromIntegral (2 * z) * lineHeight)
else
(fromIntegral (x `div` 2) / 2.0, y, fromIntegral (2 * z + 1) * lineHeight)
-- if writing in ASCII-Format transpose so i,j -> y,x
-- row-minor -> row-major
testMapTemplate :: [Text]
testMapTemplate = T.transpose [
"~~~~~~~~~~~~~~~~~~~~",
"~~SSSSSSSSSSSSSS~~~~",
"~SSGGGGGGGSGSGGS~~~~",
"~SSGGGGGGMSGSGMS~~~~",
"~SGGGGGGMMMGGGS~~~S~",
"~SGGGMGMMMMMGGS~~~SS",
"~GGGGGGGGGGGGGGS~~~~",
"~SGGGGGGGGGGGGGS~~~~",
"~~SSSSGGGSSSSS~~~~~~",
"~~~~~SGGGGS~~~~~~~~~",
"~~~~SSGGGGSS~~~~~~~~",
"~~SSSGGGGGGSSSSS~~~~",
"~SSGSGSGGGSGSGGS~~~~",
"~SSGSGSGGMSGSGMS~~~~",
"~SGGMMMMGGGGGGS~~~~~",
"~SGMMMMMGGGGSSS~~~~~",
"~GGMMMMMGGGSSSSS~~~~",
"~SGGGGGGGSSSSSSS~~~~",
"~~SSSSSSSSSSSS~~~~~~",
"~~~~~~~~~~~~~~~~~~~~"
]
testmap :: IO PlayMap
testmap = do
g <- getStdGen
rawMap <- return $ parseTemplate (randoms g) (T.concat testMapTemplate)
return $ listArray ((0,0),(19,19)) rawMap
parseTemplate :: [Int] -> Text -> [MapEntry]
parseTemplate (r:rs) t =
(case T.head t of
'~' -> (0, Water)
'S' -> (0, Sand)
'G' -> (fromIntegral (r `mod` 3)/2.0,Grass)
'M' -> (fromIntegral (r `mod` 3 + 2)/2.0, Mountain)
_ -> error "invalid template format for map"
):parseTemplate rs (T.tail t)
parseTemplate [] _ = error "out of randoms.."