241 lines
6.5 KiB
Haskell
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)
|
|
}
|