{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} module Main where import Control.Monad (unless) import Control.Monad.Except (runExceptT, withExceptT) import Control.Monad.IO.Class (MonadIO (..)) import Data.ByteString (ByteString) import qualified Data.ByteString.Char8 as B8 import Data.Function (fix) import qualified Data.Vector.Unboxed as UV import Graphics.GL import SDL import System.FilePath (()) import Text.Show.Pretty (pPrint) import Typograffiti import Typograffiti.GL vertexShader :: ByteString vertexShader = B8.pack $ unlines [ "#version 330 core" , "uniform mat4 projection;" , "uniform mat4 modelview;" , "in vec2 position;" , "in vec2 uv;" , "out vec2 fuv;" , "void main () {" , " fuv = uv;" , " gl_Position = projection * modelview * vec4(position.xy, 0.0, 1.0);" , "}" ] fragmentShader :: ByteString fragmentShader = B8.pack $ unlines [ "#version 330 core" , "in vec2 fuv;" , "out vec4 fcolor;" , "uniform sampler2D tex;" , "void main () {" , " fcolor = texture(tex, fuv);" , "}" ] -- TODO: Word caching. -- Somehow make it so it isn't bonded to one kind of -- shader. It would be nice if users could write their own -- shaders for this. At the same time, they shouldn't have to. main :: IO () main = do SDL.initializeAll let openGL = defaultOpenGL { glProfile = Core Debug 3 3 } wcfg = defaultWindow { windowInitialSize = V2 640 480 , windowOpenGL = Just openGL , windowResizable = True } w <- createWindow "Typograffiti" wcfg _ <- glCreateContext w let ttfName = "assets" "Lora-Regular.ttf" (either fail return =<<) . runExceptT $ do -- Get the atlas atlas <- withExceptT show $ allocAtlas ttfName (GlyphSizeInPixels 16 16) asciiChars -- Compile our shader program let position = 0 uv = 1 vert <- compileOGLShader vertexShader GL_VERTEX_SHADER frag <- compileOGLShader fragmentShader GL_FRAGMENT_SHADER prog <- compileOGLProgram [ ("position", fromIntegral position) , ("uv", fromIntegral uv) ] [vert, frag] glUseProgram prog -- Get our uniform locations projection <- getUniformLocation prog "projection" modelview <- getUniformLocation prog "modelview" tex <- getUniformLocation prog "tex" -- Generate our string geometry geom <- withExceptT show $ stringTris atlas True "Typograffiti from your head to your feetee." let (ps, uvs) = UV.unzip geom -- Buffer the geometry into our attributes textVao <- withVAO $ \vao -> do withBuffers 2 $ \[pbuf, uvbuf] -> do bufferGeometry position pbuf ps bufferGeometry uv uvbuf uvs return vao atlasVao <- withVAO $ \vao -> do withBuffers 2 $ \[pbuf, uvbuf] -> do let V2 w h = fromIntegral <$> atlasTextureSize atlas bufferGeometry position pbuf $ UV.fromList [ V2 0 0, V2 w 0, V2 w h , V2 0 0, V2 w h, V2 0 h ] bufferGeometry uv uvbuf $ UV.fromList [ V2 0 0, V2 1 0, V2 1 1 , V2 0 0, V2 1 1, V2 0 1 ] return vao -- Set our model view transform let mv :: M44 Float mv = mat4Translate (V3 0 16 0) mv2 :: M44 Float mv2 = mv !*! mat4Translate (V3 0 16 0) -- Forever loop, drawing stuff fix $ \loop -> do events <- fmap eventPayload <$> pollEvents glClearColor 0 0 0 1 glClear GL_COLOR_BUFFER_BIT dsz@(V2 dw dh) <- glGetDrawableSize w glViewport 0 0 (fromIntegral dw) (fromIntegral dh) wsz <- get (windowSize w) let pj :: M44 Float = orthoProjection wsz withBoundTextures [atlasTexture atlas] $ do updateUniform prog projection pj updateUniform prog modelview mv updateUniform prog tex (0 :: Int) drawVAO prog textVao GL_TRIANGLES (fromIntegral $ UV.length ps) updateUniform prog projection pj updateUniform prog modelview mv2 drawVAO prog atlasVao GL_TRIANGLES 6 glSwapWindow w unless (any (== QuitEvent) events) loop