FTGL-1.0: Graphics/Rendering/FTGL.hs
{-# INCLUDE <FTGL/ftgl.h> #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# OPTIONS_GHC -O2 -fglasgow-exts #-}
-- | * Author: Jefferson Heard (jefferson.r.heard at gmail.com)
--
-- * Copyright 2008 Renaissance Computing Institute < http://www.renci.org >
--
-- * License: GNU LGPL
--
-- * Compatibility GHC (I could change the data declarations to not be empty and that would make it more generally compatible, I believe)
--
-- * Description:
--
-- Use FreeType 2 Fonts in OpenGL. Requires the FTGL library and FreeType libraries.
-- available at < http://ftgl.wiki.sourceforge.net/ > . The most important functions for
-- everyday use are renderFont and the create*Font family of functions. To render a
-- simple string inside OpenGL, assuming you have OpenGL initialized and a current
-- pen color, all you need is:
--
-- > do font <- createTextureFont "Font.ttf"
-- > setFontFaceSize font 24 72
-- > renderFont font "Hello world!"
--
-- Fonts are rendered so that a single point is an OpenGL unit, and a point is 1:72 of
-- an inch.
module Graphics.Rendering.FTGL (
createBitmapFont
, createBufferFont
, createOutlineFont
, createPixmapFont
, createPolygonFont
, createTextureFont
, createExtrudeFont
, Glyph
, Font
, Layout
, createSimpleLayout
, getLayoutFont
, setLayoutFont
, getLayoutAlignment
, setLayoutAlignment
, getLayoutLineLength
, setLayoutLineLength
, setLayoutLineSpacing
, destroyFont
, attachData
, attachFile
, setFontCharMap
, setFontFaceSize
, getFontFaceSize
, setFontFaceDepth
, getFontBBox
, getFontAdvance
, renderFont
, getFontError
, destroyLayout
, renderLayout
, getLayoutError
, RenderMode(All,Back,Front,Side)
, TextAlignment(AlignLeft,AlignRight,AlignCenter,Justify)
)
where
import Foreign (unsafePerformIO)
import Foreign.C
import Foreign.Ptr
import Foreign.Marshal.Alloc
import Foreign.Marshal.Array
import qualified Graphics.Rendering.OpenGL.GL as GL
import Control.Applicative ((<$>))
foreign import ccall unsafe "ftglCreateBitmapFont" fcreateBitmapFont :: CString -> IO Font
foreign import ccall unsafe "ftglCreateBufferFont" fcreateBufferFont :: CString -> IO Font
foreign import ccall unsafe "ftglCreateOutlineFont" fcreateOutlineFont :: CString -> IO Font
foreign import ccall unsafe "ftglCreatePixmapFont" fcreatePixmapFont :: CString -> IO Font
foreign import ccall unsafe "ftglCreatePolygonFont" fcreatePolygonFont :: CString -> IO Font
foreign import ccall unsafe "ftglCreateTextureFont" fcreateTextureFont :: CString -> IO Font
foreign import ccall unsafe "ftglCreateExtrudeFont" fcreateExtrudeFont :: CString -> IO Font
foreign import ccall unsafe "ftglCreateSimpleLayout" createSimpleLayout :: IO Layout
foreign import ccall unsafe "ftglSetLayoutFont" setLayoutFont :: Layout -> Font -> IO ()
foreign import ccall unsafe "ftglGetLayoutFont" fgetLayoutFont :: Layout -> IO Font
foreign import ccall unsafe "ftglSetLayoutLineLength" setLayoutLineLength :: Layout -> CFloat -> IO ()
foreign import ccall unsafe "ftglGetLayoutLineLength" fgetLayoutLineLength :: Layout -> IO CFloat
foreign import ccall unsafe "ftglSetLayoutAlignment" setLayoutAlignment :: Layout -> CInt -> IO ()
foreign import ccall unsafe "ftglGetLayoutAlignement" fgetLayoutAlignment :: Layout -> IO CInt
foreign import ccall unsafe "ftglSetLayoutLineSpacing" setLayoutLineSpacing :: Layout -> CFloat -> IO ()
foreign import ccall unsafe "ftglDestroyFont" destroyFont :: Font -> IO ()
foreign import ccall unsafe "ftglAttachFile" fattachFile :: Font -> CString -> IO ()
foreign import ccall unsafe "ftglAttachData" attachData :: Font -> Ptr () -> IO ()
foreign import ccall unsafe "ftglSetFontCharMap" setFontCharMap :: Font -> CInt -> IO ()
foreign import ccall unsafe "ftglGetFontCharMapCount" fgetFontCharMapCount :: Font -> IO CInt
foreign import ccall unsafe "ftglGetFontCharMapList" fgetFontCharMapList :: Font -> IO (Ptr CInt)
foreign import ccall unsafe "ftglSetFontFaceSize" fsetFontFaceSize :: Font -> CInt -> CInt -> IO CInt
foreign import ccall unsafe "ftglGetFontFaceSize" fgetFontFaceSize :: Font -> IO CInt
foreign import ccall unsafe "ftglSetFontDepth" setFontFaceDepth :: Font -> CInt -> IO ()
foreign import ccall unsafe "ftglSetFontOutset" setFontOutset :: Font -> CInt -> CInt -> IO ()
foreign import ccall unsafe "ftglGetFontBBox" fgetFontBBox :: Font -> CString -> Ptr CFloat -> IO ()
foreign import ccall unsafe "ftglGetFontAdvance" fgetFontAdvance :: Font -> CString -> IO CFloat
foreign import ccall unsafe "ftglRenderFont" frenderFont :: Font -> CString -> CInt -> IO ()
foreign import ccall unsafe "ftglGetFontError" fgetFontError :: Font -> IO CInt
foreign import ccall unsafe "ftglDestroyLayout" destroyLayout :: Layout -> IO ()
foreign import ccall unsafe "ftglRenderLayout" renderLayout_foreign :: Layout -> CString -> IO ()
foreign import ccall unsafe "ftglGetLayoutError" fgetLayoutError :: Layout -> IO CInt
setFontFaceSize :: Font -> Int -> Int -> IO CInt
setFontFaceSize f s x = fsetFontFaceSize f (fromIntegral s) (fromIntegral x)
-- | Whether or not in polygonal or extrusion mode, the font will render equally front and back
data RenderMode = Front | Back | Side | All
-- | In a Layout directed render, the layout mode of the text
data TextAlignment = AlignLeft | AlignCenter | AlignRight | Justify
marshalRenderMode :: RenderMode -> CInt
marshalRenderMode Front = 0x0001
marshalRenderMode Back = 0x0002
marshalRenderMode Side = 0x004
marshalRenderMode All = 0xffff
marshalTextAlignment :: TextAlignment -> CInt
marshalTextAlignment AlignLeft = 0
marshalTextAlignment AlignCenter = 1
marshalTextAlignment AlignRight = 2
marshalTextAlignment Justify = 3
readTextAlignment :: CInt -> TextAlignment
readTextAlignment 0 = AlignLeft
readTextAlignment 1 = AlignCenter
readTextAlignment 2 = AlignRight
readTextAlignment 3 = Justify
-- | An opaque type encapsulating a glyph in C. Currently the glyph functions are unimplemented in Haskell.
data Glyph_Opaque
-- | An opaque type encapsulating a font in C.
data Font_Opaque
-- | An opaque type encapsulating a layout in C
data Layout_Opaque
type Glyph = Ptr Glyph_Opaque
type Font = Ptr Font_Opaque
type Layout = Ptr Layout_Opaque
-- | Create a bitmapped version of a TrueType font. Bitmapped versions will not
-- | respond to matrix transformations, but rather must be transformed using the
-- | raster positioning functions in OpenGL
createBitmapFont :: String -> IO Font
createBitmapFont file = withCStringLen file $ \(p,l) -> fcreateBitmapFont p
-- | Create a buffered version of a TrueType font. This stores the entirety of
-- | a string in a texture, "buffering" it before rendering. Very fast if you
-- | will be repeatedly rendering the same strings over and over.
createBufferFont :: String -> IO Font
createBufferFont file = withCStringLen file $ \(p,l) -> fcreateBufferFont p
-- | Create an outline version of a TrueType font. This uses actual geometry
-- | and will scale independently without loss of quality. Faster than polygons
-- | but slower than texture or buffer fonts.
createOutlineFont :: String -> IO Font
createOutlineFont file = withCStringLen file $ \(p,l) -> fcreateOutlineFont p
-- | Create a pixmap version of a TrueType font. Higher quality than the bitmap
-- | font without losing any performance. Use this if you don't mind using
-- | set and get RasterPosition.
createPixmapFont :: String -> IO Font
createPixmapFont file = withCStringLen file $ \(p,l) -> fcreatePixmapFont p
-- | Create polygonal display list fonts. These scale independently without
-- | losing quality, unlike texture or buffer fonts, but can be impractical
-- | for large amounts of text because of the high number of polygons needed.
-- | Additionally, they do not, unlike the textured fonts, create artifacts
-- | within the square formed at the edge of each character.
createPolygonFont :: String -> IO Font
createPolygonFont file = withCStringLen file $ \(p,l) -> fcreatePolygonFont p
-- | Create textured display list fonts. These can scale somewhat well,
-- | but lose quality quickly. They are much faster than polygonal fonts,
-- | though, so are suitable for large quantities of text. Especially suited
-- | well to text that changes with most frames, because it doesn't incur the
-- | (normally helpful) overhead of buffering.
createTextureFont :: String -> IO Font
createTextureFont file = withCStringLen file $ \(p,l) -> fcreateTextureFont p
-- | Create a 3D extruded font. This is the only way of creating 3D fonts
-- | within FTGL. Could be fun to use a geometry shader to get different
-- | effects by warping the otherwise square nature of the font. Polygonal.
-- | Scales without losing quality. Slower than all other fonts.
createExtrudeFont :: String -> IO Font
createExtrudeFont file = withCStringLen file $ \(p,l) -> fcreateExtrudeFont p
-- | Get the embedded font from the Layout
getLayoutFont f = unsafePerformIO $ fgetLayoutFont f
-- | Get the line length in points (1:72in) of lines in the layout
getLayoutLineLength :: Layout -> Float
getLayoutLineLength f = realToFrac . unsafePerformIO $ fgetLayoutLineLength f
-- | Get the alignment of text in this layout.
getLayoutAlignment :: Layout -> TextAlignment
getLayoutAlignment f = readTextAlignment . unsafePerformIO $ fgetLayoutAlignment f
-- | Get the number of characters loaded into the current charmap for the font.
getFontCharMapCount :: Font -> Int
getFontCharMapCount f = fromIntegral . unsafePerformIO $ fgetFontCharMapCount f
-- | Get the different character mappings available in this font.
getFontCharMapList f = unsafePerformIO $ fgetFontCharMapList f
-- | Get the current font face size in points.
getFontFaceSize :: Font -> Int
getFontFaceSize f = fromIntegral . unsafePerformIO $ fgetFontFaceSize f
-- | Get any errors associated with loading a font. FIXME return should be a type, not an Int.
getFontError :: Font -> Int
getFontError f = fromIntegral . unsafePerformIO $ fgetFontError f
-- | Attach a metadata file to a font.
attachFile :: Font -> String -> IO ()
attachFile font str = withCString str $ \p -> fattachFile font p
-- | Get the horizontal span of a string of text using the current font. Input as the xcoord
-- | in any translate operation
getFontAdvance :: Font -> String -> Float
getFontAdvance font str = realToFrac . unsafePerformIO $ withCString str $ \p -> fgetFontAdvance font p
-- | Render a string of text in the current font.
renderFont :: Font -> String -> RenderMode -> IO ()
renderFont font str mode = withCString str $ \p -> do
frenderFont font p (marshalRenderMode mode)
-- | Get the text extents of a string as a list of (lower-left,lower-right,upper-left,upper-right)
getFontBBox :: Font -> String -> [Float]
getFontBBox f s = unsafePerformIO $
allocaBytes 16 $ \pf ->
withCString s $ \ps -> do
fgetFontBBox f ps pf
map realToFrac <$> peekArray 4 pf
-- | Get any errors associated with a layout.
getLayoutError f = unsafePerformIO $ fgetLayoutError f
-- | Render a string of text within a layout.
renderLayout layout str = withCString str $ \strPtr -> do renderLayout_foreign layout strPtr