FTGL-1.2: 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
where
import Foreign (unsafePerformIO)
import Foreign.C
import Foreign.Ptr
import Foreign.Marshal.Alloc
import Foreign.Marshal.Array
import Data.Bits
import Data.Char (ord)
import qualified Graphics.Rendering.OpenGL.GL as GL
import Control.Applicative ((<$>))
foreign import ccall unsafe "ftglCreateBitmapFont" fcreateBitmapFont :: CString -> IO Font
-- | 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 = withCString file $ \p -> fcreateBitmapFont p
foreign import ccall unsafe "ftglCreateBufferFont" fcreateBufferFont :: CString -> IO Font
-- | 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 = withCString file $ \p -> fcreateBufferFont p
foreign import ccall unsafe "ftglCreateOutlineFont" fcreateOutlineFont :: CString -> IO Font
-- | 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 = withCString file $ \p -> fcreateOutlineFont p
foreign import ccall unsafe "ftglCreatePixmapFont" fcreatePixmapFont :: CString -> IO Font
-- | 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 = withCString file $ \p -> fcreatePixmapFont p
foreign import ccall unsafe "ftglCreatePolygonFont" fcreatePolygonFont :: CString -> IO Font
-- | 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 = withCString file $ \p -> fcreatePolygonFont p
foreign import ccall unsafe "ftglCreateTextureFont" fcreateTextureFont :: CString -> IO Font
-- | 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 = withCString file $ \p -> fcreateTextureFont p
foreign import ccall unsafe "ftglCreateExtrudeFont" fcreateExtrudeFont :: CString -> IO Font
-- | 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 = withCString file $ \p -> fcreateExtrudeFont p
-- | Create a simple layout
foreign import ccall unsafe "ftglCreateSimpleLayout" createSimpleLayout :: IO Layout
-- | Set the layout's font.
foreign import ccall unsafe "ftglSetLayoutFont" setLayoutFont :: Layout -> Font -> IO ()
foreign import ccall unsafe "ftglGetLayoutFont" fgetLayoutFont :: Layout -> IO Font
-- | Get the embedded font from the Layout
getLayoutFont f = unsafePerformIO $ fgetLayoutFont f
-- | Set the line length, I believe in OpenGL units, although I'm not sure.
foreign import ccall unsafe "ftglSetLayoutLineLength" setLayoutLineLength :: Layout -> CFloat -> IO ()
foreign import ccall unsafe "ftglGetLayoutLineLength" fgetLayoutLineLength :: Layout -> IO CFloat
-- | Get the line length in points (1:72in) of lines in the layout
getLayoutLineLength :: Layout -> Float
getLayoutLineLength f = realToFrac . unsafePerformIO $ fgetLayoutLineLength f
foreign import ccall unsafe "ftglSetLayoutAlignment" fsetLayoutAlignment :: Layout -> CInt -> IO ()
-- | Set the layout alignment
setLayoutAlignment layout alignment = fsetLayoutAlignment layout (marshalTextAlignment alignment)
foreign import ccall unsafe "ftglGetLayoutAlignement" fgetLayoutAlignment :: Layout -> IO CInt
-- | Get the alignment of text in this layout.
getLayoutAlignment :: Layout -> TextAlignment
getLayoutAlignment f = readTextAlignment . unsafePerformIO $ fgetLayoutAlignment f
foreign import ccall unsafe "ftglSetLayoutLineSpacing" fsetLayoutLineSpacing :: Layout -> CFloat -> IO ()
-- | Set layout line spacing in OpenGL units.
setLayoutLineSpacing :: Layout -> Float -> IO ()
setLayoutLineSpacing layout spacing = setLayoutLineSpacing layout (realToFrac spacing)
-- | Destroy a font
foreign import ccall unsafe "ftglDestroyFont" destroyFont :: Font -> IO ()
foreign import ccall unsafe "ftglAttachFile" fattachFile :: Font -> CString -> IO ()
-- | Attach a metadata file to a font.
attachFile :: Font -> String -> IO ()
attachFile font str = withCString str $ \p -> fattachFile font p
-- | Attach some external data (often kerning) to the font
foreign import ccall unsafe "ftglAttachData" attachData :: Font -> Ptr () -> IO ()
-- | Set the font's character map
foreign import ccall unsafe "ftglSetFontCharMap" fsetFontCharMap :: Font -> CInt -> IO ()
setCharMap :: Font -> CharMap -> IO ()
setCharMap font charmap = fsetFontCharMap font (marshalCharMap charmap)
foreign import ccall unsafe "ftglGetFontCharMapCount" fgetFontCharMapCount :: Font -> IO CInt
-- | Get the number of characters loaded into the current charmap for the font.
getFontCharMapCount :: Font -> Int
getFontCharMapCount f = fromIntegral . unsafePerformIO $ fgetFontCharMapCount f
foreign import ccall unsafe "ftglGetFontCharMapList" fgetFontCharMapList :: Font -> IO (Ptr CInt)
-- | Get the different character mappings available in this font.
getFontCharMapList f = unsafePerformIO $ fgetFontCharMapList f
foreign import ccall unsafe "ftglSetFontFaceSize" fsetFontFaceSize :: Font -> CInt -> CInt -> IO CInt
setFontFaceSize :: Font -> Int -> Int -> IO CInt
setFontFaceSize f s x = fsetFontFaceSize f (fromIntegral s) (fromIntegral x)
foreign import ccall unsafe "ftglGetFontFaceSize" fgetFontFaceSize :: Font -> IO CInt
-- | Get the current font face size in points.
getFontFaceSize :: Font -> Int
getFontFaceSize f = fromIntegral . unsafePerformIO $ fgetFontFaceSize f
foreign import ccall unsafe "ftglSetFontDepth" fsetFontDepth :: Font -> CFloat -> IO ()
setFontDepth :: Font -> Float -> IO ()
setFontDepth font depth = fsetFontDepth font (realToFrac depth)
foreign import ccall unsafe "ftglSetFontOutset" fsetFontOutset :: Font -> CFloat -> CFloat -> IO ()
setFontOutset :: Font -> Float -> Float -> IO ()
setFontOutset font d o = fsetFontOutset font (realToFrac d) (realToFrac o)
foreign import ccall unsafe "ftglGetFontBBox" fgetFontBBox :: Font -> CString -> Int -> Ptr CFloat -> IO ()
-- | Get the text extents of a string as a list of (llx,lly,lly,urx,ury,urz)
getFontBBox :: Font -> String -> [Float]
getFontBBox f s = unsafePerformIO $
allocaBytes 24 $ \pf ->
withCString s $ \ps -> do
fgetFontBBox f ps (-1) pf
map realToFrac <$> peekArray 6 pf
foreign import ccall unsafe "ftglGetFontAscender" fgetFontAscender :: Font -> CFloat
-- | Get the global ascender height for the face.
getFontAscender :: Font -> Float
getFontAscender = realToFrac . fgetFontAscender
foreign import ccall unsafe "ftglGetFontDescender" fgetFontDescender :: Font -> CFloat
-- | Gets the global descender height for the face.
getFontDescender :: Font -> Float
getFontDescender = realToFrac . fgetFontDescender
foreign import ccall unsafe "ftglGetFontLineHeight" fgetFontLineHeight :: Font -> CFloat
-- | Gets the global line spacing for the face.
getFontLineHeight :: Font -> Float
getFontLineHeight = realToFrac . fgetFontLineHeight
foreign import ccall unsafe "ftglGetFontAdvance" fgetFontAdvance :: Font -> CString -> IO CFloat
-- | 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
foreign import ccall unsafe "ftglRenderFont" frenderFont :: Font -> CString -> CInt -> IO ()
-- | 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)
foreign import ccall unsafe "ftglGetFontError" fgetFontError :: Font -> IO CInt
-- | 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
foreign import ccall unsafe "ftglDestroyLayout" destroyLayout :: Layout -> IO ()
foreign import ccall unsafe "ftglRenderLayout" frenderLayout :: Layout -> CString -> IO ()
-- | Render a string of text within a layout.
renderLayout layout str = withCString str $ \strPtr -> do frenderLayout layout strPtr
foreign import ccall unsafe "ftglGetLayoutError" fgetLayoutError :: Layout -> IO CInt
-- | Get any errors associated with a layout.
getLayoutError f = unsafePerformIO $ fgetLayoutError f
-- | 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
data CharMap =
EncodingNone
| EncodingMSSymbol
| EncodingUnicode
| EncodingSJIS
| EncodingGB2312
| EncodingBig5
| EncodingWanSung
| EncodingJohab
| EncodingAdobeStandard
| EncodingAdobeExpert
| EncodingAdobeCustom
| EncodingAdobeLatin1
| EncodingOldLatin2
| EncodingAppleRoman
encodeTag :: Char -> Char -> Char -> Char -> CInt
encodeTag a b c d =
(fromIntegral (ord a) `shift` 24)
.|. (fromIntegral (ord b) `shift` 16)
.|. (fromIntegral (ord c) `shift` 8)
.|. (fromIntegral (ord d))
marshalCharMap EncodingNone = 0
marshalCharMap EncodingMSSymbol = encodeTag 's' 'y' 'm' 'b'
marshalCharMap EncodingUnicode =encodeTag 'u' 'n' 'i' 'c'
marshalCharMap EncodingSJIS = encodeTag 's' 'j' 'i' 's'
marshalCharMap EncodingGB2312 = encodeTag 'g' 'b' ' ' ' '
marshalCharMap EncodingBig5= encodeTag 'b' 'i' 'g' '5'
marshalCharMap EncodingWanSung= encodeTag 'w' 'a' 'n' 's'
marshalCharMap EncodingJohab= encodeTag 'j' 'o' 'h' 'a'
marshalCharMap EncodingAdobeStandard= encodeTag 'A' 'D' 'O' 'B'
marshalCharMap EncodingAdobeExpert= encodeTag 'A' 'D' 'B' 'E'
marshalCharMap EncodingAdobeCustom= encodeTag 'A' 'D' 'B' 'C'
marshalCharMap EncodingAdobeLatin1= encodeTag 'l' 'a' 't' '1'
marshalCharMap EncodingOldLatin2= encodeTag 'l' 'a' 't' '2'
marshalCharMap EncodingAppleRoman= encodeTag 'a' 'r' 'm' 'n'