M src/Typograffiti/Atlas.hs => src/Typograffiti/Atlas.hs +53 -33
@@ 15,6 15,7 @@ module Typograffiti.Atlas where
import Control.Monad
import Control.Monad.Except (MonadError (..))
import Control.Monad.IO.Class
+import Data.Maybe (fromMaybe)
import Data.IntMap (IntMap)
import qualified Data.IntMap as IM
import Data.Vector.Unboxed (Vector)
@@ 179,45 180,64 @@ allocAtlas
allocAtlas fontFilePath gs str = do
e <- liftIO $ runFreeType $ do
fce <- newFace fontFilePath
- case gs of
- GlyphSizeInPixels w h -> setPixelSizes fce w h
- GlyphSizeByChar (CharSize w h dpix dpiy) -> setCharSize fce w h dpix dpiy
-
- (amMap, am) <- foldM (measure fce 512 renderGlyph) (mempty, emptyAM) str
-
- let V2 w h = amWH am
- xymap :: IntMap (V2 Int)
- xymap = amXY <$> amMap
-
- t <- liftIO $ do
- t <- allocAndActivateTex GL_TEXTURE0
- glPixelStorei GL_UNPACK_ALIGNMENT 1
- withCString (replicate (w * h) $ toEnum 0) $
- glTexImage2D GL_TEXTURE_2D 0 GL_RED (fromIntegral w) (fromIntegral h)
- 0 GL_RED GL_UNSIGNED_BYTE . castPtr
- return t
-
- lib <- getLibrary
- atlas <- foldM (texturize xymap) (emptyAtlas lib fce t) str
-
- glGenerateMipmap GL_TEXTURE_2D
- glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_S GL_REPEAT
- glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_T GL_REPEAT
- glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER GL_LINEAR
- glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER GL_LINEAR
- glBindTexture GL_TEXTURE_2D 0
- glPixelStorei GL_UNPACK_ALIGNMENT 4
- return
- atlas{ atlasTextureSize = V2 w h
- , atlasGlyphSize = gs
- , atlasFilePath = fontFilePath
- }
+ allocRichAtlas fontFilePath fce (Just gs) renderGlyph str
either
(throwError . TypograffitiErrorFreetype "cannot alloc atlas")
(return . fst)
e
+-- | Allocate a new 'Atlas'.
+-- When creating a new 'Atlas' you must pass all the characters that you
+-- might need during the life of the 'Atlas'. Character texturization only
+-- happens once.
+allocRichAtlas
+ :: String
+ -- ^ Key identifying this altered font.
+ -> FT_Face
+ -- ^ Raw FreeType2-loaded font.
+ -> Maybe GlyphSize
+ -- ^ Size of glyphs in this Atlas, callers may configure this externally.
+ -> (FT_GlyphSlot -> FreeTypeIO ())
+ -- ^ Callback for mutating each glyph loaded from the given font.
+ -> String
+ -- ^ The characters to include in this 'Atlas'.
+ -> FreeTypeIO Atlas
+allocRichAtlas key fce gs cb str = do
+ case gs of
+ Just (GlyphSizeInPixels w h) -> setPixelSizes fce w h
+ Just (GlyphSizeByChar (CharSize w h dpix dpiy)) -> setCharSize fce w h dpix dpiy
+ Nothing -> return ()
+
+ (amMap, am) <- foldM (measure fce 512 cb) (mempty, emptyAM) str
+
+ let V2 w h = amWH am
+ xymap :: IntMap (V2 Int)
+ xymap = amXY <$> amMap
+
+ t <- liftIO $ do
+ t <- allocAndActivateTex GL_TEXTURE0
+ glPixelStorei GL_UNPACK_ALIGNMENT 1
+ withCString (replicate (w * h) $ toEnum 0) $
+ glTexImage2D GL_TEXTURE_2D 0 GL_RED (fromIntegral w) (fromIntegral h)
+ 0 GL_RED GL_UNSIGNED_BYTE . castPtr
+ return t
+
+ lib <- getLibrary
+ atlas <- foldM (texturize xymap) (emptyAtlas lib fce t) str
+
+ glGenerateMipmap GL_TEXTURE_2D
+ glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_S GL_REPEAT
+ glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_T GL_REPEAT
+ glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MAG_FILTER GL_LINEAR
+ glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER GL_LINEAR
+ glBindTexture GL_TEXTURE_2D 0
+ glPixelStorei GL_UNPACK_ALIGNMENT 4
+ return
+ atlas{ atlasTextureSize = V2 w h
+ , atlasGlyphSize = fromMaybe (GlyphSizeInPixels 0 0) gs
+ , atlasFilePath = key
+ }
-- | Releases all resources associated with the given 'Atlas'.
freeAtlas :: MonadIO m => Atlas -> m ()
M src/Typograffiti/Store.hs => src/Typograffiti/Store.hs +38 -0
@@ 28,6 28,7 @@ import Linear
import Typograffiti.Atlas
import Typograffiti.Cache
import Typograffiti.Glyph
+import Typograffiti.Utils (FT_Face, FT_GlyphSlot, FreeTypeIO(..))
-- | A pre-rendered bit of text, ready to display given
@@ 71,6 72,8 @@ getTextRendering
-> FilePath
-- ^ The path to the font to use
-- for rendering.
+ -- Or alternatively: the `key`
+ -- identifying a registered font.
-> GlyphSize
-- ^ The size of the font glyphs.
-> String
@@ 149,3 152,38 @@ allocFont store file sz = do
$ putTMVar mvar
$ s{ textRenderingDataFontMap = M.insert (file, sz) font fontmap }
return font
+
+registerFont
+ :: Layout t
+ => FontStore t
+ -> String
+ -> FT_Face
+ -> Maybe GlyphSize
+ -> (FT_GlyphSlot -> FreeTypeIO ())
+ -> FreeTypeIO (Font t)
+-- | Register an externally-loaded font under a given key (low-level API)
+-- Allows registering a callback for mutating glyphs prior
+-- to being composited into place on the GPU, which is
+-- responsible for ensuring Typograffiti has a bitmap to composite.
+registerFont store key fce sz cb = do
+ let mvar = unFontStore store
+ s <- liftIO $ atomically $ takeTMVar mvar
+ atlas <-
+ allocRichAtlas
+ key
+ fce
+ sz
+ cb
+ $ S.toList
+ $ textRenderingDataCharSet s
+ let fontmap = textRenderingDataFontMap s
+ font = Font
+ { fontAtlas = atlas
+ , fontWordCache = mempty
+ }
+ let sz' = atlasGlyphSize atlas
+ liftIO
+ $ atomically
+ $ putTMVar mvar
+ $ s{ textRenderingDataFontMap = M.insert (key, sz') font fontmap }
+ return font