summaryrefslogtreecommitdiff
path: root/UtilGL.hs
blob: 22347c37ec12a0aa0b3da98b32e611ff7bcfcda0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
{-# LANGUAGE QuasiQuotes #-}
module UtilGL where

import Control.Concurrent (threadDelay, yield)
import Control.Monad
import Data.Bool
import Data.ByteString (ByteString)
import Data.Maybe
import Data.IORef
import System.IO
import System.Directory
import System.Process
import System.Exit
import Graphics.Rendering.OpenGL as GL
import Language.Haskell.TH
import Language.Haskell.TH.Quote
import Text.Printf

data Env = Env
    { mycolor :: GLfloat -> GLfloat -> GLfloat -> GLfloat -> Color4 GLfloat
    }


cbDebugMessage :: GL.DebugMessage -> IO ()
cbDebugMessage (DebugMessage src typ mid severity msg) = do
    let src' = take 14 $ drop 11 $ show src ++ repeat ' '
    hPutStrLn stderr $ concat [src', ": ", msg]

notify :: String -> IO ()
notify msg = do
    cb <- get GL.debugMessageCallback
    (maybe cbDebugMessage (const GL.debugMessageInsert) cb)
        $ DebugMessage DebugSourceApplication DebugTypeMarker (DebugMessageID 0) DebugSeverityNotification msg

invertedColor4 :: Num a => a -> a -> a -> a -> Color4 a
invertedColor4 r g b a = Color4 (1-r) (1-g) (1-b) a

initGL :: IO Env
initGL = do
    GL.debugOutput $=! Enabled
    dbref <- newIORef Nothing
    let setDebugMessageCallback _ = do
            writeIORef dbref $ Just cbDebugMessage
            hPutStrLn stderr "Application   : Debug log enabled."
    GL.debugMessageCallback $=! Just setDebugMessageCallback
    GL.debugMessageInsert
        $ DebugMessage DebugSourceApplication DebugTypeMarker (DebugMessageID 0) DebugSeverityNotification
                       "Debug log test: timeout."
    stamp <- fmap (++ "/.config/inverted") getHomeDirectory
    mycolor <- bool Color4 invertedColor4 <$> doesFileExist stamp
    yield
    threadDelay 10000
    dbc <- readIORef dbref
    GL.debugMessageCallback $=! dbc
    notify "Initialized."
    return Env { mycolor = mycolor }

makeShader :: ShaderType -> ByteString -> IO (Maybe Shader)
makeShader typ src = do
    shader <- GL.createShader typ
    GL.shaderSourceBS shader $= src
    GL.compileShader shader
    stv <- get (GL.compileStatus shader)
    nfo <- get (GL.shaderInfoLog shader)
    when (not stv) $ hPutStrLn stderr nfo
    return $ guard stv >> Just shader

makeProgram :: Maybe Shader -> Maybe Shader -> IO (Maybe Program)
makeProgram vshader fshader = mkP $ catMaybes [vshader,fshader]
 where
    mkP [vshader,fshader] = do
        prog <- GL.createProgram
        GL.attachShader prog vshader
        GL.attachShader prog fshader
        GL.linkProgram prog
        stp <- get (GL.linkStatus prog)
        nfo <- get(GL.programInfoLog prog)
        when (not stp) $ hPutStrLn stderr nfo
        return $ guard stp >> Just prog
    mkP _ = return Nothing



unsupported :: Monad m => p -> m a
unsupported _ = fail "not supported."

qw :: QuasiQuoter
qw = QuasiQuoter f unsupported unsupported unsupported
 where unsupported _ = fail "not supported."
       f x = return $ ListE $ map (LitE . StringL) $ words x

str :: QuasiQuoter
str  = QuasiQuoter {
        quoteExp = stringE,
        quotePat = unsupported,
        quoteDec = unsupported,
        quoteType = unsupported
       }

glslVertex :: QuasiQuoter
glslVertex = QuasiQuoter glslE unsupported unsupported unsupported
 where
    glslE xs = do
        let _packUtf8 = VarE $ mkName "packUtf8"
            _string   = LitE $ StringL xs
        (code,e) <- runIO $ do
            (gotvalidator,_,_) <- readCreateProcessWithExitCode (shell "which glslangValidator") ""
            if gotvalidator == ExitSuccess
              then do
                writeFile "/tmp/glsl-shader.vert" xs
                (code,out,err) <- readCreateProcessWithExitCode (shell "glslangValidator /tmp/glsl-shader.vert") ""
                return $ (code, out ++ err ++ unlines (zipWith (\n s ->printf "%4d %s" n s ::String) ([1..]::[Int]) (lines xs)))
              else
                return (ExitSuccess, "")
        when (code /= ExitSuccess) $ do
            fail e
        return $ AppE _packUtf8 _string

glslFragment :: QuasiQuoter
glslFragment = QuasiQuoter glslE unsupported unsupported unsupported
 where
    glslE xs = do
        let _packUtf8 = VarE $ mkName "packUtf8"
            _string   = LitE $ StringL xs
        (code,e) <- runIO $ do
            (gotvalidator,_,_) <- readCreateProcessWithExitCode (shell "which glslangValidator") ""
            if gotvalidator == ExitSuccess
              then do
                (pth,h) <-openTempFile "/tmp" "glsl.frag"
                hPutStr h xs
                hClose h
                (code,out,err) <- readCreateProcessWithExitCode (shell $ "glslangValidator "++pth) ""
                return $ (code, out ++ err ++ unlines (zipWith (\n s ->printf "%4d %s" n s ::String) ([1..]::[Int]) (lines xs)))
              else
                return (ExitSuccess, "")
        when (code /= ExitSuccess) $ do
            fail e
        return $ AppE _packUtf8 _string