canvas/app/Renderer.hs
2020-05-13 04:21:49 +02:00

241 lines
6.5 KiB
Haskell

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE BangPatterns #-}
module Renderer where
import SDL (($=))
import qualified Graphics.Rendering.OpenGL as GL
import qualified Graphics.GL.Functions as GLRaw (glVertexAttribDivisor)
-- import qualified Graphics.GLUtil as GLU
import qualified Data.Map.Strict as M
import qualified Data.ByteString as BS
import Codec.Picture
import Linear
import Foreign
import Control.Monad (replicateM)
import System.Random
-- internal imports
import Types
initSpriteRenderObjects aggModel = do
quadVAO <- GL.genObjectName
quadVBO <- GL.genObjectName
quadInstances <- GL.genObjectName
GL.bindBuffer GL.ArrayBuffer $= Just quadInstances
withArray aggModel $ \ptr ->
GL.bufferData GL.ArrayBuffer $=
( fromIntegral $ length aggModel * sizeOf (undefined :: Float)
, ptr
, GL.StaticDraw
)
GL.bindBuffer GL.ArrayBuffer $= Nothing
GL.bindBuffer GL.ArrayBuffer $= Just quadVBO
withArray rawVertices $ \ptr ->
GL.bufferData GL.ArrayBuffer $=
( fromIntegral $ length rawVertices * sizeOf (undefined :: Float)
, ptr
, GL.StaticDraw
)
GL.bindVertexArrayObject $= Just quadVAO
GL.vertexAttribArray (GL.AttribLocation 0) $= GL.Enabled
GL.vertexAttribPointer (GL.AttribLocation 0) $=
( GL.ToFloat
, GL.VertexArrayDescriptor 4 GL.Float 0 (nullPtr)
)
mapM_
(\intId -> do
GL.bindBuffer GL.ArrayBuffer $= Just quadInstances
GL.vertexAttribArray (GL.AttribLocation (3 + fromIntegral intId)) $=
GL.Enabled
GL.vertexAttribPointer (GL.AttribLocation (3 + fromIntegral intId)) $=
( GL.ToFloat
, GL.VertexArrayDescriptor
4
GL.Float
(fromIntegral $ 4 * 4 * (sizeOf (undefined :: GL.GLfloat)))
(nullPtr `plusPtr` (intId * 4 * sizeOf (undefined :: GL.GLfloat)))
)
GL.bindBuffer GL.ArrayBuffer $= Nothing
GLRaw.glVertexAttribDivisor (3 + fromIntegral intId) 1
)
([ 0 .. 3 ] :: [Int])
-- GL.bindBuffer GL.ArrayBuffer $= Nothing
GL.bindVertexArrayObject $= Nothing
return (SpriteRenderObjects quadVAO quadVBO)
rawVertices :: [Float]
rawVertices =
[ 0, 1, 0, 1
, 1, 0, 1, 0
, 0, 0, 0, 0
, 0, 1, 0, 1
, 1, 1, 1, 1
, 1, 0, 1, 0
]
initSpriteShaderObjects = do
-- vertexShaderSrc <- BS.readFile "shader/vertex.sl"
-- fragmentShaderSrc <- BS.readFile "shader/fragment.sl"
vertexShader <- createShader VertexShader
fragmentShader <- createShader FragmentShader
vertexShaderSrc <- BS.readFile "shader/vertex.sl"
fragmentShaderSrc <- BS.readFile "shader/fragment.sl"
shaderSourceBS vertexShader $= vertexShaderSrc
shaderSourceBS fragmentShader $= fragmentShaderSrc
compileShader vertexShader
get errors >>= mapM_ (hPutStrLn stderr . ("GL: "++) . show)
vOK <- get (compileStatus vertexShader)
infoLog <- get (shaderInfoLog vertexShader)
unless (null infoLog || infoLog == "\NUL")
(mapM_
putStrLn
["Shader info log for '" ++ filePath ++ "':", infoLog, ""]
)
unless vOK $ do
deleteObjectName vertexShader
ioError (userError "vertexShader compilation failed")
compileShader fragmentShader
get errors >>= mapM_ (hPutStrLn stderr . ("GL: "++) . show)
fOK <- get (compileStatus fragmentShader)
infoLog <- get (shaderInfoLog fragmentShader)
unless (null infoLog || infoLog == "\NUL")
(mapM_
putStrLn
["Shader info log for '" ++ filePath ++ "':", infoLog, ""]
)
unless fOK $ do
deleteObjectName fragmentShader
ioError (userError "fragmentShader compilation failed")
-- shaderProgram <- GLU.simpleShaderProgramBS vertexShaderSrc fragmentShaderSrc
shaderProgram <- createProgram
attachShaders shaderProgram $= [vertexShader, fragmentShader]
linkProgram shaderProgram
get errors >>= mapM_ (hPutStrLn stderr . ("GL: "++) . show)
return (SpriteShaderObjects shaderProgram)
initSpriteTextureObjects
:: [(String, FilePath)]
-> IO (M.Map AssetId (GL.TextureObject, V2 Int))
initSpriteTextureObjects lookupList = do
M.fromList <$> mapM
(\(name, fp) -> do
-- texture <- Gl.genObjectName
-- GL.bindBuffer GL.ArrayBuffer $= Just texture
-- withArray rawVertices $ \ptr ->
-- GL.bufferData GL.ArrayBuffer $=
-- ( fromIntegral $ length rawVertices * sizeof (0 :: Float)
-- , ptr
-- , GL.StaticDraw
-- )
-- GL.vertexAttribPointer (GL.AttribLocation 1) $=
-- ( GL.ToFloat
-- , GL.VertexArrayDescriptor 2 GL.Float 0 (plusPtr nullPtr 0)
-- )
ts <- loadTex fp
return (name, ts)
)
lookupList
loadTex :: FilePath -> IO (GL.TextureObject, V2 Int)
loadTex fp = do
t <- either error id <$> GLU.readTexture fp
img <- convertRGBA8 <$> either error id <$> readImage fp
let size = V2 (imageWidth img) (imageHeight img)
return (t, size)
loadSprites
:: Int
-> IO (AssetDetails SpriteRenderObjects SpriteShaderObjects Sprite)
loadSprites amount = do
let lookups =
[ ("lynx", "assets/img/lynx.png")
]
-- positions =
-- [ (V2 0 0)
-- ]
GL.texture GL.Texture2D $= GL.Enabled
GLU.texture2DWrap $= (GL.Repeated, GL.ClampToEdge)
GL.textureFilter GL.Texture2D $= ((GL.Nearest, Just GL.Nearest), GL.Nearest)
GL.textureWrapMode GL.Texture2D GL.S $= (GL.Repeated, GL.Repeat)
GL.textureWrapMode GL.Texture2D GL.T $= (GL.Repeated, GL.Repeat)
textObj <- initSpriteTextureObjects lookups
positions <- replicateM amount $ do
x <- randomRIO (-1, 1)
y <- randomRIO (-1, 1)
return (V2 x y)
sizes <- mapM
(\origSize -> do
scale <- randomRIO (0.1, (2 :: Float))
return (fmap (scale *) $
(fmap fromIntegral origSize) / (V2 980 540))
)
(replicate amount (snd $ snd $ head $ M.assocs textObj))
let aggModel :: [Float]
!aggModel = foldl
(\acc (pos@(V2 px py), size@(V2 sx sy)) ->
let qMatrix =
[ sx, 0, 0, 0
, 0, sy, 0, 0
, 0, 0, 1, 0
, fromIntegral px, fromIntegral py, 0, 1
]
in (acc ++ qMatrix)
)
[]
(zip positions sizes)
vertObj <- initSpriteRenderObjects aggModel
shadObj <- initSpriteShaderObjects
return AssetDetails
{ adVertObj = vertObj
, adShadObj = shadObj
, adTextObj = M.fromList $ map (\(k, v) -> (k, fst v)) (M.assocs textObj)
, adDataObj = M.fromList $
map
(\(k, v) ->
( k
, map (\pos -> Sprite pos (snd v)) positions
)
)
(M.assocs textObj)
}