packages feed

barrier-0.1.0: data-generator.hs

{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE LambdaCase #-}

import System.Environment

import Control.Monad
import Control.Applicative
import Control.Exception

import Foreign.Storable
import Foreign.Marshal
import Foreign.Ptr
import Foreign.C

import Graphics.Rendering.FreeType.Internal
import Graphics.Rendering.FreeType.Internal.Face(glyph, FT_Face)
import Graphics.Rendering.FreeType.Internal.Vector(FT_Vector(FT_Vector))
import Graphics.Rendering.FreeType.Internal.Library(FT_Library)
import Graphics.Rendering.FreeType.Internal.GlyphSlot(advance)
import Graphics.Rendering.FreeType.Internal.PrimitiveTypes(FT_ULong)

import Data.Typeable

data FTError = FTError String CInt deriving(Show, Typeable)
instance Exception FTError

ft :: String -> IO CInt -> IO ()
ft n f = do
    e <- f
    unless (e == 0) $ throwIO (FTError n e)

withFreeType :: (FT_Library -> IO a) -> IO a
withFreeType = bracket bra ket
  where
    bra = alloca $ \p -> ft "Init_FreeType" (ft_Init_FreeType p) >> peek p
    ket = ft "Done_FreeType" . ft_Done_FreeType

withFontFace :: FilePath -> (FT_Face -> IO a) -> FT_Library -> IO a
withFontFace fn m lib = bracket bra ket m
  where
    bra = alloca $ \p -> withCString fn $ \f ->
        ft "New_Face" (ft_New_Face lib f 0 p) >> peek p
    ket = ft "Done_Face" . ft_Done_Face

firstChar :: FT_Face -> IO FT_ULong
firstChar face = fromIntegral <$> ft_Get_First_Char face nullPtr

nextChar :: FT_Face -> FT_ULong -> IO FT_ULong
nextChar face c = ft_Get_Next_Char face c nullPtr

forCharM_ :: FT_Face -> (FT_ULong -> IO ()) -> IO ()
forCharM_ face m = firstChar face >>= go
  where
    go 0 = return ()
    go i = m i >> nextChar face i >>= go


main :: IO ()
main = getArgs >>= \case
    [fontPath] -> withFreeType $ withFontFace fontPath $ \face -> do
        ft "Set_Pixel_Sizes" $ ft_Set_Pixel_Sizes face 0 11
        slot <- peek $ glyph face
        forCharM_ face $ \c -> do
            ft "Load_Char" $ ft_Load_Char face c 0
            FT_Vector x _ <- peek $ advance slot
            case quotRem x 64 of
                (s, 0) -> putStrLn $ show c ++ '\t': show s
                _      -> fail "rem font size"

    _ -> do
        p <- getProgName
        putStrLn $ "Usage: " ++ p ++ " FONT_FILE"