Files
loop/src/Render.hs
T
2021-08-17 19:08:18 +02:00

188 lines
6.5 KiB
Haskell

module Render
where
import Shader
import Shader.Data
--import Shader.Poke
import Data.Preload.Render
import Picture.Data
import Geometry.Data
import Data.Foldable
import Foreign hiding (rotate)
import Graphics.Rendering.OpenGL hiding (Line,translate,scale,imageHeight,Polygon,Color,T)
import qualified SDL
import qualified Data.Vector.Unboxed.Mutable as UMV
import qualified Data.Vector.Mutable as MV
import Control.Monad.Primitive
--import qualified Data.Vector.Fusion.Stream.Monadic as VS
divideSize :: Int -> Size -> Size
divideSize i (Size x y) = Size (div x $ fromIntegral i) (div y $ fromIntegral i)
sizeToTexSize :: Size -> TextureSize2D
sizeToTexSize (Size x y) = TextureSize2D x y
{- | Determine where light is shining in the world. -}
createLightMap
:: RenderData
-> [(Point3,Float,Float)] -- Lights
-> Int -- ^ number of walls
-> Int -- ^ number of silhoutte lines to draw
-> Int -- ^ number of surface triangles to draw
-> IO ()
createLightMap pdata lightPoints nWalls nSils nsurfVs = do
depthFunc $= Just Less
-- clear buffer to full alpha and furthest depth
-- clearColor is specified in preloadRender
clearColor $= Color4 0 0 0 1
clear [ColorBuffer,DepthBuffer]
--colorMask $= Color4 Disabled Disabled Disabled Disabled
cullFace $= Just Back
-- draw walls from your point of view in order to set z buffer
drawShader (_lightingWallShader pdata) nWalls
-- draw foreground elements to set z buffer
drawShader (_lightingSurfaceShader pdata) nsurfVs
-- for each of the lights:
-- stencil out the walls from this light's point of view
-- draw fading lightmap circles on the floor
-- draw fading lightmaps on the walls
depthMask $= Disabled
blendFunc $= (Zero, OneMinusSrcAlpha)
stencilTest $= Enabled
depthFunc $= Just Lequal
--flip VS.mapM_ (VS.fromList lightPoints) $ \(V3 x y z,r,lum) -> do
forM_ lightPoints $ \(V3 x y z,r,lum) -> do
-- stencil out shadows
colorMask $= Color4 Disabled Disabled Disabled Disabled
clear [StencilBuffer]
cullFace $= Just Back
stencilOp $= (OpKeep,OpKeep,OpIncr)
stencilFunc $= (Always, 0, 255)
currentProgram $= Just (_shaderProgram $ _lightingOccludeShader pdata)
uniform (head $ _shaderCustomUnis $ _lightingOccludeShader pdata)
$= Vector3 x y z
drawShader (_lightingOccludeShader pdata) nWalls
currentProgram $= Just (_shaderProgram $ _lightingLineShadowShader pdata)
uniform (head $ _shaderCustomUnis $ _lightingLineShadowShader pdata)
$= Vector3 x y z
drawShader (_lightingLineShadowShader pdata) nSils
cullFace $= Just Front
stencilOp $= (OpKeep,OpKeep,OpDecr)
currentProgram $= Just (_shaderProgram $ _lightingOccludeShader pdata)
drawShader (_lightingOccludeShader pdata) nWalls
currentProgram $= Just (_shaderProgram $ _lightingLineShadowShader pdata)
drawShader (_lightingLineShadowShader pdata) nSils
-- draw geometry surfaces
cullFace $= Just Back
colorMask $= Color4 Disabled Disabled Disabled Enabled
stencilFunc $= (Equal, 0, 255)
currentProgram $= Just (_shaderProgram $ _lightingSurfaceShader pdata)
uniform (head $ _shaderCustomUnis $ _lightingSurfaceShader pdata)
$= Vector3 x y z
uniform (_shaderCustomUnis (_lightingSurfaceShader pdata) !! 1)
$= Vector2 r lum
drawShader (_lightingSurfaceShader pdata) nsurfVs
-- draw wall light "circles"
currentProgram $= Just (_shaderProgram $ _lightingWallShader pdata)
uniform (head $ _shaderCustomUnis $ _lightingWallShader pdata)
$= Vector3 x y z
uniform (_shaderCustomUnis (_lightingWallShader pdata) !! 1)
$= Vector2 r lum
drawShader (_lightingWallShader pdata) nWalls
cullFace $= Nothing
stencilTest $= Disabled
{- | Blur between two framebuffers.
Assumes no depth testing is done -}
pingPongBlur :: RenderData -> IO ()
pingPongBlur pdata = do
bindFramebuffer Framebuffer $= fst (_fbo3 pdata)
textureBinding Texture2D $= Just (snd $ _fbo2 pdata)
drawShader (_bloomBlurShader pdata) 4
bindFramebuffer Framebuffer $= fst (_fbo2 pdata)
textureBinding Texture2D $= Just (snd $ _fbo3 pdata)
drawShader (_bloomBlurShader pdata) 4
-- assumes that vertices have already been sent to the shader
pingPongBetween
:: (FramebufferObject,TextureObject)
-> (FramebufferObject,TextureObject)
-> FullShader
-> IO ()
pingPongBetween (fb1,to1) (fb2,to2) fs = do
bindFramebuffer Framebuffer $= fb2
textureBinding Texture2D $= Just to1
drawShader fs 4
bindFramebuffer Framebuffer $= fb1
textureBinding Texture2D $= Just to2
drawShader fs 4
drawTextureOnFramebuffer
:: FullShader
-> FramebufferObject
-> TextureObject
-> IO ()
drawTextureOnFramebuffer fs fbo to = do
bindFramebuffer Framebuffer $= fbo
textureBinding Texture2D $= Just to
drawShader fs 4
renderFoldable
:: MV.MVector (PrimState IO) FullShader
-> Picture
-> IO ()
renderFoldable shadV struct = do
counts <- UMV.replicate 6 0
pokeBindFoldable shadV counts struct
MV.imapM_ (drawShaderLay 0 counts) shadV
renderFoldableTimed
:: MV.MVector (PrimState IO) FullShader
-> Picture
-> IO Word32
renderFoldableTimed shadV struct = do
pokeStartTicks <- SDL.ticks
counts <- UMV.replicate 6 0
pokeBindFoldable shadV counts struct
MV.imapM_ (drawShaderLay 0 counts) shadV
pokeEndTicks <- SDL.ticks
return $ pokeEndTicks - pokeStartTicks
------------------------------end renderFoldable
renderLayer
:: Int
-> MV.MVector (PrimState IO) FullShader
-> UMV.MVector (PrimState IO) Int
-> IO ()
renderLayer layer shads counts = do
let layerCounts = UMV.slice (layer * 6) 6 counts
MV.imapM_ (drawShaderLay layer layerCounts) shads
pokeTwoOff
:: Ptr Float
-> Int
-> (Float,Float)
-> IO ()
{-# INLINE pokeTwoOff #-}
pokeTwoOff ptr n (x,y) = do
pokeElemOff ptr (2*n+0) x
pokeElemOff ptr (2*n+1) y
pokeThreeOff
:: Ptr Float
-> Int
-> (Float,Float,Float)
-> IO ()
{-# INLINE pokeThreeOff #-}
pokeThreeOff ptr n (x,y,z) = do
pokeElemOff ptr (3*n+0) x
pokeElemOff ptr (3*n+1) y
pokeElemOff ptr (3*n+2) z
pokeFourOff :: Ptr Float -> Int -> (Float,Float,Float,Float) -> IO ()
{-# INLINE pokeFourOff #-}
pokeFourOff ptr n (x,y,z,w) = do
pokeElemOff ptr (4*n+0) x
pokeElemOff ptr (4*n+1) y
pokeElemOff ptr (4*n+2) z
pokeElemOff ptr (4*n+3) w