minitypeset-opengl-0.3.0.0: src/Graphics/Rendering/MiniTypeset/Render.hs
-- | Low-level rendering.
--
-- You shouldn't normally need to use this directly,
-- though boxes can be useful for highlighting.
{-# LANGUAGE BangPatterns #-}
module Graphics.Rendering.MiniTypeset.Render where
--------------------------------------------------------------------------------
import Data.Word
import Data.Char
import GHC.Float
import Control.Monad
import Data.IORef
import Graphics.Rendering.OpenGL as GL
import Graphics.Rendering.TrueType.STB
import Graphics.Rendering.MiniTypeset.Common
import Graphics.Rendering.MiniTypeset.Box
import Graphics.Rendering.MiniTypeset.FontTexture
import Graphics.Rendering.MiniTypeset.MultiFont
--------------------------------------------------------------------------------
setCol :: Col -> IO ()
setCol !(Col r g b) = color (Color3 r g b)
setColAlpha :: Col -> Float -> IO ()
setColAlpha !(Col r g b) !a = color (Color4 r g b a)
--------------------------------------------------------------------------------
-- * Render boxes
renderQuad :: Quad -> IO ()
renderQuad (Quad (x1,y1) (x2,y2)) =
renderPrimitive Quads $ do
vertex (Vertex2 x1 y1)
vertex (Vertex2 x2 y1)
vertex (Vertex2 x2 y2)
vertex (Vertex2 x1 y2)
-- | Renders the outer box as a quad
renderOuterBoxQuad :: AbsBox -> IO ()
renderOuterBoxQuad = renderQuad . absboxOuterQuad
-- | Renders the inner box as a quad
renderInnerBoxQuad :: AbsBox -> IO ()
renderInnerBoxQuad = renderQuad . absboxInnerQuad
-- | Renders the gap quad (useful for debugging)
renderGapBoxQuad :: AbsBox -> IO ()
renderGapBoxQuad = renderQuad . absboxGapQuad
-- | Renders the bounding box quad (useful for debugging)
renderBoundingBoxQuad :: AbsBox -> IO ()
renderBoundingBoxQuad = renderQuad . absboxBoundingQuad
--------------------------------------------------------------------------------
-- * Render box outlines
renderQuadOutline :: Quad -> IO ()
renderQuadOutline (Quad (x1,y1) (x2,y2)) =
renderPrimitive LineLoop $ do
vertex (Vertex2 x1 y1)
vertex (Vertex2 x2 y1)
vertex (Vertex2 x2 y2)
vertex (Vertex2 x1 y2)
-- | Renders the outer box as a quad
renderOuterBoxOutline :: AbsBox -> IO ()
renderOuterBoxOutline = renderQuadOutline . absboxOuterQuad
-- | Renders the inner box as a quad
renderInnerBoxOutline :: AbsBox -> IO ()
renderInnerBoxOutline = renderQuadOutline . absboxInnerQuad
-- | Renders the gap quad (useful for debugging)
renderGapBoxOutline :: AbsBox -> IO ()
renderGapBoxOutline = renderQuadOutline . absboxGapQuad
-- | Renders the bounding box quad (useful for debugging)
renderBoundingBoxOutline :: AbsBox -> IO ()
renderBoundingBoxOutline = renderQuadOutline . absboxBoundingQuad
--------------------------------------------------------------------------------
-- * Render lines
-- TODO: finetune line rendering (retina display, antialising, position hinting based on width, etc...)
renderLine :: Col -> Double -> Pos -> Pos -> IO ()
renderLine !col !lwidth !(Pos x1 y1) !(Pos x2 y2) = do
setCol col
lineWidth $= double2Float lwidth
let hwidth = 0.5 * lwidth
renderPrimitive Lines $ do
vertex $ Vertex2 (dround x1) (dround y1)
vertex $ Vertex2 (dround x2) (dround y2)
where
dround :: Double -> Double
dround !x = fromIntegral (round x :: Int)
--------------------------------------------------------------------------------
-- * Render characters
-- | Renders a multifont glyph with the given color.
renderMFG :: Pos -> Col -> MultiFontGlyph -> IO ()
renderMFG !pos !col !(MFG ftex bufloc) = do
setCol col
renderChar' pos ftex bufloc
--------------------------------------------------------------------------------
-- | Renders a single character. Note: the position will be the position
-- of the left end of the baseline of the character, not the top-left corner!
--
-- Returns the horizontal advancement.
--
renderCharAt :: Pos -> FontTexture -> Char -> IO Double
renderCharAt pos ftex ch = do
bufloc <- lookupFontTexture ftex ch
renderChar' pos ftex bufloc
let adv = advanceWidth (_locHM bufloc)
return $ float2Double adv
renderCharAt_ :: Pos -> FontTexture -> Char -> IO ()
renderCharAt_ pos ftex ch = void $ renderCharAt pos ftex ch
--------------------------------------------------------------------------------
renderChar' :: Pos -> FontTexture -> BufLoc -> IO ()
renderChar' !pos@(Pos x0 y0) !ftex !bufloc = do
bufs <- readIORef (_ftexBufs ftex)
let texBuf@(TexBuf texobj texsiz) = bufs!!(_locBufIdx bufloc)
textureBinding Texture2D $=! Just texobj
let (wi,hi) = _locBufSiz bufloc
(s,t) = _locBufXY bufloc
(p,q) = _locBufOfs bufloc
-- lsb = leftSideBearing (_locHM bufloc) -- already included in the offset?
(x,y) = (x0 + fromIntegral p , y0 + fromIntegral q) -- tmp?
wf = fromIntegral wi :: Double
hf = fromIntegral hi :: Double
texture Texture2D $=! Enabled
blend $=! Enabled
blendFunc $=! (SrcAlpha,OneMinusSrcAlpha)
let (texw,texh) = _ftexBufSize ftex
ftexw = fromIntegral texw :: Double
ftexh = fromIntegral texh :: Double
fs, ft :: Int -> Double
fs !j = (fromIntegral j + 1.0) / ftexw
ft !i = (fromIntegral i + 1.0) / ftexh
let g :: Double -> Double
g x = fromIntegral (round x :: Int)
let tc s t = texCoord (TexCoord2 (fs s) (ft t))
vt x y = vertex (Vertex2 (g x) (g y))
renderPrimitive Quads $ do
tc s t ; vt x y
tc (s+wi) t ; vt (x+wf) y
tc (s+wi) (t+hi) ; vt (x+wf) (y+hf)
tc s (t+hi) ; vt x (y+hf)
blend $=! Disabled
texture Texture2D $=! Disabled
return ()
--------------------------------------------------------------------------------