packages feed

topkata-0.0: Topkata/World/Render.hs

module Topkata.World.Render (drawWorld, inWall) where

import Topkata.World.Base
import Data.Array
import Data.List 
import Graphics.UI.GLUT
    (Vertex3(..), GLfloat(..), Normal3(..), Vector3(..),
     renderPrimitive, PrimitiveMode(..),
     normal, vertex, 
     translate,
     color, Color4(..))


borderWidth = 0.025

boxSelect SideFront  = [1, 2, 3, 4]
boxSelect SideBack   = [5, 6, 7, 8]
boxSelect SideLeft   = [1, 5, 8, 4]
boxSelect SideTop    = [1, 2, 6, 5]
boxSelect SideRight  = [2, 6, 7, 3]
boxSelect SideBottom = [4, 8, 7, 3]


cubicVertices (ix, iy, iz) =
    let x, y, z :: GLfloat
        x = fromIntegral ix - 1 
        y = fromIntegral iy - 1
        z = fromIntegral iz - 1
   in
    listArray (1, 8)
     [Vector3 x y (-z),
      Vector3 (x+1) y (-z),
      Vector3 (x+1) (y+1) (-z),
      Vector3 x (y+1) (-z),
      Vector3 x y (-z-1),
      Vector3 (x+1) y (-z-1),
      Vector3 (x+1) (y+1) (-z-1),
      Vector3 x (y+1) (-z-1)]

boxVertices pos block =
      [ [ vs ! s | s <- sel side] | side <- solidSides ]
    where vs = cubicVertices pos
          sel side   = boxSelect side
          solidSides = allSides \\ block


worldQuads world = [boxVertices pos block | (pos, block) <- assocs world ]

prod (Vector3 x1 y1 z1) (Vector3 x2 y2 z2) =
    Vector3
      (y1 * z2 - z1 * y2)
      (z1 * x2 - x1 * z2)
      (x1 * y2 - y1 * x2)


normalize (Vector3 x y z) = Vector3 (x/d) (y/d) (z/d)
  where d = sqrt (x*x+y*y+z*z)

vop op (Vector3 x y z) (Vector3 x' y' z') =
    Vector3 (op x x') (op y y') (op z z')

vdiff = vop (-)
vadd  = vop (+)
vscale (Vector3 x y z) s =  (Vector3 (x*s) (y*s) (z*s))
vneg (Vector3 x y z) = (Vector3 (-x) (-y) (-z))
v2n (Vector3 x y z) = Normal3 x y z
vec2vex (Vector3 x y z) = Vertex3 x y z

drawQuad vs = do
    mapM_ oneQuad vs
  where
    qnormal v1 v2 = normalize (prod v1 v2)
    oneQuad vs@(v1:v2:v3:v4:_) = 
      let  orthoV        = qnormal (vdiff v2 v1) (vdiff v3 v2)
           borderV       = vscale orthoV borderWidth
           bigSide       = map (vadd borderV) vs
                           
      in do
        renderPrimitive Quads $ do
            normal $ v2n orthoV
            mapM_ (vertex . vec2vex) bigSide
            mapM_ (vertex . vec2vex) vs 
        renderPrimitive QuadStrip $ do
                mapM_ (\ (v1, v2) -> do
                         -- putStrLn $ show (v1, (vadd v1 orthoV))
                         vertex (vec2vex v1)
                         vertex (vec2vex (vadd v1 borderV))
                         normal $ v2n $ qnormal (vdiff v2 v1) (vneg orthoV))
                  (zip (vs ++ [v1]) (tail vs ++ [v1, v2]))  
           

drawBoxAtPos world pos = drawQuad $ boxVertices pos block
 where block = world ! pos

drawWorld world pos = do
    --drawQuad $ take 4 $ head $ worldQuads world
    color (Color4 1 1 (1.0 :: GLfloat) 1.0)
    --color (Color4 1.0 1.0 (1.0 :: GLfloat) 1)
    mapM_ drawQuad $ worldQuads world
    --drawBoxAtPos world pos

inWall x = f < 2 * borderWidth  + 0.3
    where x'     =  abs (realToFrac x) + borderWidth
          (_, f) = properFraction x'