module Render ( setup , render ) where import Game import MainLoop import Level import Player import Tank import Texture import Model import Control.Monad.State import Data.Fixed import Data.Maybe import Data.Obj3D import Data.Obj3D.GL import Data.Ratio import qualified Data.Map as M import Bindings.GLPng import Graphics.Rendering.OpenGL.GL (($=), GLfloat, GLdouble, Capability(..), Vector3(..)) import Graphics.Rendering.OpenGL.GL.BeginEnd (unsafeRenderPrimitive, PrimitiveMode(..)) import Graphics.Rendering.OpenGL.GL.CoordTrans import Graphics.Rendering.OpenGL.GL.Colors import Graphics.Rendering.OpenGL.GL.Framebuffer (clear, ClearBuffer(..)) import Graphics.Rendering.OpenGL.GL.PerFragment (blend, blendFunc, BlendingFactor(..), depthFunc, ComparisonFunction(..)) import Graphics.Rendering.OpenGL.GL.Texturing.Application (texture) import Graphics.Rendering.OpenGL.GL.Texturing.Objects (textureBinding, TextureObject(..)) import Graphics.Rendering.OpenGL.GL.Texturing.Parameters (Repetition(..), Clamping(..), TextureFilter(..), MinificationFilter, MagnificationFilter) import Graphics.Rendering.OpenGL.GL.Texturing.Specification (TextureTarget(..)) import Graphics.Rendering.OpenGL.GL.VertexArrays (clientState, ClientArrayType(..)) import Graphics.Rendering.OpenGL.GL.VertexSpec getTexture :: Texture -> Main TextureObject getTexture t = do ts <- gets textures let tobj = M.lookup t ts if (isJust tobj) then return $ fromJust tobj else do path <- liftIO $ texturePath t tex <- liftIO $ pngBind path BuildMipmap Alpha (Repeated, Repeat) (Linear', Just Linear') Linear' >>= return . TextureObject . fromIntegral . fst modify $ \state -> state {textures = M.insert t tex ts} return tex getModel :: Model -> Main InterleavedObj getModel m = do ms <- gets models let mobj = M.lookup m ms if (isJust mobj) then return $ fromJust mobj else do path <- liftIO $ modelPath m objmod <- liftIO $ loadObjFile path model <- case objmod of Left error -> fail $ show error Right obj -> liftIO $ makeInterleavedArrays obj modify $ \state -> state {models = M.insert m model ms} return model setup :: Main () setup = do (lw, lh) <- gets (level . gameState) >>= \l -> return (fromIntegral . levelWidth $ l :: GLfloat, fromIntegral . levelHeight $ l :: GLfloat) liftIO $ do blend $= Enabled blendFunc $= (SrcAlpha, OneMinusSrcAlpha) depthFunc $= Just Lequal shadeModel $= Smooth lighting $= Enabled light (Light 0) $= Enabled position (Light 0) $= Vertex4 (-1) (-1) 1 (0 :: GLfloat) colorMaterial $= Just (Front, AmbientAndDiffuse) clientState VertexArray $= Enabled clientState NormalArray $= Enabled clientState TextureCoordArray $= Enabled -- cache textures & models getTexture TextureWood getTexture TextureTank getTexture TextureCannon getTexture TextureBullet getTexture TextureCrosshair getModel ModelTank return () render :: Main () render = do tanklist <- gets $ tanks . gameState bulletlist <- gets $ bullets . gameState playerlist <- gets players textureWood <- getTexture TextureWood textureTank <- getTexture TextureTank textureCannon <- getTexture TextureCannon textureBullet <- getTexture TextureBullet textureCrosshair <- getTexture TextureCrosshair modelTank <- getModel ModelTank (lw, lh) <- gets (level . gameState) >>= \l -> return (fromIntegral . levelWidth $ l :: GLfloat, fromIntegral . levelHeight $ l :: GLfloat) liftIO $ do clear [ColorBuffer, DepthBuffer] depthFunc $= Just Lequal texture Texture2D $= Enabled textureBinding Texture2D $= Just textureWood normal $ Normal3 0 0 (1 :: GLfloat) unsafeRenderPrimitive Quads $ do texCoord $ TexCoord2 (0 :: GLfloat) (0 :: GLfloat) vertex $ Vertex2 0 lh texCoord $ TexCoord2 (lw/2) 0 vertex $ Vertex2 lw lh texCoord $ TexCoord2 (lw/2) (lh/2) vertex $ Vertex2 lw 0 texCoord $ TexCoord2 0 (lh/2) vertex $ Vertex2 (0 :: GLfloat) (0 :: GLfloat) bindInterleavedArrays modelTank forM_ tanklist $ \tank -> unsafePreservingMatrix $ do let x = realToFrac . tankX $ tank y = realToFrac . tankY $ tank rotDir = realToFrac . tankDir $ tank rotAim = realToFrac . tankAim $ tank translate $ Vector3 x y (0 :: GLfloat) rotate rotDir $ Vector3 0 0 (1 :: GLfloat) textureBinding Texture2D $= Just textureTank unsafePreservingMatrix $ do rotate 90 $ Vector3 1 0 (0 :: GLfloat) drawObject modelTank 1 rotate (rotAim-rotDir) $ Vector3 0 0 (1 :: GLfloat) textureBinding Texture2D $= Just textureCannon unsafePreservingMatrix $ do rotate 90 $ Vector3 1 0 (0 :: GLfloat) drawObject modelTank 0 forM_ bulletlist $ \bullet -> unsafePreservingMatrix $ do let x = realToFrac . bulletX $ bullet y = realToFrac . bulletY $ bullet rotDir = realToFrac . bulletDir $ bullet translate $ Vector3 x y (0.2 :: GLfloat) rotate 30 $ Vector3 1 0 (0 :: GLfloat) rotate rotDir $ Vector3 0 0 (1 :: GLfloat) textureBinding Texture2D $= Just textureBullet unsafeRenderPrimitive Quads $ do texCoord $ TexCoord2 (0 :: GLfloat) (0 :: GLfloat) vertex $ Vertex3 (-0.1 :: GLfloat) (-0.1 :: GLfloat) 0 texCoord $ TexCoord2 (0 :: GLfloat) (1 :: GLfloat) vertex $ Vertex3 (-0.1 :: GLfloat) (0.1 :: GLfloat) 0 texCoord $ TexCoord2 (1 :: GLfloat) (1 :: GLfloat) vertex $ Vertex3 (0.1 :: GLfloat) (0.1 :: GLfloat) 0 texCoord $ TexCoord2 (1 :: GLfloat) (0 :: GLfloat) vertex $ Vertex3 (0.1 :: GLfloat) (-0.1 :: GLfloat) 0 depthFunc $= Just Always textureBinding Texture2D $= Just textureCrosshair forM_ playerlist renderPlayer