packages feed

stb-truetype 0.1.2 → 0.1.4

raw patch · 5 files changed

+5207/−1925 lines, 5 filesdep ~arraydep ~base

Dependency ranges changed: array, base

Files

Graphics/Rendering/TrueType/STB.hs view
@@ -1,31 +1,35 @@ --- TODO: ---   * rewrite the file loading so that it we do not depend on ByteString---   * automatic glyph indexing, texture creation ------ -- Module      : Graphics.Rendering.TrueType.STB--- Version     : 0.1.2+-- Version     : 0.1.4 -- License     : Public Domain -- Author      : Balazs Komuves -- Maintainer  : bkomuves (plus) hackage (at) gmail (dot) com -- Stability   : experimental -- Portability : portable(?), requires FFI and CPP--- Tested with : GHC 6.10.1+-- Tested with : GHC 8.0.2, 8.2.1 -- + -- | This is a wrapper around Sean Barrett's TrueType font rasterizer code. -- The original can be found at <http://nothings.org/stb/stb_truetype.h>.--- The version of @stb-truetype@ used here is @0.3@.+-- The version of @stb-truetype@ used here is @v1.19@. --+-- This is a very low-level library; if you just want to render text +-- using OpenGL, look at the the higher-level library @minitypeset-opengl@+--+-- Note: the glyph coordinate system uses te is the mathematical convention, +-- that is, the Y coordinate increases upwards; unlike the screen and/or bitmap+-- coordinate system, where Y increases downwards.+--  {-# LANGUAGE CPP, ForeignFunctionInterface #-} {-# CFILES cbits/wrapper.c #-}  -- for Hugs (?) module Graphics.Rendering.TrueType.STB    ( TrueType(..)   , Offset-  , Font+  , Font(..)+  , CFontInfo   , Glyph   -- * Initialization   , loadTTF@@ -33,8 +37,10 @@   , enumerateFonts   , initFont   , findGlyph+  , notDefinedGlyphChar   -- * Font metrics   , Unscaled+  , Scaling   , HorizontalMetrics(..)   , VerticalMetrics(..)   , BoundingBox(..)@@ -46,27 +52,37 @@   , getGlyphKernAdvance   , getGlyphBoundingBox   -- * Bitmaps-  , Scaling   , Bitmap(..)   , newBitmap   , withBitmap   , flipBitmap   , BitmapOfs+  , bitmapArray+  , bitmapFloatArray+  -- * Vanilla (non-subpixel) rendering   , getGlyphBitmapBox   , newGlyphBitmap   , renderGlyphIntoBitmap'   , renderGlyphIntoBitmap-  , bitmapArray-  , bitmapFloatArray+  -- * Subpixel rendering+  , SubpixelShift+  , getGlyphBitmapBoxSubpixel+  , newGlyphBitmapSubpixel+  , renderGlyphIntoBitmapSubpixel'+  , renderGlyphIntoBitmapSubpixel   -- * Cached glyph storage   , CachedBitmap(..)-  , BitmapCache+  , BitmapCache(..)   , bmcVerticalMetrics   , bmcScaling   , newBitmapCache   , getCachedBitmap-  -  ) where+  -- * Unicode tables+  , UnicodeCache+  , newUnicodeCache +  , lookupUnicodeCache   +  ) +  where  -------------------------------------------------------------------------------- @@ -80,6 +96,7 @@ import Data.Array import Data.Array.IO import Data.Array.Unboxed+import Data.Array.Unsafe  #ifdef __GLASGOW_HASKELL__ import qualified Data.Array.Base as Arr  #endif@@ -91,11 +108,14 @@  import Foreign hiding (newArray) import Foreign.C+import Foreign.Concurrent  import Data.ByteString (ByteString) import qualified Data.ByteString as B import qualified Data.ByteString.Internal as BI +import System.IO.Unsafe as Unsafe+ --------------------------------------------------------------------------------  -- | A TrueType font file (containing maybe multiple font sets) loaded into memory.@@ -107,6 +127,10 @@ -- | A glyph inside a font. newtype Glyph = Glyph Int deriving (Eq,Ord,Show) +-- | Glyph index 0 is normally reserved for showing missing glyphs.+notdefGlyph :: Glyph+notdefGlyph = Glyph 0+ ccodepoint :: Char -> CCodepoint ccodepoint = fromIntegral . ord  @@ -133,18 +157,20 @@ withFontInfo (Font _ fptr _) = withForeignPtr fptr  ---------------------------------------------------------------------------------+-- | A table indexed by unicode code points.+-- -- Organized into small continous blocks (say 128 characters)--- so lookup should pretty very fast-type UnicodeCache a = MVar (IntMap (IOArray Char (Maybe a)))+-- so lookup should be pretty fast+newtype UnicodeCache a = UC (MVar (IntMap (IOArray Char (Maybe a)))) -unicodeCacheGranularity = 128 :: Int+unicodeCacheGranularity :: Int+unicodeCacheGranularity = 128   newUnicodeCache :: IO (UnicodeCache a)-newUnicodeCache = newMVar (IntMap.empty)+newUnicodeCache = UC <$> newMVar (IntMap.empty)  lookupUnicodeCache :: Char -> (Char -> IO a) -> UnicodeCache a -> IO a-lookupUnicodeCache char calculate cache = do+lookupUnicodeCache char calculate (UC cache) = do   themap <- takeMVar cache     let k = ord char `div` unicodeCacheGranularity   case IntMap.lookup k themap of@@ -202,10 +228,20 @@    -------------------------------------------------------------------------------- --- | Note: this is cached.+-- | The character @0xffff@ (which is not a valid unicode code point) which maps to the \"not defined glyph\"+notDefinedGlyphChar :: Char+notDefinedGlyphChar = '\xffff'++-- | Maps unicode characters to glyphs. As a hack, we map @0xffff@ (which is not a+-- valid unicode code point) to the \"not defined glyph\" (glyph #0), which has no +-- character counterpart.+--+-- Note: this is cached, so you can call it many times if necessary. findGlyph :: Font -> Char -> IO (Maybe Glyph) findGlyph fontinfo@(Font _ _ glyphmap) char =-  lookupUnicodeCache char (findGlyphNotCached fontinfo) glyphmap +  case ord char of+    0xffff -> return (Just notdefGlyph)+    _      -> lookupUnicodeCache char (findGlyphNotCached fontinfo) glyphmap   -- this is not cached findGlyphNotCached :: Font -> Char -> IO (Maybe Glyph)@@ -222,15 +258,15 @@ --------------------------------------------------------------------------------  -- | Note: the metrics are scaled!-data CachedBitmap = CBM Bitmap BitmapOfs (HorizontalMetrics Float)+data CachedBitmap = CBM !Glyph !Bitmap !BitmapOfs !(HorizontalMetrics Float)  -- | A \"bitmap cache\". data BitmapCache = BMCache-  { bmc_fontinfo :: Font-  , bmc_scaling  :: (Float,Float)-  , bmc_cache    :: UnicodeCache (Maybe CachedBitmap)-  , bmc_vmetrics :: VerticalMetrics Float-  , bmc_flipped  :: Bool+  { bmc_fontinfo :: !Font+  , bmc_scaling  :: !(Float,Float)+  , bmc_cache    :: !(UnicodeCache (Maybe CachedBitmap))+  , bmc_vmetrics :: !(VerticalMetrics Float)+  , bmc_flipped  :: !Bool   }  -- | Note: these metrics are scaled!@@ -264,7 +300,7 @@           bm <- if flipped then flipBitmap bm' else return bm'           hmetu <- getGlyphHorizontalMetrics font glyph           let hmets = fmap (\x -> xscale * fromIntegral x) hmetu -          return $ Just (CBM bm ofs hmets)+          return $ Just (CBM glyph bm ofs hmets)         Nothing -> do           return Nothing         @@ -277,9 +313,9 @@ -- 'lineGap' is the spacing between one row's descent and the next row's ascent... -- so you should advance the vertical position by @ascent - descent + lineGap@       data VerticalMetrics a = VMetrics-  { ascent  :: a   -  , descent :: a-  , lineGap :: a+  { ascent  :: !a   +  , descent :: !a+  , lineGap :: !a   }   deriving Show   @@ -300,8 +336,8 @@ -- 'leftSideBearing' is the offset from the current horizontal position to the left edge of the character; -- 'advanceWidth' is the offset from the current horizontal position to the next horizontal position. data HorizontalMetrics a = HMetrics-  { advanceWidth    :: a      -  , leftSideBearing :: a+  { advanceWidth    :: !a      +  , leftSideBearing :: !a   }   deriving Show @@ -341,25 +377,32 @@         , leftSideBearing = fromIntegral lsb         }         --- | This is not yet implemented in @stb_truetype@; it always returns 0.+-- | An additional amount to add to the \'advance\' value between two glyphs getGlyphKernAdvance :: Font -> Glyph -> Glyph -> IO Unscaled getGlyphKernAdvance fontinfo glyph1 glyph2 =    withFontInfo fontinfo $ \ptr -> do     kern <- stbtt_GetGlyphKernAdvance ptr (cglyphindex glyph1) (cglyphindex glyph1)     return (fromIntegral kern)-    -getGlyphBoundingBox :: Font -> Glyph -> IO (BoundingBox Unscaled)++getGlyphBoundingBox :: Font -> Glyph -> IO (Maybe (BoundingBox Unscaled)) getGlyphBoundingBox fontinfo glyph =   withFontInfo fontinfo $ \ptr -> do     alloca $ \px0 -> alloca $ \py0 -> alloca $ \px1 -> alloca $ \py1 -> do-      stbtt_GetGlyphBox ptr (cglyphindex glyph) px0 py0 px1 py1-      x0 <- peek px0 :: IO CInt-      y0 <- peek py0 :: IO CInt-      x1 <- peek px1 :: IO CInt-      y1 <- peek py1 :: IO CInt-      return $ BBox -        (fromIntegral x0, fromIntegral y0)-        (fromIntegral x1, fromIntegral y1)+      --poke px0 0+      --poke py0 0+      --poke px1 0+      --poke py1 0+      r <- stbtt_GetGlyphBox ptr (cglyphindex glyph) px0 py0 px1 py1+      if r == 0 +        then return Nothing+        else do+          x0 <- peek px0 :: IO CInt+          y0 <- peek py0 :: IO CInt+          x1 <- peek px1 :: IO CInt+          y1 <- peek py1 :: IO CInt+          return $ Just $ BBox +            (fromIntegral x0, fromIntegral y0)+            (fromIntegral x1, fromIntegral y1)          -------------------------------------------------------------------------------- @@ -367,8 +410,8 @@  -- | A 8-bit grayscale bitmap. data Bitmap = Bitmap-  { bitmapSize :: (Int,Int)-  , bitmapPtr  :: ForeignPtr Word8+  { bitmapSize :: !(Int,Int)+  , bitmapPtr  :: !(ForeignPtr Word8)   }  -- | An offset (for example the pivot of the glyph) @@ -414,7 +457,7 @@ #else         writeArray ar (y,x) a #endif-    unsafeFreeze ar+    Arr.unsafeFreeze ar                               bitmapFloatArray :: Bitmap -> IO (UArray (Int,Int) Float) bitmapFloatArray bm = @@ -431,8 +474,11 @@ #else         writeArray ar (y,x) z #endif-    unsafeFreeze ar+    Arr.unsafeFreeze ar +--------------------------------------------------------------------------------+-- * vanilla (non-subpixel) rendering+ -- | Returns the size of the bitmap (in pixels) needed to  -- render the glyph with the given scaling. --@@ -471,7 +517,8 @@       ysiz <- peek pysiz :: IO CInt       xofs <- peek pxofs :: IO CInt       yofs <- peek pyofs :: IO CInt-      fpbm <- newForeignPtr bitmapFinalizer pbm+      -- fpbm <- newForeignPtr bitmapFinalizer pbm+      fpbm <- Foreign.Concurrent.newForeignPtr pbm (bitmapFinalizer1 pbm)        let bm  = Bitmap (fromIntegral xsiz, fromIntegral ysiz) fpbm           ofs = (fromIntegral xofs, fromIntegral yofs)       return $ (bm,ofs)@@ -498,55 +545,119 @@ renderGlyphIntoBitmap fontinfo glyph scaling@(xscale,yscale) bm ofs@(xofs,yofs) = do   BBox (x0,y0) _ <- getGlyphBitmapBox fontinfo glyph scaling   renderGlyphIntoBitmap' fontinfo glyph scaling bm (xofs+x0,yofs+y0) -         + --------------------------------------------------------------------------------+-- * Subpixel rendering -{--typedef struct-{-   unsigned char  *data;         // pointer to .ttf file-   int             fontstart;    // offset of start of font+-- | The subpixel version of the rendering functions accept an additional fractional shift+type SubpixelShift = (Float,Float) -   int numGlyphs;                // number of glyphs, needed for range checking+-- | Returns the size of the bitmap (in pixels) needed to +-- render the glyph with the given scaling.+--+-- The box is centered around the glyph origin; so the+-- bitmap width is @x1-x0@, height is @y1-y0@, and location to place+-- the bitmap top left is @(leftSideBearing*scale,y0)@.+-- Note that the bitmap uses /y-increases-down/, but the shape uses+-- /y-increases-up/, so the results of 'getGlyphBitmapBox' and +-- 'getGlyphBoundingBox' are inverted.+getGlyphBitmapBoxSubpixel :: Font -> Glyph -> Scaling -> SubpixelShift -> IO (BoundingBox Int)+getGlyphBitmapBoxSubpixel fontinfo glyph (xscale,yscale) (xshift,yshift) =+  withFontInfo fontinfo $ \ptr -> do+    alloca $ \px0 -> alloca $ \py0 -> alloca $ \px1 -> alloca $ \py1 -> do+      stbtt_GetGlyphBitmapBoxSubpixel ptr (cglyphindex glyph) +        (realToFrac xscale) (realToFrac yscale) +        (realToFrac xshift) (realToFrac yshift) +        px0 py0 px1 py1+      x0 <- peek px0 :: IO CInt+      y0 <- peek py0 :: IO CInt+      x1 <- peek px1 :: IO CInt+      y1 <- peek py1 :: IO CInt+      return $ BBox +        (fromIntegral x0, fromIntegral y0)+        (fromIntegral x1, fromIntegral y1) -   int loca,head,glyf,hhea,hmtx; // table locations as offset from start of .ttf-   int index_map;                // a cmap mapping for our chosen character encoding-   int indexToLocFormat;         // format needed to map from glyph index to glyph-} stbtt_fontinfo;--}+-- | Creates a new bitmap just enough to fit the glyph with the given scaling,+-- and renders the glyph into it. The offset returned is the offset +-- in pixel space /from/ the glyph origin /to/ the top-left of the bitmap+-- (so it's almost always negative).+newGlyphBitmapSubpixel :: Font -> Glyph -> Scaling -> SubpixelShift -> IO (Bitmap,BitmapOfs)+newGlyphBitmapSubpixel fontinfo glyph (xscale,yscale) (xshift,yshift) = do+  withFontInfo fontinfo $ \ptr -> do+    alloca $ \pxsiz -> alloca $ \pysiz -> alloca $ \pxofs -> alloca $ \pyofs -> do+      pbm <- stbtt_GetGlyphBitmapSubpixel ptr +        (realToFrac xscale) (realToFrac yscale) +        (realToFrac xshift) (realToFrac yshift) +        (cglyphindex glyph) +        pxsiz pysiz pxofs pyofs+      xsiz <- peek pxsiz :: IO CInt+      ysiz <- peek pysiz :: IO CInt+      xofs <- peek pxofs :: IO CInt+      yofs <- peek pyofs :: IO CInt+      -- fpbm <- newForeignPtr bitmapFinalizer pbm+      fpbm <- Foreign.Concurrent.newForeignPtr pbm (bitmapFinalizer1 pbm) +      let bm  = Bitmap (fromIntegral xsiz, fromIntegral ysiz) fpbm+          ofs = (fromIntegral xofs, fromIntegral yofs)+      return $ (bm,ofs) -data TableLoc = TableLoc -  { _loca :: Int-  , _head :: Int-  , _glyf :: Int-  , _hhea :: Int-  , _hmtx :: Int-  }+-- | The offset is the /top-left corner/ of the bounding box of the glyph,+-- and must be nonnegative (otherwise nothing will happen).+renderGlyphIntoBitmapSubpixel' :: Font -> Glyph -> Scaling -> SubpixelShift -> Bitmap -> BitmapOfs -> IO ()+renderGlyphIntoBitmapSubpixel' fontinfo glyph (xscale,yscale) (xshift,yshift) bm (xofs,yofs) = do+  let (xsiz,ysiz) = bitmapSize bm +  when ( xofs < xsiz && yofs < ysiz && xofs >= 0 && yofs >= 0 ) $ do+    withFontInfo fontinfo $ \ptr -> do+      withBitmap bm $ \width height pbm -> do+        let pbm' = pbm `plusPtr` (width*yofs+xofs)+        stbtt_MakeGlyphBitmapSubpixel ptr pbm'+          (fromIntegral $ width - xofs) (fromIntegral $ height - yofs)+          (fromIntegral width)  -- stride+          (realToFrac xscale) (realToFrac yscale) +          (realToFrac xshift) (realToFrac yshift) +          (cglyphindex glyph)         -instance Storable TableLoc where -  alignment _ = alignment (undefined :: CInt)-  sizeOf _    = 5 * sizeOf (undefined :: CInt)-  peek = error "TableLoc/peek: not implemented"-  poke = error "TableLoc/poke: not implemented"+-- | The offset is the /origin/ of the glyph. If the glyph extends from the+-- bitmap in the positive direction, it is clipped; however, if it extends+-- in the negative direction, no drawing will happen!+renderGlyphIntoBitmapSubpixel ::  Font -> Glyph -> Scaling -> SubpixelShift -> Bitmap -> BitmapOfs -> IO ()+renderGlyphIntoBitmapSubpixel fontinfo glyph scaling@(xscale,yscale) shift bm ofs@(xofs,yofs) = do+  BBox (x0,y0) _ <- getGlyphBitmapBoxSubpixel fontinfo glyph scaling shift+  renderGlyphIntoBitmapSubpixel' fontinfo glyph scaling shift bm (xofs+x0,yofs+y0) +         +-------------------------------------------------------------------------------- +foreign import ccall "sizeof_stbtt_fontinfo" sizeof_stbtt_fontinfo :: CInt+ data CFontInfo = CFontInfo-  { _userData  :: Ptr ()-  , _data      :: Ptr Word8-  , _fontstart :: Int -  , _numGlyphs :: Int-  , _tableloc  :: TableLoc-  , _indexMap  :: Int-  , _indexToLocFmt :: Int-  }-  ++{-+struct stbtt_fontinfo+{+   void           * userdata;+   unsigned char  * data;              // pointer to .ttf file+   int              fontstart;         // offset of start of font++   int numGlyphs;                     // number of glyphs, needed for range checking++   int loca,head,glyf,hhea,hmtx,kern,gpos; // table locations as offset from start of .ttf+   int index_map;                     // a cmap mapping for our chosen character encoding+   int indexToLocFormat;              // format needed to map from glyph index to glyph++   stbtt__buf cff;                    // cff font data+   stbtt__buf charstrings;            // the charstring index+   stbtt__buf gsubrs;                 // global charstring subroutines index+   stbtt__buf subrs;                  // private charstring subroutines index+   stbtt__buf fontdicts;              // array of font dicts+   stbtt__buf fdselect;               // map from glyph to fontdict+};+-}+  instance Storable CFontInfo where    alignment _ = alignment (undefined :: CInt)-  sizeOf _    = 2 * sizeOf (undefined :: Ptr Word8)-              + sizeOf (undefined :: TableLoc)-              + 4 * sizeOf (undefined :: CInt)+  sizeOf _    = fromIntegral sizeof_stbtt_fontinfo   peek = error "CFontInfo/peek: not implemented"               poke = error "CFontInfo/poke: not implemented"       -              +      --------------------------------------------------------------------------------  type CCodepoint  = CInt@@ -595,16 +706,7 @@  ------- -{---- stb_truetype v0.2-foreign import ccall unsafe "stb_truetype.h stbtt_FreeBitmap"-  stbtt_FreeBitmap :: Ptr Word8 -> IO () --foreign import ccall unsafe "stb_truetype.h &stbtt_FreeBitmap"-  bitmapFinalizer :: FunPtr (Ptr Word8 -> IO ())--}---- stb_truetype v0.3, with "userdata"+-- since stb_truetype v0.3, with "userdata" foreign import ccall unsafe "stb_truetype.h stbtt_FreeBitmap"   stbtt_FreeBitmap :: Ptr Word8 -> Ptr a -> IO ()  @@ -612,8 +714,11 @@   :: (Ptr Word8 -> IO ()) -> IO (FinalizerPtr Word8)  bitmapFinalizer :: FunPtr (Ptr Word8 -> IO ())-bitmapFinalizer = unsafePerformIO $ mkFinPtr $ \p -> stbtt_FreeBitmap p nullPtr+bitmapFinalizer = Unsafe.unsafePerformIO $ mkFinPtr $ \p -> stbtt_FreeBitmap p nullPtr  +bitmapFinalizer1 :: Ptr Word8 -> IO ()+bitmapFinalizer1 p = stbtt_FreeBitmap p nullPtr+ ------  {- @@ -652,6 +757,31 @@ foreign import ccall unsafe "stb_truetype.h stbtt_GetGlyphBitmapBox"   stbtt_GetGlyphBitmapBox      :: Ptr CFontInfo -> CGlyphIndex -> CFloat -> CFloat+    -> Ptr CInt -> Ptr CInt -> Ptr CInt -> Ptr CInt -> IO ()++-----+-- * subpixel versions++foreign import ccall unsafe "stb_truetype.h stbtt_GetGlyphBitmapSubpixel"+  stbtt_GetGlyphBitmapSubpixel +    :: Ptr CFontInfo -> CFloat -> CFloat +    -> CFloat -> CFloat+    -> CGlyphIndex +    -> Ptr CInt -> Ptr CInt -> Ptr CInt -> Ptr CInt -> IO (Ptr Word8)++foreign import ccall unsafe "stb_truetype.h stbtt_MakeGlyphBitmap"+  stbtt_MakeGlyphBitmapSubpixel +    :: Ptr CFontInfo -> Ptr Word8 -> CInt -> CInt -> CInt+    -> CFloat -> CFloat+    -> CFloat -> CFloat +    -> CGlyphIndex -> IO ()++-- (Note that the bitmap uses y-increases-down, but the shape uses+-- y-increases-up, so GlyphBitmapBox and GlyphBox are inverted.)+foreign import ccall unsafe "stb_truetype.h stbtt_GetGlyphBitmapBoxSubpixel"+  stbtt_GetGlyphBitmapBoxSubpixel +    :: Ptr CFontInfo -> CGlyphIndex -> CFloat -> CFloat+    -> CFloat -> CFloat     -> Ptr CInt -> Ptr CInt -> Ptr CInt -> Ptr CInt -> IO ()  --------------------------------------------------------------------------------
cbits/stb_truetype.h view
@@ -1,1809 +1,4853 @@-// stb_truetype.h - v0.3 - public domain - 2009 Sean Barrett / RAD Game Tools-//-//   This library processes TrueType files:-//        parse files-//        extract glyph metrics-//        extract glyph shapes-//        render glyphs to one-channel bitmaps with antialiasing (box filter)-//-//   Todo:-//        non-MS cmaps-//        crashproof on bad data-//        hinting-//        subpixel positioning when rendering bitmap-//        cleartype-style AA-//-// ADDITIONAL CONTRIBUTORS-//-//   Mikko Mononen: compound shape support, more cmap formats-//-// VERSIONS-//-//   0.3 (2009-06-24) cmap fmt=12, compound shapes (MM)-//                    userdata, malloc-from-userdata, non-zero fill (STB)-//   0.2 (2009-03-11) Fix unsigned/signed char warnings-//   0.1 (2009-03-09) First public release-//-// USAGE-//-//   Include this file in whatever places neeed to refer to it. In ONE C/C++-//   file, write:-//      #define STB_TRUETYPE_IMPLEMENTATION-//   before the #include of this file. This expands out the actual-//   implementation into that C/C++ file.-//-//   Look at the header-file sections below for the API, but here's a quick skim:-//-//   Simple 3D API (don't ship this, but it's fine for tools and quick start,-//                  and you can cut and paste from it to move to more advanced)-//           stbtt_BakeFontBitmap()               -- bake a font to a bitmap for use as texture-//           stbtt_GetBakedQuad()                 -- compute quad to draw for a given char-//-//   "Load" a font file from a memory buffer (you have to keep the buffer loaded)-//           stbtt_InitFont()-//           stbtt_GetFontOffsetForIndex()        -- use for TTC font collections-//-//   Render a unicode codepoint to a bitmap-//           stbtt_GetCodepointBitmap()           -- allocates and returns a bitmap-//           stbtt_MakeCodepointBitmap()          -- renders into bitmap you provide-//           stbtt_GetCodepointBitmapBox()        -- how big the bitmap must be-//-//   Character advance/positioning-//           stbtt_GetCodepointHMetrics()-//           stbtt_GetFontVMetrics()-//-// NOTES-//-//   The system uses the raw data found in the .ttf file without changing it-//   and without building auxiliary data structures. This is a bit inefficient-//   on little-endian systems (the data is big-endian), but assuming you're-//   caching the bitmaps or glyph shapes this shouldn't be a big deal.-//-//   It appears to be very hard to programmatically determine what font a-//   given file is in a general way. I provide an API for this, but I don't-//   recommend it.-//-//-// SOURCE STATISTICS (based on v0.3, 1800 LOC)-//-//   Documentation & header file        350 LOC  \___ 500 LOC documentation-//   Sample code                        140 LOC  /-//   Truetype parsing                   580 LOC  ---- 600 LOC TrueType-//   Software rasterization             240 LOC  \                           .-//   Curve tesselation                  120 LOC   \__ 500 LOC Bitmap creation-//   Bitmap management                   70 LOC   /-//   Baked bitmap interface              70 LOC  /-//   Font name matching & access        150 LOC  ---- 150 -//   C runtime library abstraction       60 LOC  ----  60---//////////////////////////////////////////////////////////////////////////////-//////////////////////////////////////////////////////////////////////////////-////-////  SAMPLE PROGRAMS-////-//-//  Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless-//-#if 0-#define STB_TRUETYPE_IMPLEMENTATION  // force following include to generate implementation-#include "stb_truetype.h"--char ttf_buffer[1<<20];-unsigned char temp_bitmap[512*512];--stbtt_chardata cdata[96]; // ASCII 32..126 is 95 glyphs-GLstbtt_uint ftex;--void my_stbtt_initfont(void)-{-   fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb"));-   stbtt_BakeFontBitmap(data,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits!-   // can free ttf_buffer at this point-   glGenTextures(1, &ftex);-   glBindTexture(GL_TEXTURE_2D, ftex);-   glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap);-   // can free temp_bitmap at this point-   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);-}--void my_stbtt_print(float x, float y, char *text)-{-   // assume orthographic projection with units = screen pixels, origin at top left-   glBindTexture(GL_TEXTURE_2D, ftex);-   glBegin(GL_QUADS);-   while (*text) {-      if (*text >= 32 && *text < 128) {-         stbtt_aligned_quad q;-         stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl,0=old d3d-         glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0);-         glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0);-         glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1);-         glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1);-      }-      ++text;-   }-   glEnd();-}-#endif-//-//-//////////////////////////////////////////////////////////////////////////////-//-// Complete program (this compiles): get a single bitmap, print as ASCII art-//-#if 0-#include <stdio.h>-#define STB_TRUETYPE_IMPLEMENTATION  // force following include to generate implementation-#include "stb_truetype.h"--char ttf_buffer[1<<25];--int main(int argc, char **argv)-{-   stbtt_fontinfo font;-   unsigned char *bitmap;-   int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20);--   fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb"));--   stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0));-   bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0);--   for (j=0; j < h; ++j) {-      for (i=0; i < w; ++i)-         putchar(" .:ioVM@"[bitmap[j*w+i]>>5]);-      putchar('\n');-   }-   return 0;-}-#endif -//-// Output:-//-//     .ii.-//    @@@@@@.-//   V@Mio@@o-//   :i.  V@V-//     :oM@@M-//   :@@@MM@M-//   @@o  o@M-//  :@@.  M@M-//   @@@o@@@@-//   :M@@V:@@.-//  -//////////////////////////////////////////////////////////////////////////////-// -// Complete program: print "Hello World!" banner, with bugs-//-#if 0-int main(int arg, char **argv)-{-   unsigned char screen[20][79];-   int i,j, pos=0;-   float scale;-   char *text = "Heljo World!";--   fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb"));-   stbtt_InitFont(&font, buffer, 0);--   scale = stbtt_ScaleForPixelHeight(&font, 16);-   memset(screen, 0, sizeof(screen));--   while (*text) {-      int advance,lsb,x0,y0,x1,y1, newpos, baseline=13;-      stbtt_GetCodepointHMetrics(&font, *text, &advance, &lsb);-      stbtt_GetCodepointBitmapBox(&font, *text, scale,scale, &x0,&y0,&x1,&y1);-      newpos = pos + (int) (lsb * scale) + x0;-      stbtt_MakeCodepointBitmap(&font, &screen[baseline + y0][newpos], x1-x0,y1-y0, 79, scale,scale, *text);-      // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong-      // because this API is really for baking character bitmaps into textures-      pos += (int) (advance * scale);-      ++text;-   }--   for (j=0; j < 20; ++j) {-      for (i=0; i < 79; ++i)-         putchar(" .:ioVM@"[screen[j][i]>>5]);-      putchar('\n');-   }--   return 0;-}-#endif---//////////////////////////////////////////////////////////////////////////////-//////////////////////////////////////////////////////////////////////////////-////-////   INTEGRATION WITH RUNTIME LIBRARIES-////--#ifdef STB_TRUETYPE_IMPLEMENTATION-   // #define your own (u)stbtt_int8/16/32 before including to override this-   #ifndef stbtt_uint8-   typedef unsigned char   stbtt_uint8;-   typedef signed   char   stbtt_int8;-   typedef unsigned short  stbtt_uint16;-   typedef signed   short  stbtt_int16;-   typedef unsigned int    stbtt_uint32;-   typedef signed   int    stbtt_int32;-   #endif--   typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1];-   typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1];--   // #define your own STBTT_sort() to override this to avoid qsort-   #ifndef STBTT_sort-   #include <stdlib.h>-   #define STBTT_sort(data,num_items,item_size,compare_func)   qsort(data,num_items,item_size,compare_func)-   #endif--   // #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h-   #ifndef STBTT_ifloor-   #include <math.h>-   #define STBTT_ifloor(x)   ((int) floor(x))-   #define STBTT_iceil(x)    ((int) ceil(x))-   #endif--   // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h-   #ifndef STBTT_malloc-   #if !defined(__APPLE__) // apple hack-   #include <malloc.h>-   #endif                  // apple hack-   #define STBTT_malloc(x,u)  malloc(x)-   #define STBTT_free(x,u)    free(x)-   #endif--   #ifndef STBTT_assert-   #include <assert.h>-   #define STBTT_assert(x)    assert(x)-   #endif--   #ifndef STBTT_strlen-   #include <string.h>-   #define STBTT_strlen(x)    strlen(x)-   #endif--   #ifndef STBTT_memcpy-   #include <memory.h>-   #define STBTT_memcpy       memcpy-   #define STBTT_memset       memset-   #endif-#endif--///////////////////////////////////////////////////////////////////////////////-///////////////////////////////////////////////////////////////////////////////-////-////   INTERFACE-////-////--#ifndef __STB_INCLUDE_STB_TRUETYPE_H__-#define __STB_INCLUDE_STB_TRUETYPE_H__--#ifdef __cplusplus-extern "C" {-#endif--//////////////////////////////////////////////////////////////////////////////-//-// TEXTURE BAKING API-//-// If you use this API, you only have to call two functions ever.-//--typedef struct-{-   unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap-   float xoff,yoff,xadvance;   -} stbtt_bakedchar;--extern int stbtt_BakeFontBitmap(const unsigned char *data, int offset,  // font location (use offset=0 for plain .ttf)-                                float pixel_height,                     // height of font in pixels-                                unsigned char *pixels, int pw, int ph,  // bitmap to be filled in-                                int first_char, int num_chars,          // characters to bake-                                stbtt_bakedchar *chardata);             // you allocate this, it's num_chars long-// if return is positive, the first unused row of the bitmap-// if return is negative, returns the negative of the number of characters that fit-// if return is 0, no characters fit and no rows were used-// This uses a very crappy packing.--typedef struct-{-   float x0,y0,s0,t0; // top-left-   float x1,y1,s1,t1; // bottom-right-} stbtt_aligned_quad;--extern void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph,  // same data as above-                               int char_index,             // character to display-                               float *xpos, float *ypos,   // pointers to current position in screen pixel space-                               stbtt_aligned_quad *q,      // output: quad to draw-                               int opengl_fillrule);       // true if opengl fill rule; false if DX9 or earlier-// Call GetBakedQuad with char_index = 'character - first_char', and it-// creates the quad you need to draw and advances the current position.-// It's inefficient; you might want to c&p it and optimize it.---//////////////////////////////////////////////////////////////////////////////-//-// FONT LOADING-//-//--extern int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index);-// Each .ttf file may have more than one font. Each has a sequential index-// number starting from 0. Call this function to get the font offset for a-// given index; it returns -1 if the index is out of range. A regular .ttf-// file will only define one font and it always be at offset 0, so it will-// return '0' for index 0, and -1 for all other indices. You can just skip-// this step if you know it's that kind of font.---// The following structure is defined publically so you can declare one on-// the stack or as a global or etc.-typedef struct-{-   void           *userdata;-   unsigned char  *data;         // pointer to .ttf file-   int             fontstart;    // offset of start of font--   int numGlyphs;                // number of glyphs, needed for range checking--   int loca,head,glyf,hhea,hmtx; // table locations as offset from start of .ttf-   int index_map;                // a cmap mapping for our chosen character encoding-   int indexToLocFormat;         // format needed to map from glyph index to glyph-} stbtt_fontinfo;--extern int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset);-// Given an offset into the file that defines a font, this function builds-// the necessary cached info for the rest of the system. You must allocate-// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't-// need to do anything special to free it, because the contents are a pure-// cache with no additional data structures. Returns 0 on failure.---//////////////////////////////////////////////////////////////////////////////-//-// CHARACTER TO GLYPH-INDEX CONVERSIOn--int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint);-// If you're going to perform multiple operations on the same character-// and you want a speed-up, call this function with the character you're-// going to process, then use glyph-based functions instead of the-// codepoint-based functions.---//////////////////////////////////////////////////////////////////////////////-//-// CHARACTER PROPERTIES-//--extern float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels);-// computes a scale factor to produce a font whose "height" is 'pixels' tall.-// Height is measured as the distance from the highest ascender to the lowest-// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics-// and computing:-//       scale = pixels / (ascent - descent)-// so if you prefer to measure height by the ascent only, use a similar calculation.--extern void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap);-// ascent is the coordinate above the baseline the font extends; descent-// is the coordinate below the baseline the font extends (i.e. it is typically negative)-// lineGap is the spacing between one row's descent and the next row's ascent...-// so you should advance the vertical position by "*ascent - *descent + *lineGap"-//   these are expressed in unscaled coordinates--extern void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing);-// leftSideBearing is the offset from the current horizontal position to the left edge of the character-// advanceWidth is the offset from the current horizontal position to the next horizontal position-//   these are expressed in unscaled coordinates--extern int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2);-// an additional amount to add to the 'advance' value between ch1 and ch2-// @TODO; for now always returns 0!--extern int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1);-// Gets the bounding box of the visible part of the glyph, in unscaled coordinates--extern void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing);-extern int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2);-extern int  stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);-// as above, but takes one or more glyph indices for greater efficiency---//////////////////////////////////////////////////////////////////////////////-//-// GLYPH SHAPES (you probably don't need these, but they have to go before-// the bitmaps for C declaration-order reasons)-//--#ifndef STBTT_vmove // you can predefine these to use different values (but why?)-   enum {-      STBTT_vmove=1,-      STBTT_vline,-      STBTT_vcurve-   };-#endif--#ifndef stbtt_vertex // you can predefine this to use different values-                   // (we share this with other code at RAD)-   #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file-   typedef struct-   {-      stbtt_vertex_type x,y,cx,cy;-      unsigned char type,padding;-   } stbtt_vertex;-#endif--extern int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices);-extern int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices);-// returns # of vertices and fills *vertices with the pointer to them-//   these are expressed in "unscaled" coordinates--extern void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);-// frees the data allocated above--//////////////////////////////////////////////////////////////////////////////-//-// BITMAP RENDERING-//--extern void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata);-// frees the bitmap allocated below--extern unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff);-// allocates a large-enough single-channel 8bpp bitmap and renders the-// specified character/glyph at the specified scale into it, with-// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque).-// *width & *height are filled out with the width & height of the bitmap,-// which is stored left-to-right, top-to-bottom.-//-// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap--extern void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint);-// the same as above, but you pass in storage for the bitmap in the form-// of 'output', with row spacing of 'out_stride' bytes. the bitmap is-// clipped to out_w/out_h bytes. call the next function to get the-// height and width and positioning info--extern void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);-// get the bbox of the bitmap centered around the glyph origin; so the-// bitmap width is ix1-ix0, height is iy1-iy0, and location to place-// the bitmap top left is (leftSideBearing*scale,iy0).-// (Note that the bitmap uses y-increases-down, but the shape uses-// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.)--extern unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff);-extern void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);-extern void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph);--//extern void stbtt_get_true_bbox(stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);--// @TODO: don't expose this structure-typedef struct-{-   int w,h,stride;-   unsigned char *pixels;-} stbtt__bitmap;--extern void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, int x_off, int y_off, int invert, void *userdata);--//////////////////////////////////////////////////////////////////////////////-//-// Finding the right font...-//-// You should really just solve this offline, keep your own tables-// of what font is what, and don't try to get it out of the .ttf file.-// That's because getting it out of the .ttf file is really hard, because-// the names in the file can appear in many possible encodings, in many-// possible languages, and e.g. if you need a case-insensitive comparison,-// the details of that depend on the encoding & language in a complex way-// (actually underspecified in truetype, but also gigantic).-//-// But you can use the provided functions in two possible ways:-//     stbtt_FindMatchingFont() will use *case-sensitive* comparisons on-//             unicode-encoded names to try to find the font you want;-//             you can run this before calling stbtt_InitFont()-//-//     stbtt_GetFontNameString() lets you get any of the various strings-//             from the file yourself and do your own comparisons on them.-//             You have to have called stbtt_InitFont() first.---extern int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags);-// returns the offset (not index) of the font that matches, or -1 if none-//   if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold".-//   if you use any other flag, use a font name like "Arial"; this checks-//     the 'macStyle' header field; i don't know if fonts set this consistently-#define STBTT_MACSTYLE_DONTCARE     0-#define STBTT_MACSTYLE_BOLD         1-#define STBTT_MACSTYLE_ITALIC       2-#define STBTT_MACSTYLE_UNDERSCORE   4-#define STBTT_MACSTYLE_NONE         8   // <= not same as 0, this makes us check the bitfield is 0--extern int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2);-// returns 1/0 whether the first string interpreted as utf8 is identical to-// the second string interpreted as big-endian utf16... useful for strings from next func--extern char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID);-// returns the string (which may be big-endian double byte, e.g. for unicode)-// and puts the length in bytes in *length.-//-// some of the values for the IDs are below; for more see the truetype spec:-//     http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html-//     http://www.microsoft.com/typography/otspec/name.htm--enum { // platformID-   STBTT_PLATFORM_ID_UNICODE   =0,-   STBTT_PLATFORM_ID_MAC       =1,-   STBTT_PLATFORM_ID_ISO       =2,-   STBTT_PLATFORM_ID_MICROSOFT =3-};--enum { // encodingID for STBTT_PLATFORM_ID_UNICODE-   STBTT_UNICODE_EID_UNICODE_1_0    =0,-   STBTT_UNICODE_EID_UNICODE_1_1    =1,-   STBTT_UNICODE_EID_ISO_10646      =2,-   STBTT_UNICODE_EID_UNICODE_2_0_BMP=3,-   STBTT_UNICODE_EID_UNICODE_2_0_FULL=4,-};--enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT-   STBTT_MS_EID_SYMBOL        =0,-   STBTT_MS_EID_UNICODE_BMP   =1,-   STBTT_MS_EID_SHIFTJIS      =2,-   STBTT_MS_EID_UNICODE_FULL  =10,-};--enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes-   STBTT_MAC_EID_ROMAN        =0,   STBTT_MAC_EID_ARABIC       =4,-   STBTT_MAC_EID_JAPANESE     =1,   STBTT_MAC_EID_HEBREW       =5,-   STBTT_MAC_EID_CHINESE_TRAD =2,   STBTT_MAC_EID_GREEK        =6,-   STBTT_MAC_EID_KOREAN       =3,   STBTT_MAC_EID_RUSSIAN      =7,-};--enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID...-       // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs-   STBTT_MS_LANG_ENGLISH     =0x0409,   STBTT_MS_LANG_ITALIAN     =0x0410,-   STBTT_MS_LANG_CHINESE     =0x0804,   STBTT_MS_LANG_JAPANESE    =0x0411,-   STBTT_MS_LANG_DUTCH       =0x0413,   STBTT_MS_LANG_KOREAN      =0x0412,-   STBTT_MS_LANG_FRENCH      =0x040c,   STBTT_MS_LANG_RUSSIAN     =0x0419,-   STBTT_MS_LANG_GERMAN      =0x0407,   STBTT_MS_LANG_SPANISH     =0x0409,-   STBTT_MS_LANG_HEBREW      =0x040d,   STBTT_MS_LANG_SWEDISH     =0x041D,-};--enum { // languageID for STBTT_PLATFORM_ID_MAC-   STBTT_MAC_LANG_ENGLISH      =0 ,   STBTT_MAC_LANG_JAPANESE     =11,-   STBTT_MAC_LANG_ARABIC       =12,   STBTT_MAC_LANG_KOREAN       =23,-   STBTT_MAC_LANG_DUTCH        =4 ,   STBTT_MAC_LANG_RUSSIAN      =32,-   STBTT_MAC_LANG_FRENCH       =1 ,   STBTT_MAC_LANG_SPANISH      =6 ,-   STBTT_MAC_LANG_GERMAN       =2 ,   STBTT_MAC_LANG_SWEDISH      =5 ,-   STBTT_MAC_LANG_HEBREW       =10,   STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33,-   STBTT_MAC_LANG_ITALIAN      =3 ,   STBTT_MAC_LANG_CHINESE_TRAD =19,-};--#ifdef __cplusplus-}-#endif--#endif // __STB_INCLUDE_STB_TRUETYPE_H__--///////////////////////////////////////////////////////////////////////////////-///////////////////////////////////////////////////////////////////////////////-////-////   IMPLEMENTATION-////-////--#ifdef STB_TRUETYPE_IMPLEMENTATION--//////////////////////////////////////////////////////////////////////////-//-// accessors to parse data from file-//--// on platforms that don't allow misaligned reads, if we want to allow-// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE--#define ttBYTE(p)     (* (stbtt_uint8 *) (p))-#define ttCHAR(p)     (* (stbtt_int8 *) (p))-#define ttFixed(p)    ttLONG(p)--#if defined(STB_TRUETYPE_BIGENDIAN) && !defined(ALLOW_UNALIGNED_TRUETYPE)--   #define ttUSHORT(p)   (* (stbtt_uint16 *) (p))-   #define ttSHORT(p)    (* (stbtt_int16 *) (p))-   #define ttULONG(p)    (* (stbtt_uint32 *) (p))-   #define ttLONG(p)     (* (stbtt_int32 *) (p))--#else--   stbtt_uint16 ttUSHORT(const stbtt_uint8 *p) { return p[0]*256 + p[1]; }-   stbtt_int16 ttSHORT(const stbtt_uint8 *p)   { return p[0]*256 + p[1]; }-   stbtt_uint32 ttULONG(const stbtt_uint8 *p)  { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }-   stbtt_int32 ttLONG(const stbtt_uint8 *p)    { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }--#endif--#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3))-#define stbtt_tag(p,str)           stbtt_tag4(p,str[0],str[1],str[2],str[3])--static int stbtt__isfont(const stbtt_uint8 *font)-{-   // check the version number-   if (stbtt_tag(font, "1"))   return 1; // TrueType 1-   if (stbtt_tag(font, "typ1"))   return 1; // TrueType with type 1 font -- we don't support this!-   if (stbtt_tag(font, "OTTO"))   return 1; // OpenType with CFF-   if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0-   return 0;-}--// @OPTIMIZE: binary search-static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, char *tag)-{-   stbtt_int32 num_tables = ttUSHORT(data+fontstart+4);-   stbtt_uint32 tabledir = fontstart + 12;-   stbtt_int32 i;-   for (i=0; i < num_tables; ++i) {-      stbtt_uint32 loc = tabledir + 16*i;-      if (stbtt_tag(data+loc+0, tag))-         return ttULONG(data+loc+8);-   }-   return 0;-}--int stbtt_GetFontOffsetForIndex(const unsigned char *font_collection, int index)-{-   // if it's just a font, there's only one valid index-   if (stbtt__isfont(font_collection))-      return index == 0 ? 0 : -1;--   // check if it's a TTC-   if (stbtt_tag(font_collection, "ttcf")) {-      // version 1?-      if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {-         stbtt_int32 n = ttLONG(font_collection+8);-         if (index >= n)-            return -1;-         return ttULONG(font_collection+12+index*14);-      }-   }-   return -1;-}--int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data2, int fontstart)-{-   stbtt_uint8 *data = (stbtt_uint8 *) data2;-   stbtt_uint32 cmap, t;-   stbtt_int32 i,numTables;--   info->data = data;-   info->fontstart = fontstart;--   cmap = stbtt__find_table(data, fontstart, "cmap");-   info->loca = stbtt__find_table(data, fontstart, "loca");-   info->head = stbtt__find_table(data, fontstart, "head");-   info->glyf = stbtt__find_table(data, fontstart, "glyf");-   info->hhea = stbtt__find_table(data, fontstart, "hhea");-   info->hmtx = stbtt__find_table(data, fontstart, "hmtx");-   if (!cmap || !info->loca || !info->head || !info->glyf || !info->hhea || !info->hmtx)-      return 0;--   t = stbtt__find_table(data, fontstart, "maxp");-   if (t)-      info->numGlyphs = ttUSHORT(data+t+4);-   else-      info->numGlyphs = 0xffff;--   // find a cmap encoding table we understand *now* to avoid searching-   // later. (todo: could make this installable)-   // the same regardless of glyph.-   numTables = ttUSHORT(data + cmap + 2);-   info->index_map = 0;-   for (i=0; i < numTables; ++i) {-      stbtt_uint32 encoding_record = cmap + 4 + 8 * i;-      // find an encoding we understand:-      switch(ttUSHORT(data+encoding_record)) {-         case STBTT_PLATFORM_ID_MICROSOFT:-            switch (ttUSHORT(data+encoding_record+2)) {-               case STBTT_MS_EID_UNICODE_BMP:-               case STBTT_MS_EID_UNICODE_FULL:-                  // MS/Unicode-                  info->index_map = cmap + ttULONG(data+encoding_record+4);-                  break;-            }-            break;-      }-   }-   if (info->index_map == 0)-      return 0;--   info->indexToLocFormat = ttUSHORT(data+info->head + 50);-   return 1;-}--int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint)-{-   stbtt_uint8 *data = info->data;-   stbtt_uint32 index_map = info->index_map;--   stbtt_uint16 format = ttUSHORT(data + index_map + 0);-   if (format == 0) { // apple byte encoding-      stbtt_int32 bytes = ttUSHORT(data + index_map + 2);-      if (unicode_codepoint < bytes-6)-         return ttBYTE(data + index_map + 6 + unicode_codepoint);-      return 0;-   } else if (format == 6) {-      stbtt_uint32 first = ttUSHORT(data + index_map + 6);-      stbtt_uint32 count = ttUSHORT(data + index_map + 8);-      if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count)-         return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2);-      return 0;-   } else if (format == 2) {-      STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean-      return 0;-   } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges-      stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1;-      stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1;-      stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10);-      stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1;-      stbtt_uint16 item, offset, start, end;--      // do a binary search of the segments-      stbtt_uint32 endCount = index_map + 14;-      stbtt_uint32 search = endCount;--      if (unicode_codepoint > 0xffff)-         return 0;--      // they lie from endCount .. endCount + segCount-      // but searchRange is the nearest power of two, so...-      if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2))-         search += rangeShift*2;--      // now decrement to bias correctly to find smallest-      search -= 2;-      while (entrySelector) {-         stbtt_uint16 start, end;-         searchRange >>= 1;-         start = ttUSHORT(data + search + 2 + segcount*2 + 2);-         end = ttUSHORT(data + search + 2);-         start = ttUSHORT(data + search + searchRange*2 + segcount*2 + 2);-         end = ttUSHORT(data + search + searchRange*2);-         if (unicode_codepoint > end)-            search += searchRange*2;-         --entrySelector;-      }-      search += 2;--      item = (stbtt_uint16) ((search - endCount) >> 1);--      STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item));-      start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);-      end = ttUSHORT(data + index_map + 14 + 2 + 2*item);-      if (unicode_codepoint < start)-         return 0;--      offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);-      if (offset == 0)-         return unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item);--      return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item);-   } else if (format == 12) {-      stbtt_uint16 ngroups = ttUSHORT(data+index_map+6);-      stbtt_int32 low,high;-      stbtt_uint16 g = 0;-      low = 0; high = (stbtt_int32)ngroups;-      // Binary search the right group.-      while (low <= high) {-         stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high-         stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12);-         stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4);-         if ((stbtt_uint32) unicode_codepoint < start_char)-            high = mid-1;-         else if ((stbtt_uint32) unicode_codepoint > end_char)-            low = mid+1;-         else {-            stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8);-            return start_glyph + unicode_codepoint-start_char;-         }-      }-      return 0; // not found-   }-   // @TODO-   STBTT_assert(0);-   return 0;-}--int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices)-{-   return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices);-}--static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int16 x, stbtt_int16 y, stbtt_int16 cx, stbtt_int16 cy)-{-   v->type = type;-   v->x = x;-   v->y = y;-   v->cx = cx;-   v->cy = cy;-}--static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index)-{-   int g1,g2;--   if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range-   if (info->indexToLocFormat >= 2)    return -1; // unknown index->glyph map format--   if (info->indexToLocFormat == 0) {-      g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2;-      g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2;-   } else {-      g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4);-      g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4);-   }--   return g1==g2 ? -1 : g1; // if length is 0, return -1-}--int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)-{-   int g = stbtt__GetGlyfOffset(info, glyph_index);-   if (g < 0) return 0;--   if (x0) *x0 = ttSHORT(info->data + g + 2);-   if (y0) *y0 = ttSHORT(info->data + g + 4);-   if (x1) *x1 = ttSHORT(info->data + g + 6);-   if (y1) *y1 = ttSHORT(info->data + g + 8);-   return 1;-}--int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1)-{-   return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1);-}--int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)-{-   stbtt_int16 numberOfContours;-   stbtt_uint8 *endPtsOfContours;-   stbtt_uint8 *data = info->data;-   stbtt_vertex *vertices=0;-   int num_vertices=0;-   int g = stbtt__GetGlyfOffset(info, glyph_index);--   *pvertices = NULL;--   if (g < 0) return 0;--   numberOfContours = ttSHORT(data + g);--   if (numberOfContours > 0) {-      stbtt_uint8 flags=0,flagcount;-      stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off;-      stbtt_int16 x,y,cx,cy,sx,sy;-      stbtt_uint8 *points;-      endPtsOfContours = (data + g + 10);-      ins = ttUSHORT(data + g + 10 + numberOfContours * 2);-      points = data + g + 10 + numberOfContours * 2 + 2 + ins;--      n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2);--      m = n + numberOfContours;  // a loose bound on how many vertices we might need-      vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata);-      if (vertices == 0)-         return 0;--      next_move = 0;-      flagcount=0;--      // in first pass, we load uninterpreted data into the allocated array-      // above, shifted to the end of the array so we won't overwrite it when-      // we create our final data starting from the front--      off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated--      // first load flags--      for (i=0; i < n; ++i) {-         if (flagcount == 0) {-            flags = *points++;-            if (flags & 8)-               flagcount = *points++;-         } else-            --flagcount;-         vertices[off+i].type = flags;-      }--      // now load x coordinates-      x=0;-      for (i=0; i < n; ++i) {-         flags = vertices[off+i].type;-         if (flags & 2) {-            stbtt_int16 dx = *points++;-            x += (flags & 16) ? dx : -dx; // ???-         } else {-            if (!(flags & 16)) {-               x = x + (stbtt_int16) (points[0]*256 + points[1]);-               points += 2;-            }-         }-         vertices[off+i].x = x;-      }--      // now load y coordinates-      y=0;-      for (i=0; i < n; ++i) {-         flags = vertices[off+i].type;-         if (flags & 4) {-            stbtt_int16 dy = *points++;-            y += (flags & 32) ? dy : -dy; // ???-         } else {-            if (!(flags & 32)) {-               y = y + (stbtt_int16) (points[0]*256 + points[1]);-               points += 2;-            }-         }-         vertices[off+i].y = y;-      }--      // now convert them to our format-      num_vertices=0;-      sx = sy = cx = cy = 0;-      for (i=0; i < n; ++i) {-         flags = vertices[off+i].type;-         x     = (stbtt_int16) vertices[off+i].x;-         y     = (stbtt_int16) vertices[off+i].y;-         if (next_move == i) {-            // when we get to the end, we have to close the shape explicitly-            if (i != 0) {-               if (was_off)-                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy);-               else-                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0);-            }--            // now start the new one               -            stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,x,y,0,0);-            next_move = 1 + ttUSHORT(endPtsOfContours+j*2);-            ++j;-            was_off = 0;-            sx = x;-            sy = y;-         } else {-            if (!(flags & 1)) { // if it's a curve-               if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint-                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy);-               cx = x;-               cy = y;-               was_off = 1;-            } else {-               if (was_off)-                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy);-               else-                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0);-               was_off = 0;-            }-         }-      }-      if (i != 0) {-         if (was_off)-            stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy);-         else-            stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0);-      }-   } else if (numberOfContours == -1) {-      // Compound shapes.-      int more = 1;-      stbtt_uint8 *comp = data + g + 10;-      num_vertices = 0;-      vertices = 0;-      while (more) {-         stbtt_uint16 flags, gidx;-         int comp_num_verts = 0, i;-         stbtt_vertex *comp_verts = 0, *tmp = 0;-         float mtx[6] = {1,0,0,1,0,0}, m, n;-         -         flags = ttSHORT(comp); comp+=2;-         gidx = ttSHORT(comp); comp+=2;--         if (flags & 2) { // XY values-            if (flags & 1) { // shorts-               mtx[4] = ttSHORT(comp); comp+=2;-               mtx[5] = ttSHORT(comp); comp+=2;-            } else {-               mtx[4] = ttCHAR(comp); comp+=1;-               mtx[5] = ttCHAR(comp); comp+=1;-            }-         }-         else {-            // @TODO handle matching point-            STBTT_assert(0);-         }-         if (flags & (1<<3)) { // WE_HAVE_A_SCALE-            mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;-            mtx[1] = mtx[2] = 0;-         } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE-            mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;-            mtx[1] = mtx[2] = 0;-            mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;-         } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO-            mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;-            mtx[1] = ttSHORT(comp)/16384.0f; comp+=2;-            mtx[2] = ttSHORT(comp)/16384.0f; comp+=2;-            mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;-         }-         -         // Find transformation scales.-         m = (float) sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]);-         n = (float) sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]);--         // Get indexed glyph.-         comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts);-         if (comp_num_verts > 0) {-            // Transform vertices.-            for (i = 0; i < comp_num_verts; ++i) {-               stbtt_vertex* v = &comp_verts[i];-               stbtt_vertex_type x,y;-               x=v->x; y=v->y;-               v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));-               v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));-               x=v->cx; y=v->cy;-               v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));-               v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));-            }-            // Append vertices.-            tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata);-            if (!tmp) {-               if (vertices) STBTT_free(vertices, info->userdata);-               if (comp_verts) STBTT_free(comp_verts, info->userdata);-               return 0;-            }-            if (num_vertices > 0) memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));-            memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));-            if (vertices) STBTT_free(vertices, info->userdata);-            vertices = tmp;-            STBTT_free(comp_verts, info->userdata);-            num_vertices += comp_num_verts;-         }-         // More components ?-         more = flags & (1<<5);-      }-   } else if (numberOfContours < 0) {-      // @TODO other compound variations?-      STBTT_assert(0);-   } else {-      // numberOfCounters == 0, do nothing-   }--   *pvertices = vertices;-   return num_vertices;-}--void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing)-{-   stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34);-   if (glyph_index < numOfLongHorMetrics) {-      if (advanceWidth)     *advanceWidth    = ttSHORT(info->data + info->hmtx + 4*glyph_index);-      if (leftSideBearing)  *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2);-   } else {-      if (advanceWidth)     *advanceWidth    = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1));-      if (leftSideBearing)  *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics));-   }-}--int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)-{-   return 0;-}--int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2)-{-   return 0;-}--void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing)-{-   stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing);-}--void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap)-{-   if (ascent ) *ascent  = ttSHORT(info->data+info->hhea + 4);-   if (descent) *descent = ttSHORT(info->data+info->hhea + 6);-   if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8);-}--float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height)-{-   int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6);-   return (float) height / fheight;-}--void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)-{-   STBTT_free(v, info->userdata);-}--//////////////////////////////////////////////////////////////////////////////-//-// antialiasing software rasterizer-//--void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)-{-   int x0,y0,x1,y1;-   if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1))-      x0=y0=x1=y1=0; // e.g. space character-   // now move to integral bboxes (treating pixels as little squares, what pixels get touched)?-   if (ix0) *ix0 =  STBTT_ifloor(x0 * scale_x);-   if (iy0) *iy0 = -STBTT_iceil (y1 * scale_y);-   if (ix1) *ix1 =  STBTT_iceil (x1 * scale_x);-   if (iy1) *iy1 = -STBTT_ifloor(y0 * scale_y);-}--void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)-{-   stbtt_GetGlyphBitmapBox(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y, ix0,iy0,ix1,iy1);-}--typedef struct stbtt__edge {-   float x0,y0, x1,y1;-   int invert;-} stbtt__edge;--typedef struct stbtt__active_edge-{-   int x,dx;-   float ey;-   struct stbtt__active_edge *next;-   int valid;-} stbtt__active_edge;--#define FIXSHIFT   10-#define FIX        (1 << FIXSHIFT)-#define FIXMASK    (FIX-1)--static stbtt__active_edge *new_active(stbtt__edge *e, int off_x, float start_point, void *userdata)-{-   stbtt__active_edge *z = (stbtt__active_edge *) STBTT_malloc(sizeof(*z), userdata); // @TODO: make a pool of these!!!-   float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);-   STBTT_assert(e->y0 <= start_point);-   if (!z) return z;-   // round dx down to avoid going too far-   if (dxdy < 0)-      z->dx = -STBTT_ifloor(FIX * -dxdy);-   else-      z->dx = STBTT_ifloor(FIX * dxdy);-   z->x = STBTT_ifloor(FIX * (e->x0 + dxdy * (start_point - e->y0)));-   z->x -= off_x * FIX;-   z->ey = e->y1;-   z->next = 0;-   z->valid = e->invert ? 1 : -1;-   return z;-}--// note: this routine clips fills that extend off the edges... ideally this-// wouldn't happen, but it could happen if the truetype glyph bounding boxes-// are wrong, or if the user supplies a too-small bitmap-static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight)-{-   // non-zero winding fill-   int x0=0, w=0;--   while (e) {-      if (w == 0) {-         // if we're currently at zero, we need to record the edge start point-         x0 = e->x; w += e->valid;-      } else {-         int x1 = e->x; w += e->valid;-         // if we went to zero, we need to draw-         if (w == 0) {-            int i = x0 >> FIXSHIFT;-            int j = x1 >> FIXSHIFT;--            if (i < len && j >= 0) {-               if (i == j) {-                  // x0,x1 are the same pixel, so compute combined coverage-                  scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> FIXSHIFT);-               } else {-                  if (i >= 0) // add antialiasing for x0-                     scanline[i] = scanline[i] + (stbtt_uint8) (((FIX - (x0 & FIXMASK)) * max_weight) >> FIXSHIFT);-                  else-                     i = -1; // clip--                  if (j < len) // add antialiasing for x1-                     scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & FIXMASK) * max_weight) >> FIXSHIFT);-                  else-                     j = len; // clip--                  for (++i; i < j; ++i) // fill pixels between x0 and x1-                     scanline[i] = scanline[i] + (stbtt_uint8) max_weight;-               }-            }-         }-      }-      -      e = e->next;-   }-}--static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)-{-   stbtt__active_edge *active = NULL;-   int y,j=0;-   int max_weight = (255 / vsubsample);  // weight per vertical scanline-   int s; // vertical subsample index-   unsigned char scanline_data[512], *scanline;--   if (result->w > 512)-      scanline = (unsigned char *) STBTT_malloc(result->w, userdata);-   else-      scanline = scanline_data;--   y = off_y * vsubsample;-   e[n].y0 = (off_y + result->h) * (float) vsubsample + 1;--   while (j < result->h) {-      STBTT_memset(scanline, 0, result->w);-      for (s=0; s < vsubsample; ++s) {-         // find center of pixel for this scanline-         float scan_y = y + 0.5f;-         stbtt__active_edge **step = &active;--         // update all active edges;-         // remove all active edges that terminate before the center of this scanline-         while (*step) {-            stbtt__active_edge * z = *step;-            if (z->ey <= scan_y) {-               *step = z->next; // delete from list-               STBTT_assert(z->valid);-               z->valid = 0;-               STBTT_free(z, userdata);-            } else {-               z->x += z->dx; // advance to position for current scanline-               step = &((*step)->next); // advance through list-            }-         }--         // resort the list if needed-         for(;;) {-            int changed=0;-            step = &active;-            while (*step && (*step)->next) {-               if ((*step)->x > (*step)->next->x) {-                  stbtt__active_edge *t = *step;-                  stbtt__active_edge *q = t->next;--                  t->next = q->next;-                  q->next = t;-                  *step = q;-                  changed = 1;-               }-               step = &(*step)->next;-            }-            if (!changed) break;-         }--         // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline-         while (e->y0 <= scan_y) {-            if (e->y1 > scan_y) {-               stbtt__active_edge *z = new_active(e, off_x, scan_y, userdata);-               // find insertion point-               if (active == NULL)-                  active = z;-               else if (z->x < active->x) {-                  // insert at front-                  z->next = active;-                  active = z;-               } else {-                  // find thing to insert AFTER-                  stbtt__active_edge *p = active;-                  while (p->next && p->next->x < z->x)-                     p = p->next;-                  // at this point, p->next->x is NOT < z->x-                  z->next = p->next;-                  p->next = z;-               }-            }-            ++e;-         }--         // now process all active edges in XOR fashion-         if (active)-            stbtt__fill_active_edges(scanline, result->w, active, max_weight);--         ++y;-      }-      STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w);-      ++j;-   }--   while (active) {-      stbtt__active_edge *z = active;-      active = active->next;-      STBTT_free(z, userdata);-   }--   if (scanline != scanline_data)-      STBTT_free(scanline, userdata);-}--static int stbtt__edge_compare(const void *p, const void *q)-{-   stbtt__edge *a = (stbtt__edge *) p;-   stbtt__edge *b = (stbtt__edge *) q;--   if (a->y0 < b->y0) return -1;-   if (a->y0 > b->y0) return  1;-   return 0;-}--typedef struct-{-   float x,y;-} stbtt__point;--static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, int off_x, int off_y, int invert, void *userdata)-{-   float y_scale_inv = invert ? -scale_y : scale_y;-   stbtt__edge *e;-   int n,i,j,k,m;-   int vsubsample = result->h < 8 ? 15 : 5;-   // vsubsample should divide 255 evenly; otherwise we won't reach full opacity--   // now we have to blow out the windings into explicit edge lists-   n = 0;-   for (i=0; i < windings; ++i)-      n += wcount[i];--   e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel-   if (e == 0) return;-   n = 0;--   m=0;-   for (i=0; i < windings; ++i) {-      stbtt__point *p = pts + m;-      m += wcount[i];-      j = wcount[i]-1;-      for (k=0; k < wcount[i]; j=k++) {-         int a=k,b=j;-         // skip the edge if horizontal-         if (p[j].y == p[k].y)-            continue;-         // add edge from j to k to the list-         e[n].invert = 0;-         if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) {-            e[n].invert = 1;-            a=j,b=k;-         }-         e[n].x0 = p[a].x * scale_x;-         e[n].y0 = p[a].y * y_scale_inv * vsubsample;-         e[n].x1 = p[b].x * scale_x;-         e[n].y1 = p[b].y * y_scale_inv * vsubsample;-         ++n;-      }-   }--   // now sort the edges by their highest point (should snap to integer, and then by x)-   STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare);--   // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule-   stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata);--   STBTT_free(e, userdata);-}--static void stbtt__add_point(stbtt__point *points, int n, float x, float y)-{-   if (!points) return; // during first pass, it's unallocated-   points[n].x = x;-   points[n].y = y;-}--// tesselate until threshhold p is happy... @TODO warped to compensate for non-linear stretching-static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n)-{-   // midpoint-   float mx = (x0 + 2*x1 + x2)/4;-   float my = (y0 + 2*y1 + y2)/4;-   // versus directly drawn line-   float dx = (x0+x2)/2 - mx;-   float dy = (y0+y2)/2 - my;-   if (n > 16) // 65536 segments on one curve better be enough!-      return 1;-   if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA-      stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1);-      stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1);-   } else {-      stbtt__add_point(points, *num_points,x2,y2);-      *num_points = *num_points+1;-   }-   return 1;-}--// returns number of contours-stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata)-{-   stbtt__point *points=0;-   int num_points=0;--   float objspace_flatness_squared = objspace_flatness * objspace_flatness;-   int i,n=0,start=0, pass;--   // count how many "moves" there are to get the contour count-   for (i=0; i < num_verts; ++i)-      if (vertices[i].type == STBTT_vmove)-         ++n;--   *num_contours = n;-   if (n == 0) return 0;--   *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata);--   if (*contour_lengths == 0) {-      *num_contours = 0;-      return 0;-   }--   // make two passes through the points so we don't need to realloc-   for (pass=0; pass < 2; ++pass) {-      float x=0,y=0;-      if (pass == 1) {-         points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata);-         if (points == NULL) goto error;-      }-      num_points = 0;-      n= -1;-      for (i=0; i < num_verts; ++i) {-         switch (vertices[i].type) {-            case STBTT_vmove:-               // start the next contour-               if (n >= 0)-                  (*contour_lengths)[n] = num_points - start;-               ++n;-               start = num_points;--               x = vertices[i].x, y = vertices[i].y;-               stbtt__add_point(points, num_points++, x,y);-               break;-            case STBTT_vline:-               x = vertices[i].x, y = vertices[i].y;-               stbtt__add_point(points, num_points++, x, y);-               break;-            case STBTT_vcurve:-               stbtt__tesselate_curve(points, &num_points, x,y,-                                        vertices[i].cx, vertices[i].cy,-                                        vertices[i].x,  vertices[i].y,-                                        objspace_flatness_squared, 0);-               x = vertices[i].x, y = vertices[i].y;-               break;-         }-      }-      (*contour_lengths)[n] = num_points - start;-   }--   return points;-error:-   STBTT_free(points, userdata);-   STBTT_free(*contour_lengths, userdata);-   *contour_lengths = 0;-   *num_contours = 0;-   return NULL;-}--void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, int x_off, int y_off, int invert, void *userdata)-{-   float scale = scale_x > scale_y ? scale_y : scale_x;-   int winding_count, *winding_lengths;-   stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);-   if (windings) {-      stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, x_off, y_off, invert, userdata);-      STBTT_free(winding_lengths, userdata);-      STBTT_free(windings, userdata);-   }-}--void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata)-{-   STBTT_free(bitmap, userdata);-}--unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff)-{-   int ix0,iy0,ix1,iy1;-   stbtt__bitmap gbm;-   stbtt_vertex *vertices;   -   int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);--   if (scale_x == 0) scale_x = scale_y;-   if (scale_y == 0) {-      if (scale_x == 0) return NULL;-      scale_y = scale_x;-   }--   stbtt_GetGlyphBitmapBox(info, glyph, scale_x, scale_y, &ix0,&iy0,&ix1,&iy1);--   // now we get the size-   gbm.w = (ix1 - ix0);-   gbm.h = (iy1 - iy0);-   gbm.pixels = NULL; // in case we error--   if (width ) *width  = gbm.w;-   if (height) *height = gbm.h;-   if (xoff  ) *xoff   = ix0;-   if (yoff  ) *yoff   = iy0;-   -   if (gbm.w && gbm.h) {-      gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata);-      if (gbm.pixels) {-         gbm.stride = gbm.w;--         stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, ix0, iy0, 1, info->userdata);-      }-   }-   STBTT_free(vertices, info->userdata);-   return gbm.pixels;-}   --void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph)-{-   int ix0,iy0;-   stbtt_vertex *vertices;   -   int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);-   stbtt__bitmap gbm;   --   stbtt_GetGlyphBitmapBox(info, glyph, scale_x, scale_y, &ix0,&iy0,0,0);-   gbm.pixels = output;-   gbm.w = out_w;-   gbm.h = out_h;-   gbm.stride = out_stride;--   if (gbm.w && gbm.h)-      stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, ix0,iy0, 1, info->userdata);--   STBTT_free(vertices, info->userdata);-}--unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff)-{-   return stbtt_GetGlyphBitmap(info, scale_x, scale_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);-}   --void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint)-{-   stbtt_MakeGlyphBitmap(info, output, out_w, out_h, out_stride, scale_x, scale_y, stbtt_FindGlyphIndex(info,codepoint));-}--//////////////////////////////////////////////////////////////////////////////-//-// bitmap baking-//-// This is SUPER-SHITTY packing to keep source code small--extern int stbtt_BakeFontBitmap(const unsigned char *data, int offset,  // font location (use offset=0 for plain .ttf)-                                float pixel_height,                     // height of font in pixels-                                unsigned char *pixels, int pw, int ph,  // bitmap to be filled in-                                int first_char, int num_chars,          // characters to bake-                                stbtt_bakedchar *chardata)-{-   float scale;-   int x,y,bottom_y, i;-   stbtt_fontinfo f;-   stbtt_InitFont(&f, data, offset);-   STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels-   x=y=1;-   bottom_y = 1;--   scale = stbtt_ScaleForPixelHeight(&f, pixel_height);--   for (i=0; i < num_chars; ++i) {-      int advance, lsb, x0,y0,x1,y1,gw,gh;-      int g = stbtt_FindGlyphIndex(&f, first_char + i);-      stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb);-      stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1);-      gw = x1-x0;-      gh = y1-y0;-      if (x + gw + 1 >= pw)-         y = bottom_y, x = 1; // advance to next row-      if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row-         return -i;-      STBTT_assert(x+gw < pw);-      STBTT_assert(y+gh < ph);-      stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g);-      chardata[i].x0 = (stbtt_int16) x;-      chardata[i].y0 = (stbtt_int16) y;-      chardata[i].x1 = (stbtt_int16) (x + gw);-      chardata[i].y1 = (stbtt_int16) (y + gh);-      chardata[i].xadvance = scale * advance;-      chardata[i].xoff     = (float) x0;-      chardata[i].yoff     = (float) y0;-      x = x + gw + 2;-      if (y+gh+2 > bottom_y)-         bottom_y = y+gh+2;-   }-   return bottom_y;-}--void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule)-{-   float d3d_bias = opengl_fillrule ? 0 : -0.5f;-   float ipw = 1.0f / pw, iph = 1.0f / ph;-   stbtt_bakedchar *b = chardata + char_index;-   int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5);-   int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5);--   q->x0 = round_x + d3d_bias;-   q->y0 = round_y + d3d_bias;-   q->x1 = round_x + b->x1 - b->x0 + d3d_bias;-   q->y1 = round_y + b->y1 - b->y0 + d3d_bias;--   q->s0 = b->x0 * ipw;-   q->t0 = b->y0 * ipw;-   q->s1 = b->x1 * iph;-   q->t1 = b->y1 * iph;--   *xpos += b->xadvance;-}--//////////////////////////////////////////////////////////////////////////////-//-// font name matching -- recommended not to use this-//--// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string-static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) -{-   stbtt_int32 i=0;--   // convert utf16 to utf8 and compare the results while converting-   while (len2) {-      stbtt_uint16 ch = s2[0]*256 + s2[1];-      if (ch < 0x80) {-         if (i >= len1) return -1;-         if (s1[i++] != ch) return -1;-      } else if (ch < 0x800) {-         if (i+1 >= len1) return -1;-         if (s1[i++] != 0xc0 + (ch >> 6)) return -1;-         if (s1[i++] != 0x80 + (ch & 0x3f)) return -1;-      } else if (ch >= 0xd800 && ch < 0xdc00) {-         stbtt_uint32 c;-         stbtt_uint16 ch2 = s2[2]*256 + s2[3];-         if (i+3 >= len1) return -1;-         c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000;-         if (s1[i++] != 0xf0 + (c >> 18)) return -1;-         if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1;-         if (s1[i++] != 0x80 + ((c >>  6) & 0x3f)) return -1;-         if (s1[i++] != 0x80 + ((c      ) & 0x3f)) return -1;-         s2 += 2; // plus another 2 below-         len2 -= 2;-      } else if (ch >= 0xdc00 && ch < 0xe000) {-         return -1;-      } else {-         if (i+2 >= len1) return -1;-         if (s1[i++] != 0xe0 + (ch >> 12)) return -1;-         if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1;-         if (s1[i++] != 0x80 + ((ch     ) & 0x3f)) return -1;-      }-      s2 += 2;-      len2 -= 2;-   }-   return i;-}--int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) -{-   return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2);-}--// returns results in whatever encoding you request... but note that 2-byte encodings-// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare-char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID)-{-   stbtt_int32 i,count,stringOffset;-   stbtt_uint8 *fc = font->data;-   stbtt_uint32 offset = font->fontstart;-   stbtt_uint32 nm = stbtt__find_table(fc, offset, "name");-   if (!nm) return NULL;--   count = ttUSHORT(fc+nm+2);-   stringOffset = nm + ttUSHORT(fc+nm+4);-   for (i=0; i < count; ++i) {-      stbtt_uint32 loc = nm + 6 + 12 * i;-      if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2)-          && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) {-         *length = ttUSHORT(fc+loc+8);-         return (char *) (fc+stringOffset+ttUSHORT(fc+loc+10));-      }-   }-   return NULL;-}--static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id)-{-   stbtt_int32 i;-   stbtt_int32 count = ttUSHORT(fc+nm+2);-   stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4);--   for (i=0; i < count; ++i) {-      stbtt_uint32 loc = nm + 6 + 12 * i;-      stbtt_int32 id = ttUSHORT(fc+loc+6);-      if (id == target_id) {-         // find the encoding-         stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4);--         // is this a Unicode encoding?-         if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) {-            stbtt_int32 slen = ttUSHORT(fc+loc+8), off = ttUSHORT(fc+loc+10);--            // check if there's a prefix match-            stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen);-            if (matchlen >= 0) {-               // check for target_id+1 immediately following, with same encoding & language-               if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) {-                  stbtt_int32 slen = ttUSHORT(fc+loc+12+8), off = ttUSHORT(fc+loc+12+10);-                  if (slen == 0) {-                     if (matchlen == nlen)-                        return 1;-                  } else if (matchlen < nlen && name[matchlen] == ' ') {-                     ++matchlen;-                     if (stbtt_CompareUTF8toUTF16_bigendian((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen))-                        return 1;-                  }-               } else {-                  // if nothing immediately following-                  if (matchlen == nlen)-                     return 1;-               }-            }-         }--         // @TODO handle other encodings-      }-   }-   return 0;-}--static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags)-{-   stbtt_int32 nlen = STBTT_strlen((char *) name);-   stbtt_uint32 nm,hd;-   if (!stbtt__isfont(fc+offset)) return 0;--   // check italics/bold/underline flags in macStyle...-   if (flags) {-      hd = stbtt__find_table(fc, offset, "head");-      if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0;-   }--   nm = stbtt__find_table(fc, offset, "name");-   if (!nm) return 0;--   if (flags) {-      // if we checked the macStyle flags, then just check the family and ignore the subfamily-      if (stbtt__matchpair(fc, nm, name, nlen, 16, -1))  return 1;-      if (stbtt__matchpair(fc, nm, name, nlen,  1, -1))  return 1;-      if (stbtt__matchpair(fc, nm, name, nlen,  3, -1))  return 1;-   } else {-      if (stbtt__matchpair(fc, nm, name, nlen, 16, 17))  return 1;-      if (stbtt__matchpair(fc, nm, name, nlen,  1,  2))  return 1;-      if (stbtt__matchpair(fc, nm, name, nlen,  3, -1))  return 1;-   }--   return 0;-}--int stbtt_FindMatchingFont(const unsigned char *font_collection, const char *name_utf8, stbtt_int32 flags)-{-   stbtt_int32 i;-   for (i=0;;++i) {-      stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i);-      if (off < 0) return off;-      if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags))-         return off;-   }-}--#endif // STB_TRUETYPE_IMPLEMENTATION+// stb_truetype.h - v1.19 - public domain+// authored from 2009-2016 by Sean Barrett / RAD Game Tools+//+//   This library processes TrueType files:+//        parse files+//        extract glyph metrics+//        extract glyph shapes+//        render glyphs to one-channel bitmaps with antialiasing (box filter)+//        render glyphs to one-channel SDF bitmaps (signed-distance field/function)+//+//   Todo:+//        non-MS cmaps+//        crashproof on bad data+//        hinting? (no longer patented)+//        cleartype-style AA?+//        optimize: use simple memory allocator for intermediates+//        optimize: build edge-list directly from curves+//        optimize: rasterize directly from curves?+//+// ADDITIONAL CONTRIBUTORS+//+//   Mikko Mononen: compound shape support, more cmap formats+//   Tor Andersson: kerning, subpixel rendering+//   Dougall Johnson: OpenType / Type 2 font handling+//   Daniel Ribeiro Maciel: basic GPOS-based kerning+//+//   Misc other:+//       Ryan Gordon+//       Simon Glass+//       github:IntellectualKitty+//       Imanol Celaya+//       Daniel Ribeiro Maciel+//+//   Bug/warning reports/fixes:+//       "Zer" on mollyrocket       Fabian "ryg" Giesen+//       Cass Everitt               Martins Mozeiko+//       stoiko (Haemimont Games)   Cap Petschulat+//       Brian Hook                 Omar Cornut+//       Walter van Niftrik         github:aloucks+//       David Gow                  Peter LaValle+//       David Given                Sergey Popov+//       Ivan-Assen Ivanov          Giumo X. Clanjor+//       Anthony Pesch              Higor Euripedes+//       Johan Duparc               Thomas Fields+//       Hou Qiming                 Derek Vinyard+//       Rob Loach                  Cort Stratton+//       Kenney Phillis Jr.         github:oyvindjam+//       Brian Costabile            github:vassvik+//       +// VERSION HISTORY+//+//   1.19 (2018-02-11) GPOS kerning, STBTT_fmod+//   1.18 (2018-01-29) add missing function+//   1.17 (2017-07-23) make more arguments const; doc fix+//   1.16 (2017-07-12) SDF support+//   1.15 (2017-03-03) make more arguments const+//   1.14 (2017-01-16) num-fonts-in-TTC function+//   1.13 (2017-01-02) support OpenType fonts, certain Apple fonts+//   1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual+//   1.11 (2016-04-02) fix unused-variable warning+//   1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef+//   1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly+//   1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges+//   1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;+//                     variant PackFontRanges to pack and render in separate phases;+//                     fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);+//                     fixed an assert() bug in the new rasterizer+//                     replace assert() with STBTT_assert() in new rasterizer+//+//   Full history can be found at the end of this file.+//+// LICENSE+//+//   See end of file for license information.+//+// USAGE+//+//   Include this file in whatever places neeed to refer to it. In ONE C/C+++//   file, write:+//      #define STB_TRUETYPE_IMPLEMENTATION+//   before the #include of this file. This expands out the actual+//   implementation into that C/C++ file.+//+//   To make the implementation private to the file that generates the implementation,+//      #define STBTT_STATIC+//+//   Simple 3D API (don't ship this, but it's fine for tools and quick start)+//           stbtt_BakeFontBitmap()               -- bake a font to a bitmap for use as texture+//           stbtt_GetBakedQuad()                 -- compute quad to draw for a given char+//+//   Improved 3D API (more shippable):+//           #include "stb_rect_pack.h"           -- optional, but you really want it+//           stbtt_PackBegin()+//           stbtt_PackSetOversampling()          -- for improved quality on small fonts+//           stbtt_PackFontRanges()               -- pack and renders+//           stbtt_PackEnd()+//           stbtt_GetPackedQuad()+//+//   "Load" a font file from a memory buffer (you have to keep the buffer loaded)+//           stbtt_InitFont()+//           stbtt_GetFontOffsetForIndex()        -- indexing for TTC font collections+//           stbtt_GetNumberOfFonts()             -- number of fonts for TTC font collections+//+//   Render a unicode codepoint to a bitmap+//           stbtt_GetCodepointBitmap()           -- allocates and returns a bitmap+//           stbtt_MakeCodepointBitmap()          -- renders into bitmap you provide+//           stbtt_GetCodepointBitmapBox()        -- how big the bitmap must be+//+//   Character advance/positioning+//           stbtt_GetCodepointHMetrics()+//           stbtt_GetFontVMetrics()+//           stbtt_GetFontVMetricsOS2()+//           stbtt_GetCodepointKernAdvance()+//+//   Starting with version 1.06, the rasterizer was replaced with a new,+//   faster and generally-more-precise rasterizer. The new rasterizer more+//   accurately measures pixel coverage for anti-aliasing, except in the case+//   where multiple shapes overlap, in which case it overestimates the AA pixel+//   coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If+//   this turns out to be a problem, you can re-enable the old rasterizer with+//        #define STBTT_RASTERIZER_VERSION 1+//   which will incur about a 15% speed hit.+//+// ADDITIONAL DOCUMENTATION+//+//   Immediately after this block comment are a series of sample programs.+//+//   After the sample programs is the "header file" section. This section+//   includes documentation for each API function.+//+//   Some important concepts to understand to use this library:+//+//      Codepoint+//         Characters are defined by unicode codepoints, e.g. 65 is+//         uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is+//         the hiragana for "ma".+//+//      Glyph+//         A visual character shape (every codepoint is rendered as+//         some glyph)+//+//      Glyph index+//         A font-specific integer ID representing a glyph+//+//      Baseline+//         Glyph shapes are defined relative to a baseline, which is the+//         bottom of uppercase characters. Characters extend both above+//         and below the baseline.+//+//      Current Point+//         As you draw text to the screen, you keep track of a "current point"+//         which is the origin of each character. The current point's vertical+//         position is the baseline. Even "baked fonts" use this model.+//+//      Vertical Font Metrics+//         The vertical qualities of the font, used to vertically position+//         and space the characters. See docs for stbtt_GetFontVMetrics.+//+//      Font Size in Pixels or Points+//         The preferred interface for specifying font sizes in stb_truetype+//         is to specify how tall the font's vertical extent should be in pixels.+//         If that sounds good enough, skip the next paragraph.+//+//         Most font APIs instead use "points", which are a common typographic+//         measurement for describing font size, defined as 72 points per inch.+//         stb_truetype provides a point API for compatibility. However, true+//         "per inch" conventions don't make much sense on computer displays+//         since different monitors have different number of pixels per+//         inch. For example, Windows traditionally uses a convention that+//         there are 96 pixels per inch, thus making 'inch' measurements have+//         nothing to do with inches, and thus effectively defining a point to+//         be 1.333 pixels. Additionally, the TrueType font data provides+//         an explicit scale factor to scale a given font's glyphs to points,+//         but the author has observed that this scale factor is often wrong+//         for non-commercial fonts, thus making fonts scaled in points+//         according to the TrueType spec incoherently sized in practice.+//+// DETAILED USAGE:+//+//  Scale:+//    Select how high you want the font to be, in points or pixels.+//    Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute+//    a scale factor SF that will be used by all other functions.+//+//  Baseline:+//    You need to select a y-coordinate that is the baseline of where+//    your text will appear. Call GetFontBoundingBox to get the baseline-relative+//    bounding box for all characters. SF*-y0 will be the distance in pixels+//    that the worst-case character could extend above the baseline, so if+//    you want the top edge of characters to appear at the top of the+//    screen where y=0, then you would set the baseline to SF*-y0.+//+//  Current point:+//    Set the current point where the first character will appear. The+//    first character could extend left of the current point; this is font+//    dependent. You can either choose a current point that is the leftmost+//    point and hope, or add some padding, or check the bounding box or+//    left-side-bearing of the first character to be displayed and set+//    the current point based on that.+//+//  Displaying a character:+//    Compute the bounding box of the character. It will contain signed values+//    relative to <current_point, baseline>. I.e. if it returns x0,y0,x1,y1,+//    then the character should be displayed in the rectangle from+//    <current_point+SF*x0, baseline+SF*y0> to <current_point+SF*x1,baseline+SF*y1).+//+//  Advancing for the next character:+//    Call GlyphHMetrics, and compute 'current_point += SF * advance'.+// +//+// ADVANCED USAGE+//+//   Quality:+//+//    - Use the functions with Subpixel at the end to allow your characters+//      to have subpixel positioning. Since the font is anti-aliased, not+//      hinted, this is very import for quality. (This is not possible with+//      baked fonts.)+//+//    - Kerning is now supported, and if you're supporting subpixel rendering+//      then kerning is worth using to give your text a polished look.+//+//   Performance:+//+//    - Convert Unicode codepoints to glyph indexes and operate on the glyphs;+//      if you don't do this, stb_truetype is forced to do the conversion on+//      every call.+//+//    - There are a lot of memory allocations. We should modify it to take+//      a temp buffer and allocate from the temp buffer (without freeing),+//      should help performance a lot.+//+// NOTES+//+//   The system uses the raw data found in the .ttf file without changing it+//   and without building auxiliary data structures. This is a bit inefficient+//   on little-endian systems (the data is big-endian), but assuming you're+//   caching the bitmaps or glyph shapes this shouldn't be a big deal.+//+//   It appears to be very hard to programmatically determine what font a+//   given file is in a general way. I provide an API for this, but I don't+//   recommend it.+//+//+// SOURCE STATISTICS (based on v0.6c, 2050 LOC)+//+//   Documentation & header file        520 LOC  \___ 660 LOC documentation+//   Sample code                        140 LOC  /+//   Truetype parsing                   620 LOC  ---- 620 LOC TrueType+//   Software rasterization             240 LOC  \                           .+//   Curve tesselation                  120 LOC   \__ 550 LOC Bitmap creation+//   Bitmap management                  100 LOC   /+//   Baked bitmap interface              70 LOC  /+//   Font name matching & access        150 LOC  ---- 150 +//   C runtime library abstraction       60 LOC  ----  60+//+//+// PERFORMANCE MEASUREMENTS FOR 1.06:+//+//                      32-bit     64-bit+//   Previous release:  8.83 s     7.68 s+//   Pool allocations:  7.72 s     6.34 s+//   Inline sort     :  6.54 s     5.65 s+//   New rasterizer  :  5.63 s     5.00 s++//////////////////////////////////////////////////////////////////////////////+//////////////////////////////////////////////////////////////////////////////+////+////  SAMPLE PROGRAMS+////+//+//  Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless+//+#if 0+#define STB_TRUETYPE_IMPLEMENTATION  // force following include to generate implementation+#include "stb_truetype.h"++unsigned char ttf_buffer[1<<20];+unsigned char temp_bitmap[512*512];++stbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs+GLuint ftex;++void my_stbtt_initfont(void)+{+   fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb"));+   stbtt_BakeFontBitmap(ttf_buffer,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits!+   // can free ttf_buffer at this point+   glGenTextures(1, &ftex);+   glBindTexture(GL_TEXTURE_2D, ftex);+   glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap);+   // can free temp_bitmap at this point+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);+}++void my_stbtt_print(float x, float y, char *text)+{+   // assume orthographic projection with units = screen pixels, origin at top left+   glEnable(GL_TEXTURE_2D);+   glBindTexture(GL_TEXTURE_2D, ftex);+   glBegin(GL_QUADS);+   while (*text) {+      if (*text >= 32 && *text < 128) {+         stbtt_aligned_quad q;+         stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9+         glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0);+         glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0);+         glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1);+         glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1);+      }+      ++text;+   }+   glEnd();+}+#endif+//+//+//////////////////////////////////////////////////////////////////////////////+//+// Complete program (this compiles): get a single bitmap, print as ASCII art+//+#if 0+#include <stdio.h>+#define STB_TRUETYPE_IMPLEMENTATION  // force following include to generate implementation+#include "stb_truetype.h"++char ttf_buffer[1<<25];++int main(int argc, char **argv)+{+   stbtt_fontinfo font;+   unsigned char *bitmap;+   int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20);++   fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb"));++   stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0));+   bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0);++   for (j=0; j < h; ++j) {+      for (i=0; i < w; ++i)+         putchar(" .:ioVM@"[bitmap[j*w+i]>>5]);+      putchar('\n');+   }+   return 0;+}+#endif +//+// Output:+//+//     .ii.+//    @@@@@@.+//   V@Mio@@o+//   :i.  V@V+//     :oM@@M+//   :@@@MM@M+//   @@o  o@M+//  :@@.  M@M+//   @@@o@@@@+//   :M@@V:@@.+//  +//////////////////////////////////////////////////////////////////////////////+// +// Complete program: print "Hello World!" banner, with bugs+//+#if 0+char buffer[24<<20];+unsigned char screen[20][79];++int main(int arg, char **argv)+{+   stbtt_fontinfo font;+   int i,j,ascent,baseline,ch=0;+   float scale, xpos=2; // leave a little padding in case the character extends left+   char *text = "Heljo World!"; // intentionally misspelled to show 'lj' brokenness++   fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb"));+   stbtt_InitFont(&font, buffer, 0);++   scale = stbtt_ScaleForPixelHeight(&font, 15);+   stbtt_GetFontVMetrics(&font, &ascent,0,0);+   baseline = (int) (ascent*scale);++   while (text[ch]) {+      int advance,lsb,x0,y0,x1,y1;+      float x_shift = xpos - (float) floor(xpos);+      stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb);+      stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1);+      stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]);+      // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong+      // because this API is really for baking character bitmaps into textures. if you want to render+      // a sequence of characters, you really need to render each bitmap to a temp buffer, then+      // "alpha blend" that into the working buffer+      xpos += (advance * scale);+      if (text[ch+1])+         xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]);+      ++ch;+   }++   for (j=0; j < 20; ++j) {+      for (i=0; i < 78; ++i)+         putchar(" .:ioVM@"[screen[j][i]>>5]);+      putchar('\n');+   }++   return 0;+}+#endif+++//////////////////////////////////////////////////////////////////////////////+//////////////////////////////////////////////////////////////////////////////+////+////   INTEGRATION WITH YOUR CODEBASE+////+////   The following sections allow you to supply alternate definitions+////   of C library functions used by stb_truetype, e.g. if you don't+////   link with the C runtime library.++#ifdef STB_TRUETYPE_IMPLEMENTATION+   // #define your own (u)stbtt_int8/16/32 before including to override this+   #ifndef stbtt_override_uint8+   typedef unsigned char   stbtt_uint8;+   typedef signed   char   stbtt_int8;+   typedef unsigned short  stbtt_uint16;+   typedef signed   short  stbtt_int16;+   typedef unsigned int    stbtt_uint32;+   typedef signed   int    stbtt_int32;+   #endif++   typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1];+   typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1];++   // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h+   #ifndef STBTT_ifloor+   #include <math.h>+   #define STBTT_ifloor(x)   ((int) floor(x))+   #define STBTT_iceil(x)    ((int) ceil(x))+   #endif++   #ifndef STBTT_sqrt+   #include <math.h>+   #define STBTT_sqrt(x)      sqrt(x)+   #define STBTT_pow(x,y)     pow(x,y)+   #endif++   #ifndef STBTT_fmod+   #include <math.h>+   #define STBTT_fmod(x,y)    fmod(x,y)+   #endif++   #ifndef STBTT_cos+   #include <math.h>+   #define STBTT_cos(x)       cos(x)+   #define STBTT_acos(x)      acos(x)+   #endif++   #ifndef STBTT_fabs+   #include <math.h>+   #define STBTT_fabs(x)      fabs(x)+   #endif++   // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h+   #ifndef STBTT_malloc+   #include <stdlib.h>+   #define STBTT_malloc(x,u)  ((void)(u),malloc(x))+   #define STBTT_free(x,u)    ((void)(u),free(x))+   #endif++   #ifndef STBTT_assert+   #include <assert.h>+   #define STBTT_assert(x)    assert(x)+   #endif++   #ifndef STBTT_strlen+   #include <string.h>+   #define STBTT_strlen(x)    strlen(x)+   #endif++   #ifndef STBTT_memcpy+   #include <string.h>+   #define STBTT_memcpy       memcpy+   #define STBTT_memset       memset+   #endif+#endif++///////////////////////////////////////////////////////////////////////////////+///////////////////////////////////////////////////////////////////////////////+////+////   INTERFACE+////+////++#ifndef __STB_INCLUDE_STB_TRUETYPE_H__+#define __STB_INCLUDE_STB_TRUETYPE_H__++#ifdef STBTT_STATIC+#define STBTT_DEF static+#else+#define STBTT_DEF extern+#endif++#ifdef __cplusplus+extern "C" {+#endif++// private structure+typedef struct+{+   unsigned char *data;+   int cursor;+   int size;+} stbtt__buf;++//////////////////////////////////////////////////////////////////////////////+//+// TEXTURE BAKING API+//+// If you use this API, you only have to call two functions ever.+//++typedef struct+{+   unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap+   float xoff,yoff,xadvance;+} stbtt_bakedchar;++STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,  // font location (use offset=0 for plain .ttf)+                                float pixel_height,                     // height of font in pixels+                                unsigned char *pixels, int pw, int ph,  // bitmap to be filled in+                                int first_char, int num_chars,          // characters to bake+                                stbtt_bakedchar *chardata);             // you allocate this, it's num_chars long+// if return is positive, the first unused row of the bitmap+// if return is negative, returns the negative of the number of characters that fit+// if return is 0, no characters fit and no rows were used+// This uses a very crappy packing.++typedef struct+{+   float x0,y0,s0,t0; // top-left+   float x1,y1,s1,t1; // bottom-right+} stbtt_aligned_quad;++STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph,  // same data as above+                               int char_index,             // character to display+                               float *xpos, float *ypos,   // pointers to current position in screen pixel space+                               stbtt_aligned_quad *q,      // output: quad to draw+                               int opengl_fillrule);       // true if opengl fill rule; false if DX9 or earlier+// Call GetBakedQuad with char_index = 'character - first_char', and it+// creates the quad you need to draw and advances the current position.+//+// The coordinate system used assumes y increases downwards.+//+// Characters will extend both above and below the current position;+// see discussion of "BASELINE" above.+//+// It's inefficient; you might want to c&p it and optimize it.++++//////////////////////////////////////////////////////////////////////////////+//+// NEW TEXTURE BAKING API+//+// This provides options for packing multiple fonts into one atlas, not+// perfectly but better than nothing.++typedef struct+{+   unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap+   float xoff,yoff,xadvance;+   float xoff2,yoff2;+} stbtt_packedchar;++typedef struct stbtt_pack_context stbtt_pack_context;+typedef struct stbtt_fontinfo stbtt_fontinfo;+#ifndef STB_RECT_PACK_VERSION+typedef struct stbrp_rect stbrp_rect;+#endif++STBTT_DEF int  stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context);+// Initializes a packing context stored in the passed-in stbtt_pack_context.+// Future calls using this context will pack characters into the bitmap passed+// in here: a 1-channel bitmap that is width * height. stride_in_bytes is+// the distance from one row to the next (or 0 to mean they are packed tightly+// together). "padding" is the amount of padding to leave between each+// character (normally you want '1' for bitmaps you'll use as textures with+// bilinear filtering).+//+// Returns 0 on failure, 1 on success.++STBTT_DEF void stbtt_PackEnd  (stbtt_pack_context *spc);+// Cleans up the packing context and frees all memory.++#define STBTT_POINT_SIZE(x)   (-(x))++STBTT_DEF int  stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,+                                int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range);+// Creates character bitmaps from the font_index'th font found in fontdata (use+// font_index=0 if you don't know what that is). It creates num_chars_in_range+// bitmaps for characters with unicode values starting at first_unicode_char_in_range+// and increasing. Data for how to render them is stored in chardata_for_range;+// pass these to stbtt_GetPackedQuad to get back renderable quads.+//+// font_size is the full height of the character from ascender to descender,+// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed+// by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE()+// and pass that result as 'font_size':+//       ...,                  20 , ... // font max minus min y is 20 pixels tall+//       ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall++typedef struct+{+   float font_size;+   int first_unicode_codepoint_in_range;  // if non-zero, then the chars are continuous, and this is the first codepoint+   int *array_of_unicode_codepoints;       // if non-zero, then this is an array of unicode codepoints+   int num_chars;+   stbtt_packedchar *chardata_for_range; // output+   unsigned char h_oversample, v_oversample; // don't set these, they're used internally+} stbtt_pack_range;++STBTT_DEF int  stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges);+// Creates character bitmaps from multiple ranges of characters stored in+// ranges. This will usually create a better-packed bitmap than multiple+// calls to stbtt_PackFontRange. Note that you can call this multiple+// times within a single PackBegin/PackEnd.++STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample);+// Oversampling a font increases the quality by allowing higher-quality subpixel+// positioning, and is especially valuable at smaller text sizes.+//+// This function sets the amount of oversampling for all following calls to+// stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given+// pack context. The default (no oversampling) is achieved by h_oversample=1+// and v_oversample=1. The total number of pixels required is+// h_oversample*v_oversample larger than the default; for example, 2x2+// oversampling requires 4x the storage of 1x1. For best results, render+// oversampled textures with bilinear filtering. Look at the readme in+// stb/tests/oversample for information about oversampled fonts+//+// To use with PackFontRangesGather etc., you must set it before calls+// call to PackFontRangesGatherRects.++STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph,  // same data as above+                               int char_index,             // character to display+                               float *xpos, float *ypos,   // pointers to current position in screen pixel space+                               stbtt_aligned_quad *q,      // output: quad to draw+                               int align_to_integer);++STBTT_DEF int  stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);+STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects);+STBTT_DEF int  stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);+// Calling these functions in sequence is roughly equivalent to calling+// stbtt_PackFontRanges(). If you more control over the packing of multiple+// fonts, or if you want to pack custom data into a font texture, take a look+// at the source to of stbtt_PackFontRanges() and create a custom version +// using these functions, e.g. call GatherRects multiple times,+// building up a single array of rects, then call PackRects once,+// then call RenderIntoRects repeatedly. This may result in a+// better packing than calling PackFontRanges multiple times+// (or it may not).++// this is an opaque structure that you shouldn't mess with which holds+// all the context needed from PackBegin to PackEnd.+struct stbtt_pack_context {+   void *user_allocator_context;+   void *pack_info;+   int   width;+   int   height;+   int   stride_in_bytes;+   int   padding;+   unsigned int   h_oversample, v_oversample;+   unsigned char *pixels;+   void  *nodes;+};++//////////////////////////////////////////////////////////////////////////////+//+// FONT LOADING+//+//++STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data);+// This function will determine the number of fonts in a font file.  TrueType+// collection (.ttc) files may contain multiple fonts, while TrueType font+// (.ttf) files only contain one font. The number of fonts can be used for+// indexing with the previous function where the index is between zero and one+// less than the total fonts. If an error occurs, -1 is returned.++STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index);+// Each .ttf/.ttc file may have more than one font. Each font has a sequential+// index number starting from 0. Call this function to get the font offset for+// a given index; it returns -1 if the index is out of range. A regular .ttf+// file will only define one font and it always be at offset 0, so it will+// return '0' for index 0, and -1 for all other indices.++// The following structure is defined publically so you can declare one on+// the stack or as a global or etc, but you should treat it as opaque.+struct stbtt_fontinfo+{+   void           * userdata;+   unsigned char  * data;              // pointer to .ttf file+   int              fontstart;         // offset of start of font++   int numGlyphs;                     // number of glyphs, needed for range checking++   int loca,head,glyf,hhea,hmtx,kern,gpos; // table locations as offset from start of .ttf+   int index_map;                     // a cmap mapping for our chosen character encoding+   int indexToLocFormat;              // format needed to map from glyph index to glyph++   stbtt__buf cff;                    // cff font data+   stbtt__buf charstrings;            // the charstring index+   stbtt__buf gsubrs;                 // global charstring subroutines index+   stbtt__buf subrs;                  // private charstring subroutines index+   stbtt__buf fontdicts;              // array of font dicts+   stbtt__buf fdselect;               // map from glyph to fontdict+};++STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset);+// Given an offset into the file that defines a font, this function builds+// the necessary cached info for the rest of the system. You must allocate+// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't+// need to do anything special to free it, because the contents are pure+// value data with no additional data structures. Returns 0 on failure.+++//////////////////////////////////////////////////////////////////////////////+//+// CHARACTER TO GLYPH-INDEX CONVERSIOn++STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint);+// If you're going to perform multiple operations on the same character+// and you want a speed-up, call this function with the character you're+// going to process, then use glyph-based functions instead of the+// codepoint-based functions.+++//////////////////////////////////////////////////////////////////////////////+//+// CHARACTER PROPERTIES+//++STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels);+// computes a scale factor to produce a font whose "height" is 'pixels' tall.+// Height is measured as the distance from the highest ascender to the lowest+// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics+// and computing:+//       scale = pixels / (ascent - descent)+// so if you prefer to measure height by the ascent only, use a similar calculation.++STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels);+// computes a scale factor to produce a font whose EM size is mapped to+// 'pixels' tall. This is probably what traditional APIs compute, but+// I'm not positive.++STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap);+// ascent is the coordinate above the baseline the font extends; descent+// is the coordinate below the baseline the font extends (i.e. it is typically negative)+// lineGap is the spacing between one row's descent and the next row's ascent...+// so you should advance the vertical position by "*ascent - *descent + *lineGap"+//   these are expressed in unscaled coordinates, so you must multiply by+//   the scale factor for a given size++STBTT_DEF int  stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap);+// analogous to GetFontVMetrics, but returns the "typographic" values from the OS/2+// table (specific to MS/Windows TTF files).+//+// Returns 1 on success (table present), 0 on failure.++STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1);+// the bounding box around all possible characters++STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing);+// leftSideBearing is the offset from the current horizontal position to the left edge of the character+// advanceWidth is the offset from the current horizontal position to the next horizontal position+//   these are expressed in unscaled coordinates++STBTT_DEF int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2);+// an additional amount to add to the 'advance' value between ch1 and ch2++STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1);+// Gets the bounding box of the visible part of the glyph, in unscaled coordinates++STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing);+STBTT_DEF int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2);+STBTT_DEF int  stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);+// as above, but takes one or more glyph indices for greater efficiency+++//////////////////////////////////////////////////////////////////////////////+//+// GLYPH SHAPES (you probably don't need these, but they have to go before+// the bitmaps for C declaration-order reasons)+//++#ifndef STBTT_vmove // you can predefine these to use different values (but why?)+   enum {+      STBTT_vmove=1,+      STBTT_vline,+      STBTT_vcurve,+      STBTT_vcubic+   };+#endif++#ifndef stbtt_vertex // you can predefine this to use different values+                   // (we share this with other code at RAD)+   #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file+   typedef struct+   {+      stbtt_vertex_type x,y,cx,cy,cx1,cy1;+      unsigned char type,padding;+   } stbtt_vertex;+#endif++STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index);+// returns non-zero if nothing is drawn for this glyph++STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices);+STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices);+// returns # of vertices and fills *vertices with the pointer to them+//   these are expressed in "unscaled" coordinates+//+// The shape is a series of countours. Each one starts with+// a STBTT_moveto, then consists of a series of mixed+// STBTT_lineto and STBTT_curveto segments. A lineto+// draws a line from previous endpoint to its x,y; a curveto+// draws a quadratic bezier from previous endpoint to+// its x,y, using cx,cy as the bezier control point.++STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);+// frees the data allocated above++//////////////////////////////////////////////////////////////////////////////+//+// BITMAP RENDERING+//++STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata);+// frees the bitmap allocated below++STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff);+// allocates a large-enough single-channel 8bpp bitmap and renders the+// specified character/glyph at the specified scale into it, with+// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque).+// *width & *height are filled out with the width & height of the bitmap,+// which is stored left-to-right, top-to-bottom.+//+// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap++STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff);+// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel+// shift for the character++STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint);+// the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap+// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap+// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the+// width and height and positioning info for it first.++STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint);+// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel+// shift for the character++STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint);+// same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering+// is performed (see stbtt_PackSetOversampling)++STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);+// get the bbox of the bitmap centered around the glyph origin; so the+// bitmap width is ix1-ix0, height is iy1-iy0, and location to place+// the bitmap top left is (leftSideBearing*scale,iy0).+// (Note that the bitmap uses y-increases-down, but the shape uses+// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.)++STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);+// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel+// shift for the character++// the following functions are equivalent to the above functions, but operate+// on glyph indices instead of Unicode codepoints (for efficiency)+STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff);+STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff);+STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph);+STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph);+STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph);+STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);+STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);+++// @TODO: don't expose this structure+typedef struct+{+   int w,h,stride;+   unsigned char *pixels;+} stbtt__bitmap;++// rasterize a shape with quadratic beziers into a bitmap+STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result,        // 1-channel bitmap to draw into+                               float flatness_in_pixels,     // allowable error of curve in pixels+                               stbtt_vertex *vertices,       // array of vertices defining shape+                               int num_verts,                // number of vertices in above array+                               float scale_x, float scale_y, // scale applied to input vertices+                               float shift_x, float shift_y, // translation applied to input vertices+                               int x_off, int y_off,         // another translation applied to input+                               int invert,                   // if non-zero, vertically flip shape+                               void *userdata);              // context for to STBTT_MALLOC++//////////////////////////////////////////////////////////////////////////////+//+// Signed Distance Function (or Field) rendering++STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata);+// frees the SDF bitmap allocated below++STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);+STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);+// These functions compute a discretized SDF field for a single character, suitable for storing+// in a single-channel texture, sampling with bilinear filtering, and testing against+// larger than some threshhold to produce scalable fonts.+//        info              --  the font+//        scale             --  controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap+//        glyph/codepoint   --  the character to generate the SDF for+//        padding           --  extra "pixels" around the character which are filled with the distance to the character (not 0),+//                                 which allows effects like bit outlines+//        onedge_value      --  value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character)+//        pixel_dist_scale  --  what value the SDF should increase by when moving one SDF "pixel" away from the edge (on the 0..255 scale)+//                                 if positive, > onedge_value is inside; if negative, < onedge_value is inside+//        width,height      --  output height & width of the SDF bitmap (including padding)+//        xoff,yoff         --  output origin of the character+//        return value      --  a 2D array of bytes 0..255, width*height in size+//+// pixel_dist_scale & onedge_value are a scale & bias that allows you to make+// optimal use of the limited 0..255 for your application, trading off precision+// and special effects. SDF values outside the range 0..255 are clamped to 0..255.+//+// Example:+//      scale = stbtt_ScaleForPixelHeight(22)+//      padding = 5+//      onedge_value = 180+//      pixel_dist_scale = 180/5.0 = 36.0+//+//      This will create an SDF bitmap in which the character is about 22 pixels+//      high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled+//      shape, sample the SDF at each pixel and fill the pixel if the SDF value+//      is greater than or equal to 180/255. (You'll actually want to antialias,+//      which is beyond the scope of this example.) Additionally, you can compute+//      offset outlines (e.g. to stroke the character border inside & outside,+//      or only outside). For example, to fill outside the character up to 3 SDF+//      pixels, you would compare against (180-36.0*3)/255 = 72/255. The above+//      choice of variables maps a range from 5 pixels outside the shape to+//      2 pixels inside the shape to 0..255; this is intended primarily for apply+//      outside effects only (the interior range is needed to allow proper+//      antialiasing of the font at *smaller* sizes)+//+// The function computes the SDF analytically at each SDF pixel, not by e.g.+// building a higher-res bitmap and approximating it. In theory the quality+// should be as high as possible for an SDF of this size & representation, but+// unclear if this is true in practice (perhaps building a higher-res bitmap+// and computing from that can allow drop-out prevention).+//+// The algorithm has not been optimized at all, so expect it to be slow+// if computing lots of characters or very large sizes. ++++//////////////////////////////////////////////////////////////////////////////+//+// Finding the right font...+//+// You should really just solve this offline, keep your own tables+// of what font is what, and don't try to get it out of the .ttf file.+// That's because getting it out of the .ttf file is really hard, because+// the names in the file can appear in many possible encodings, in many+// possible languages, and e.g. if you need a case-insensitive comparison,+// the details of that depend on the encoding & language in a complex way+// (actually underspecified in truetype, but also gigantic).+//+// But you can use the provided functions in two possible ways:+//     stbtt_FindMatchingFont() will use *case-sensitive* comparisons on+//             unicode-encoded names to try to find the font you want;+//             you can run this before calling stbtt_InitFont()+//+//     stbtt_GetFontNameString() lets you get any of the various strings+//             from the file yourself and do your own comparisons on them.+//             You have to have called stbtt_InitFont() first.+++STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags);+// returns the offset (not index) of the font that matches, or -1 if none+//   if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold".+//   if you use any other flag, use a font name like "Arial"; this checks+//     the 'macStyle' header field; i don't know if fonts set this consistently+#define STBTT_MACSTYLE_DONTCARE     0+#define STBTT_MACSTYLE_BOLD         1+#define STBTT_MACSTYLE_ITALIC       2+#define STBTT_MACSTYLE_UNDERSCORE   4+#define STBTT_MACSTYLE_NONE         8   // <= not same as 0, this makes us check the bitfield is 0++STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2);+// returns 1/0 whether the first string interpreted as utf8 is identical to+// the second string interpreted as big-endian utf16... useful for strings from next func++STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID);+// returns the string (which may be big-endian double byte, e.g. for unicode)+// and puts the length in bytes in *length.+//+// some of the values for the IDs are below; for more see the truetype spec:+//     http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html+//     http://www.microsoft.com/typography/otspec/name.htm++enum { // platformID+   STBTT_PLATFORM_ID_UNICODE   =0,+   STBTT_PLATFORM_ID_MAC       =1,+   STBTT_PLATFORM_ID_ISO       =2,+   STBTT_PLATFORM_ID_MICROSOFT =3+};++enum { // encodingID for STBTT_PLATFORM_ID_UNICODE+   STBTT_UNICODE_EID_UNICODE_1_0    =0,+   STBTT_UNICODE_EID_UNICODE_1_1    =1,+   STBTT_UNICODE_EID_ISO_10646      =2,+   STBTT_UNICODE_EID_UNICODE_2_0_BMP=3,+   STBTT_UNICODE_EID_UNICODE_2_0_FULL=4+};++enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT+   STBTT_MS_EID_SYMBOL        =0,+   STBTT_MS_EID_UNICODE_BMP   =1,+   STBTT_MS_EID_SHIFTJIS      =2,+   STBTT_MS_EID_UNICODE_FULL  =10+};++enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes+   STBTT_MAC_EID_ROMAN        =0,   STBTT_MAC_EID_ARABIC       =4,+   STBTT_MAC_EID_JAPANESE     =1,   STBTT_MAC_EID_HEBREW       =5,+   STBTT_MAC_EID_CHINESE_TRAD =2,   STBTT_MAC_EID_GREEK        =6,+   STBTT_MAC_EID_KOREAN       =3,   STBTT_MAC_EID_RUSSIAN      =7+};++enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID...+       // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs+   STBTT_MS_LANG_ENGLISH     =0x0409,   STBTT_MS_LANG_ITALIAN     =0x0410,+   STBTT_MS_LANG_CHINESE     =0x0804,   STBTT_MS_LANG_JAPANESE    =0x0411,+   STBTT_MS_LANG_DUTCH       =0x0413,   STBTT_MS_LANG_KOREAN      =0x0412,+   STBTT_MS_LANG_FRENCH      =0x040c,   STBTT_MS_LANG_RUSSIAN     =0x0419,+   STBTT_MS_LANG_GERMAN      =0x0407,   STBTT_MS_LANG_SPANISH     =0x0409,+   STBTT_MS_LANG_HEBREW      =0x040d,   STBTT_MS_LANG_SWEDISH     =0x041D+};++enum { // languageID for STBTT_PLATFORM_ID_MAC+   STBTT_MAC_LANG_ENGLISH      =0 ,   STBTT_MAC_LANG_JAPANESE     =11,+   STBTT_MAC_LANG_ARABIC       =12,   STBTT_MAC_LANG_KOREAN       =23,+   STBTT_MAC_LANG_DUTCH        =4 ,   STBTT_MAC_LANG_RUSSIAN      =32,+   STBTT_MAC_LANG_FRENCH       =1 ,   STBTT_MAC_LANG_SPANISH      =6 ,+   STBTT_MAC_LANG_GERMAN       =2 ,   STBTT_MAC_LANG_SWEDISH      =5 ,+   STBTT_MAC_LANG_HEBREW       =10,   STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33,+   STBTT_MAC_LANG_ITALIAN      =3 ,   STBTT_MAC_LANG_CHINESE_TRAD =19+};++#ifdef __cplusplus+}+#endif++#endif // __STB_INCLUDE_STB_TRUETYPE_H__++///////////////////////////////////////////////////////////////////////////////+///////////////////////////////////////////////////////////////////////////////+////+////   IMPLEMENTATION+////+////++#ifdef STB_TRUETYPE_IMPLEMENTATION++#ifndef STBTT_MAX_OVERSAMPLE+#define STBTT_MAX_OVERSAMPLE   8+#endif++#if STBTT_MAX_OVERSAMPLE > 255+#error "STBTT_MAX_OVERSAMPLE cannot be > 255"+#endif++typedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1];++#ifndef STBTT_RASTERIZER_VERSION+#define STBTT_RASTERIZER_VERSION 2+#endif++#ifdef _MSC_VER+#define STBTT__NOTUSED(v)  (void)(v)+#else+#define STBTT__NOTUSED(v)  (void)sizeof(v)+#endif++//////////////////////////////////////////////////////////////////////////+//+// stbtt__buf helpers to parse data from file+//++static stbtt_uint8 stbtt__buf_get8(stbtt__buf *b)+{+   if (b->cursor >= b->size)+      return 0;+   return b->data[b->cursor++];+}++static stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b)+{+   if (b->cursor >= b->size)+      return 0;+   return b->data[b->cursor];+}++static void stbtt__buf_seek(stbtt__buf *b, int o)+{+   STBTT_assert(!(o > b->size || o < 0));+   b->cursor = (o > b->size || o < 0) ? b->size : o;+}++static void stbtt__buf_skip(stbtt__buf *b, int o)+{+   stbtt__buf_seek(b, b->cursor + o);+}++static stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n)+{+   stbtt_uint32 v = 0;+   int i;+   STBTT_assert(n >= 1 && n <= 4);+   for (i = 0; i < n; i++)+      v = (v << 8) | stbtt__buf_get8(b);+   return v;+}++static stbtt__buf stbtt__new_buf(const void *p, size_t size)+{+   stbtt__buf r;+   STBTT_assert(size < 0x40000000);+   r.data = (stbtt_uint8*) p;+   r.size = (int) size;+   r.cursor = 0;+   return r;+}++#define stbtt__buf_get16(b)  stbtt__buf_get((b), 2)+#define stbtt__buf_get32(b)  stbtt__buf_get((b), 4)++static stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s)+{+   stbtt__buf r = stbtt__new_buf(NULL, 0);+   if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r;+   r.data = b->data + o;+   r.size = s;+   return r;+}++static stbtt__buf stbtt__cff_get_index(stbtt__buf *b)+{+   int count, start, offsize;+   start = b->cursor;+   count = stbtt__buf_get16(b);+   if (count) {+      offsize = stbtt__buf_get8(b);+      STBTT_assert(offsize >= 1 && offsize <= 4);+      stbtt__buf_skip(b, offsize * count);+      stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1);+   }+   return stbtt__buf_range(b, start, b->cursor - start);+}++static stbtt_uint32 stbtt__cff_int(stbtt__buf *b)+{+   int b0 = stbtt__buf_get8(b);+   if (b0 >= 32 && b0 <= 246)       return b0 - 139;+   else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108;+   else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108;+   else if (b0 == 28)               return stbtt__buf_get16(b);+   else if (b0 == 29)               return stbtt__buf_get32(b);+   STBTT_assert(0);+   return 0;+}++static void stbtt__cff_skip_operand(stbtt__buf *b) {+   int v, b0 = stbtt__buf_peek8(b);+   STBTT_assert(b0 >= 28);+   if (b0 == 30) {+      stbtt__buf_skip(b, 1);+      while (b->cursor < b->size) {+         v = stbtt__buf_get8(b);+         if ((v & 0xF) == 0xF || (v >> 4) == 0xF)+            break;+      }+   } else {+      stbtt__cff_int(b);+   }+}++static stbtt__buf stbtt__dict_get(stbtt__buf *b, int key)+{+   stbtt__buf_seek(b, 0);+   while (b->cursor < b->size) {+      int start = b->cursor, end, op;+      while (stbtt__buf_peek8(b) >= 28)+         stbtt__cff_skip_operand(b);+      end = b->cursor;+      op = stbtt__buf_get8(b);+      if (op == 12)  op = stbtt__buf_get8(b) | 0x100;+      if (op == key) return stbtt__buf_range(b, start, end-start);+   }+   return stbtt__buf_range(b, 0, 0);+}++static void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out)+{+   int i;+   stbtt__buf operands = stbtt__dict_get(b, key);+   for (i = 0; i < outcount && operands.cursor < operands.size; i++)+      out[i] = stbtt__cff_int(&operands);+}++static int stbtt__cff_index_count(stbtt__buf *b)+{+   stbtt__buf_seek(b, 0);+   return stbtt__buf_get16(b);+}++static stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i)+{+   int count, offsize, start, end;+   stbtt__buf_seek(&b, 0);+   count = stbtt__buf_get16(&b);+   offsize = stbtt__buf_get8(&b);+   STBTT_assert(i >= 0 && i < count);+   STBTT_assert(offsize >= 1 && offsize <= 4);+   stbtt__buf_skip(&b, i*offsize);+   start = stbtt__buf_get(&b, offsize);+   end = stbtt__buf_get(&b, offsize);+   return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start);+}++//////////////////////////////////////////////////////////////////////////+//+// accessors to parse data from file+//++// on platforms that don't allow misaligned reads, if we want to allow+// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE++#define ttBYTE(p)     (* (stbtt_uint8 *) (p))+#define ttCHAR(p)     (* (stbtt_int8 *) (p))+#define ttFixed(p)    ttLONG(p)++static stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; }+static stbtt_int16 ttSHORT(stbtt_uint8 *p)   { return p[0]*256 + p[1]; }+static stbtt_uint32 ttULONG(stbtt_uint8 *p)  { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }+static stbtt_int32 ttLONG(stbtt_uint8 *p)    { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }++#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3))+#define stbtt_tag(p,str)           stbtt_tag4(p,str[0],str[1],str[2],str[3])++static int stbtt__isfont(stbtt_uint8 *font)+{+   // check the version number+   if (stbtt_tag4(font, '1',0,0,0))  return 1; // TrueType 1+   if (stbtt_tag(font, "typ1"))   return 1; // TrueType with type 1 font -- we don't support this!+   if (stbtt_tag(font, "OTTO"))   return 1; // OpenType with CFF+   if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0+   if (stbtt_tag(font, "true"))   return 1; // Apple specification for TrueType fonts+   return 0;+}++// @OPTIMIZE: binary search+static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag)+{+   stbtt_int32 num_tables = ttUSHORT(data+fontstart+4);+   stbtt_uint32 tabledir = fontstart + 12;+   stbtt_int32 i;+   for (i=0; i < num_tables; ++i) {+      stbtt_uint32 loc = tabledir + 16*i;+      if (stbtt_tag(data+loc+0, tag))+         return ttULONG(data+loc+8);+   }+   return 0;+}++static int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index)+{+   // if it's just a font, there's only one valid index+   if (stbtt__isfont(font_collection))+      return index == 0 ? 0 : -1;++   // check if it's a TTC+   if (stbtt_tag(font_collection, "ttcf")) {+      // version 1?+      if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {+         stbtt_int32 n = ttLONG(font_collection+8);+         if (index >= n)+            return -1;+         return ttULONG(font_collection+12+index*4);+      }+   }+   return -1;+}++static int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection)+{+   // if it's just a font, there's only one valid font+   if (stbtt__isfont(font_collection))+      return 1;++   // check if it's a TTC+   if (stbtt_tag(font_collection, "ttcf")) {+      // version 1?+      if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {+         return ttLONG(font_collection+8);+      }+   }+   return 0;+}++static stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict)+{+   stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 };+   stbtt__buf pdict;+   stbtt__dict_get_ints(&fontdict, 18, 2, private_loc);+   if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0);+   pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]);+   stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff);+   if (!subrsoff) return stbtt__new_buf(NULL, 0);+   stbtt__buf_seek(&cff, private_loc[1]+subrsoff);+   return stbtt__cff_get_index(&cff);+}++static int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart)+{+   stbtt_uint32 cmap, t;+   stbtt_int32 i,numTables;++   info->data = data;+   info->fontstart = fontstart;+   info->cff = stbtt__new_buf(NULL, 0);++   cmap = stbtt__find_table(data, fontstart, "cmap");       // required+   info->loca = stbtt__find_table(data, fontstart, "loca"); // required+   info->head = stbtt__find_table(data, fontstart, "head"); // required+   info->glyf = stbtt__find_table(data, fontstart, "glyf"); // required+   info->hhea = stbtt__find_table(data, fontstart, "hhea"); // required+   info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); // required+   info->kern = stbtt__find_table(data, fontstart, "kern"); // not required+   info->gpos = stbtt__find_table(data, fontstart, "GPOS"); // not required++   if (!cmap || !info->head || !info->hhea || !info->hmtx)+      return 0;+   if (info->glyf) {+      // required for truetype+      if (!info->loca) return 0;+   } else {+      // initialization for CFF / Type2 fonts (OTF)+      stbtt__buf b, topdict, topdictidx;+      stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0;+      stbtt_uint32 cff;++      cff = stbtt__find_table(data, fontstart, "CFF ");+      if (!cff) return 0;++      info->fontdicts = stbtt__new_buf(NULL, 0);+      info->fdselect = stbtt__new_buf(NULL, 0);++      // @TODO this should use size from table (not 512MB)+      info->cff = stbtt__new_buf(data+cff, 512*1024*1024);+      b = info->cff;++      // read the header+      stbtt__buf_skip(&b, 2);+      stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize++      // @TODO the name INDEX could list multiple fonts,+      // but we just use the first one.+      stbtt__cff_get_index(&b);  // name INDEX+      topdictidx = stbtt__cff_get_index(&b);+      topdict = stbtt__cff_index_get(topdictidx, 0);+      stbtt__cff_get_index(&b);  // string INDEX+      info->gsubrs = stbtt__cff_get_index(&b);++      stbtt__dict_get_ints(&topdict, 17, 1, &charstrings);+      stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype);+      stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff);+      stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff);+      info->subrs = stbtt__get_subrs(b, topdict);++      // we only support Type 2 charstrings+      if (cstype != 2) return 0;+      if (charstrings == 0) return 0;++      if (fdarrayoff) {+         // looks like a CID font+         if (!fdselectoff) return 0;+         stbtt__buf_seek(&b, fdarrayoff);+         info->fontdicts = stbtt__cff_get_index(&b);+         info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff);+      }++      stbtt__buf_seek(&b, charstrings);+      info->charstrings = stbtt__cff_get_index(&b);+   }++   t = stbtt__find_table(data, fontstart, "maxp");+   if (t)+      info->numGlyphs = ttUSHORT(data+t+4);+   else+      info->numGlyphs = 0xffff;++   // find a cmap encoding table we understand *now* to avoid searching+   // later. (todo: could make this installable)+   // the same regardless of glyph.+   numTables = ttUSHORT(data + cmap + 2);+   info->index_map = 0;+   for (i=0; i < numTables; ++i) {+      stbtt_uint32 encoding_record = cmap + 4 + 8 * i;+      // find an encoding we understand:+      switch(ttUSHORT(data+encoding_record)) {+         case STBTT_PLATFORM_ID_MICROSOFT:+            switch (ttUSHORT(data+encoding_record+2)) {+               case STBTT_MS_EID_UNICODE_BMP:+               case STBTT_MS_EID_UNICODE_FULL:+                  // MS/Unicode+                  info->index_map = cmap + ttULONG(data+encoding_record+4);+                  break;+            }+            break;+        case STBTT_PLATFORM_ID_UNICODE:+            // Mac/iOS has these+            // all the encodingIDs are unicode, so we don't bother to check it+            info->index_map = cmap + ttULONG(data+encoding_record+4);+            break;+      }+   }+   if (info->index_map == 0)+      return 0;++   info->indexToLocFormat = ttUSHORT(data+info->head + 50);+   return 1;+}++STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint)+{+   stbtt_uint8 *data = info->data;+   stbtt_uint32 index_map = info->index_map;++   stbtt_uint16 format = ttUSHORT(data + index_map + 0);+   if (format == 0) { // apple byte encoding+      stbtt_int32 bytes = ttUSHORT(data + index_map + 2);+      if (unicode_codepoint < bytes-6)+         return ttBYTE(data + index_map + 6 + unicode_codepoint);+      return 0;+   } else if (format == 6) {+      stbtt_uint32 first = ttUSHORT(data + index_map + 6);+      stbtt_uint32 count = ttUSHORT(data + index_map + 8);+      if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count)+         return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2);+      return 0;+   } else if (format == 2) {+      STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean+      return 0;+   } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges+      stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1;+      stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1;+      stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10);+      stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1;++      // do a binary search of the segments+      stbtt_uint32 endCount = index_map + 14;+      stbtt_uint32 search = endCount;++      if (unicode_codepoint > 0xffff)+         return 0;++      // they lie from endCount .. endCount + segCount+      // but searchRange is the nearest power of two, so...+      if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2))+         search += rangeShift*2;++      // now decrement to bias correctly to find smallest+      search -= 2;+      while (entrySelector) {+         stbtt_uint16 end;+         searchRange >>= 1;+         end = ttUSHORT(data + search + searchRange*2);+         if (unicode_codepoint > end)+            search += searchRange*2;+         --entrySelector;+      }+      search += 2;++      {+         stbtt_uint16 offset, start;+         stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1);++         STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item));+         start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);+         if (unicode_codepoint < start)+            return 0;++         offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);+         if (offset == 0)+            return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item));++         return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item);+      }+   } else if (format == 12 || format == 13) {+      stbtt_uint32 ngroups = ttULONG(data+index_map+12);+      stbtt_int32 low,high;+      low = 0; high = (stbtt_int32)ngroups;+      // Binary search the right group.+      while (low < high) {+         stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high+         stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12);+         stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4);+         if ((stbtt_uint32) unicode_codepoint < start_char)+            high = mid;+         else if ((stbtt_uint32) unicode_codepoint > end_char)+            low = mid+1;+         else {+            stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8);+            if (format == 12)+               return start_glyph + unicode_codepoint-start_char;+            else // format == 13+               return start_glyph;+         }+      }+      return 0; // not found+   }+   // @TODO+   STBTT_assert(0);+   return 0;+}++STBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices)+{+   return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices);+}++static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy)+{+   v->type = type;+   v->x = (stbtt_int16) x;+   v->y = (stbtt_int16) y;+   v->cx = (stbtt_int16) cx;+   v->cy = (stbtt_int16) cy;+}++static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index)+{+   int g1,g2;++   STBTT_assert(!info->cff.size);++   if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range+   if (info->indexToLocFormat >= 2)    return -1; // unknown index->glyph map format++   if (info->indexToLocFormat == 0) {+      g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2;+      g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2;+   } else {+      g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4);+      g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4);+   }++   return g1==g2 ? -1 : g1; // if length is 0, return -1+}++static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);++STBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)+{+   if (info->cff.size) {+      stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1);+   } else {+      int g = stbtt__GetGlyfOffset(info, glyph_index);+      if (g < 0) return 0;++      if (x0) *x0 = ttSHORT(info->data + g + 2);+      if (y0) *y0 = ttSHORT(info->data + g + 4);+      if (x1) *x1 = ttSHORT(info->data + g + 6);+      if (y1) *y1 = ttSHORT(info->data + g + 8);+   }+   return 1;+}++STBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1)+{+   return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1);+}++STBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index)+{+   stbtt_int16 numberOfContours;+   int g;+   if (info->cff.size)+      return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0;+   g = stbtt__GetGlyfOffset(info, glyph_index);+   if (g < 0) return 1;+   numberOfContours = ttSHORT(info->data + g);+   return numberOfContours == 0;+}++static int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off,+    stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy)+{+   if (start_off) {+      if (was_off)+         stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy);+      stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy);+   } else {+      if (was_off)+         stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy);+      else+         stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0);+   }+   return num_vertices;+}++static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)+{+   stbtt_int16 numberOfContours;+   stbtt_uint8 *endPtsOfContours;+   stbtt_uint8 *data = info->data;+   stbtt_vertex *vertices=0;+   int num_vertices=0;+   int g = stbtt__GetGlyfOffset(info, glyph_index);++   *pvertices = NULL;++   if (g < 0) return 0;++   numberOfContours = ttSHORT(data + g);++   if (numberOfContours > 0) {+      stbtt_uint8 flags=0,flagcount;+      stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0;+      stbtt_int32 x,y,cx,cy,sx,sy, scx,scy;+      stbtt_uint8 *points;+      endPtsOfContours = (data + g + 10);+      ins = ttUSHORT(data + g + 10 + numberOfContours * 2);+      points = data + g + 10 + numberOfContours * 2 + 2 + ins;++      n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2);++      m = n + 2*numberOfContours;  // a loose bound on how many vertices we might need+      vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata);+      if (vertices == 0)+         return 0;++      next_move = 0;+      flagcount=0;++      // in first pass, we load uninterpreted data into the allocated array+      // above, shifted to the end of the array so we won't overwrite it when+      // we create our final data starting from the front++      off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated++      // first load flags++      for (i=0; i < n; ++i) {+         if (flagcount == 0) {+            flags = *points++;+            if (flags & 8)+               flagcount = *points++;+         } else+            --flagcount;+         vertices[off+i].type = flags;+      }++      // now load x coordinates+      x=0;+      for (i=0; i < n; ++i) {+         flags = vertices[off+i].type;+         if (flags & 2) {+            stbtt_int16 dx = *points++;+            x += (flags & 16) ? dx : -dx; // ???+         } else {+            if (!(flags & 16)) {+               x = x + (stbtt_int16) (points[0]*256 + points[1]);+               points += 2;+            }+         }+         vertices[off+i].x = (stbtt_int16) x;+      }++      // now load y coordinates+      y=0;+      for (i=0; i < n; ++i) {+         flags = vertices[off+i].type;+         if (flags & 4) {+            stbtt_int16 dy = *points++;+            y += (flags & 32) ? dy : -dy; // ???+         } else {+            if (!(flags & 32)) {+               y = y + (stbtt_int16) (points[0]*256 + points[1]);+               points += 2;+            }+         }+         vertices[off+i].y = (stbtt_int16) y;+      }++      // now convert them to our format+      num_vertices=0;+      sx = sy = cx = cy = scx = scy = 0;+      for (i=0; i < n; ++i) {+         flags = vertices[off+i].type;+         x     = (stbtt_int16) vertices[off+i].x;+         y     = (stbtt_int16) vertices[off+i].y;++         if (next_move == i) {+            if (i != 0)+               num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);++            // now start the new one               +            start_off = !(flags & 1);+            if (start_off) {+               // if we start off with an off-curve point, then when we need to find a point on the curve+               // where we can start, and we need to save some state for when we wraparound.+               scx = x;+               scy = y;+               if (!(vertices[off+i+1].type & 1)) {+                  // next point is also a curve point, so interpolate an on-point curve+                  sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1;+                  sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1;+               } else {+                  // otherwise just use the next point as our start point+                  sx = (stbtt_int32) vertices[off+i+1].x;+                  sy = (stbtt_int32) vertices[off+i+1].y;+                  ++i; // we're using point i+1 as the starting point, so skip it+               }+            } else {+               sx = x;+               sy = y;+            }+            stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0);+            was_off = 0;+            next_move = 1 + ttUSHORT(endPtsOfContours+j*2);+            ++j;+         } else {+            if (!(flags & 1)) { // if it's a curve+               if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint+                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy);+               cx = x;+               cy = y;+               was_off = 1;+            } else {+               if (was_off)+                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy);+               else+                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0);+               was_off = 0;+            }+         }+      }+      num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);+   } else if (numberOfContours == -1) {+      // Compound shapes.+      int more = 1;+      stbtt_uint8 *comp = data + g + 10;+      num_vertices = 0;+      vertices = 0;+      while (more) {+         stbtt_uint16 flags, gidx;+         int comp_num_verts = 0, i;+         stbtt_vertex *comp_verts = 0, *tmp = 0;+         float mtx[6] = {1,0,0,1,0,0}, m, n;+         +         flags = ttSHORT(comp); comp+=2;+         gidx = ttSHORT(comp); comp+=2;++         if (flags & 2) { // XY values+            if (flags & 1) { // shorts+               mtx[4] = ttSHORT(comp); comp+=2;+               mtx[5] = ttSHORT(comp); comp+=2;+            } else {+               mtx[4] = ttCHAR(comp); comp+=1;+               mtx[5] = ttCHAR(comp); comp+=1;+            }+         }+         else {+            // @TODO handle matching point+            STBTT_assert(0);+         }+         if (flags & (1<<3)) { // WE_HAVE_A_SCALE+            mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;+            mtx[1] = mtx[2] = 0;+         } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE+            mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;+            mtx[1] = mtx[2] = 0;+            mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;+         } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO+            mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;+            mtx[1] = ttSHORT(comp)/16384.0f; comp+=2;+            mtx[2] = ttSHORT(comp)/16384.0f; comp+=2;+            mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;+         }+         +         // Find transformation scales.+         m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]);+         n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]);++         // Get indexed glyph.+         comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts);+         if (comp_num_verts > 0) {+            // Transform vertices.+            for (i = 0; i < comp_num_verts; ++i) {+               stbtt_vertex* v = &comp_verts[i];+               stbtt_vertex_type x,y;+               x=v->x; y=v->y;+               v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));+               v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));+               x=v->cx; y=v->cy;+               v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));+               v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));+            }+            // Append vertices.+            tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata);+            if (!tmp) {+               if (vertices) STBTT_free(vertices, info->userdata);+               if (comp_verts) STBTT_free(comp_verts, info->userdata);+               return 0;+            }+            if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));+            STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));+            if (vertices) STBTT_free(vertices, info->userdata);+            vertices = tmp;+            STBTT_free(comp_verts, info->userdata);+            num_vertices += comp_num_verts;+         }+         // More components ?+         more = flags & (1<<5);+      }+   } else if (numberOfContours < 0) {+      // @TODO other compound variations?+      STBTT_assert(0);+   } else {+      // numberOfCounters == 0, do nothing+   }++   *pvertices = vertices;+   return num_vertices;+}++typedef struct+{+   int bounds;+   int started;+   float first_x, first_y;+   float x, y;+   stbtt_int32 min_x, max_x, min_y, max_y;++   stbtt_vertex *pvertices;+   int num_vertices;+} stbtt__csctx;++#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0}++static void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y)+{+   if (x > c->max_x || !c->started) c->max_x = x;+   if (y > c->max_y || !c->started) c->max_y = y;+   if (x < c->min_x || !c->started) c->min_x = x;+   if (y < c->min_y || !c->started) c->min_y = y;+   c->started = 1;+}++static void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1)+{+   if (c->bounds) {+      stbtt__track_vertex(c, x, y);+      if (type == STBTT_vcubic) {+         stbtt__track_vertex(c, cx, cy);+         stbtt__track_vertex(c, cx1, cy1);+      }+   } else {+      stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy);+      c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1;+      c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1;+   }+   c->num_vertices++;+}++static void stbtt__csctx_close_shape(stbtt__csctx *ctx)+{+   if (ctx->first_x != ctx->x || ctx->first_y != ctx->y)+      stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0);+}++static void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy)+{+   stbtt__csctx_close_shape(ctx);+   ctx->first_x = ctx->x = ctx->x + dx;+   ctx->first_y = ctx->y = ctx->y + dy;+   stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);+}++static void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy)+{+   ctx->x += dx;+   ctx->y += dy;+   stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);+}++static void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3)+{+   float cx1 = ctx->x + dx1;+   float cy1 = ctx->y + dy1;+   float cx2 = cx1 + dx2;+   float cy2 = cy1 + dy2;+   ctx->x = cx2 + dx3;+   ctx->y = cy2 + dy3;+   stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2);+}++static stbtt__buf stbtt__get_subr(stbtt__buf idx, int n)+{+   int count = stbtt__cff_index_count(&idx);+   int bias = 107;+   if (count >= 33900)+      bias = 32768;+   else if (count >= 1240)+      bias = 1131;+   n += bias;+   if (n < 0 || n >= count)+      return stbtt__new_buf(NULL, 0);+   return stbtt__cff_index_get(idx, n);+}++static stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index)+{+   stbtt__buf fdselect = info->fdselect;+   int nranges, start, end, v, fmt, fdselector = -1, i;++   stbtt__buf_seek(&fdselect, 0);+   fmt = stbtt__buf_get8(&fdselect);+   if (fmt == 0) {+      // untested+      stbtt__buf_skip(&fdselect, glyph_index);+      fdselector = stbtt__buf_get8(&fdselect);+   } else if (fmt == 3) {+      nranges = stbtt__buf_get16(&fdselect);+      start = stbtt__buf_get16(&fdselect);+      for (i = 0; i < nranges; i++) {+         v = stbtt__buf_get8(&fdselect);+         end = stbtt__buf_get16(&fdselect);+         if (glyph_index >= start && glyph_index < end) {+            fdselector = v;+            break;+         }+         start = end;+      }+   }+   if (fdselector == -1) stbtt__new_buf(NULL, 0);+   return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector));+}++static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c)+{+   int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0;+   int has_subrs = 0, clear_stack;+   float s[48];+   stbtt__buf subr_stack[10], subrs = info->subrs, b;+   float f;++#define STBTT__CSERR(s) (0)++   // this currently ignores the initial width value, which isn't needed if we have hmtx+   b = stbtt__cff_index_get(info->charstrings, glyph_index);+   while (b.cursor < b.size) {+      i = 0;+      clear_stack = 1;+      b0 = stbtt__buf_get8(&b);+      switch (b0) {+      // @TODO implement hinting+      case 0x13: // hintmask+      case 0x14: // cntrmask+         if (in_header)+            maskbits += (sp / 2); // implicit "vstem"+         in_header = 0;+         stbtt__buf_skip(&b, (maskbits + 7) / 8);+         break;++      case 0x01: // hstem+      case 0x03: // vstem+      case 0x12: // hstemhm+      case 0x17: // vstemhm+         maskbits += (sp / 2);+         break;++      case 0x15: // rmoveto+         in_header = 0;+         if (sp < 2) return STBTT__CSERR("rmoveto stack");+         stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]);+         break;+      case 0x04: // vmoveto+         in_header = 0;+         if (sp < 1) return STBTT__CSERR("vmoveto stack");+         stbtt__csctx_rmove_to(c, 0, s[sp-1]);+         break;+      case 0x16: // hmoveto+         in_header = 0;+         if (sp < 1) return STBTT__CSERR("hmoveto stack");+         stbtt__csctx_rmove_to(c, s[sp-1], 0);+         break;++      case 0x05: // rlineto+         if (sp < 2) return STBTT__CSERR("rlineto stack");+         for (; i + 1 < sp; i += 2)+            stbtt__csctx_rline_to(c, s[i], s[i+1]);+         break;++      // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical+      // starting from a different place.++      case 0x07: // vlineto+         if (sp < 1) return STBTT__CSERR("vlineto stack");+         goto vlineto;+      case 0x06: // hlineto+         if (sp < 1) return STBTT__CSERR("hlineto stack");+         for (;;) {+            if (i >= sp) break;+            stbtt__csctx_rline_to(c, s[i], 0);+            i++;+      vlineto:+            if (i >= sp) break;+            stbtt__csctx_rline_to(c, 0, s[i]);+            i++;+         }+         break;++      case 0x1F: // hvcurveto+         if (sp < 4) return STBTT__CSERR("hvcurveto stack");+         goto hvcurveto;+      case 0x1E: // vhcurveto+         if (sp < 4) return STBTT__CSERR("vhcurveto stack");+         for (;;) {+            if (i + 3 >= sp) break;+            stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f);+            i += 4;+      hvcurveto:+            if (i + 3 >= sp) break;+            stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]);+            i += 4;+         }+         break;++      case 0x08: // rrcurveto+         if (sp < 6) return STBTT__CSERR("rcurveline stack");+         for (; i + 5 < sp; i += 6)+            stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);+         break;++      case 0x18: // rcurveline+         if (sp < 8) return STBTT__CSERR("rcurveline stack");+         for (; i + 5 < sp - 2; i += 6)+            stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);+         if (i + 1 >= sp) return STBTT__CSERR("rcurveline stack");+         stbtt__csctx_rline_to(c, s[i], s[i+1]);+         break;++      case 0x19: // rlinecurve+         if (sp < 8) return STBTT__CSERR("rlinecurve stack");+         for (; i + 1 < sp - 6; i += 2)+            stbtt__csctx_rline_to(c, s[i], s[i+1]);+         if (i + 5 >= sp) return STBTT__CSERR("rlinecurve stack");+         stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);+         break;++      case 0x1A: // vvcurveto+      case 0x1B: // hhcurveto+         if (sp < 4) return STBTT__CSERR("(vv|hh)curveto stack");+         f = 0.0;+         if (sp & 1) { f = s[i]; i++; }+         for (; i + 3 < sp; i += 4) {+            if (b0 == 0x1B)+               stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0);+            else+               stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]);+            f = 0.0;+         }+         break;++      case 0x0A: // callsubr+         if (!has_subrs) {+            if (info->fdselect.size)+               subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);+            has_subrs = 1;+         }+         // fallthrough+      case 0x1D: // callgsubr+         if (sp < 1) return STBTT__CSERR("call(g|)subr stack");+         v = (int) s[--sp];+         if (subr_stack_height >= 10) return STBTT__CSERR("recursion limit");+         subr_stack[subr_stack_height++] = b;+         b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v);+         if (b.size == 0) return STBTT__CSERR("subr not found");+         b.cursor = 0;+         clear_stack = 0;+         break;++      case 0x0B: // return+         if (subr_stack_height <= 0) return STBTT__CSERR("return outside subr");+         b = subr_stack[--subr_stack_height];+         clear_stack = 0;+         break;++      case 0x0E: // endchar+         stbtt__csctx_close_shape(c);+         return 1;++      case 0x0C: { // two-byte escape+         float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6;+         float dx, dy;+         int b1 = stbtt__buf_get8(&b);+         switch (b1) {+         // @TODO These "flex" implementations ignore the flex-depth and resolution,+         // and always draw beziers.+         case 0x22: // hflex+            if (sp < 7) return STBTT__CSERR("hflex stack");+            dx1 = s[0];+            dx2 = s[1];+            dy2 = s[2];+            dx3 = s[3];+            dx4 = s[4];+            dx5 = s[5];+            dx6 = s[6];+            stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0);+            stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0);+            break;++         case 0x23: // flex+            if (sp < 13) return STBTT__CSERR("flex stack");+            dx1 = s[0];+            dy1 = s[1];+            dx2 = s[2];+            dy2 = s[3];+            dx3 = s[4];+            dy3 = s[5];+            dx4 = s[6];+            dy4 = s[7];+            dx5 = s[8];+            dy5 = s[9];+            dx6 = s[10];+            dy6 = s[11];+            //fd is s[12]+            stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);+            stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);+            break;++         case 0x24: // hflex1+            if (sp < 9) return STBTT__CSERR("hflex1 stack");+            dx1 = s[0];+            dy1 = s[1];+            dx2 = s[2];+            dy2 = s[3];+            dx3 = s[4];+            dx4 = s[5];+            dx5 = s[6];+            dy5 = s[7];+            dx6 = s[8];+            stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0);+            stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5));+            break;++         case 0x25: // flex1+            if (sp < 11) return STBTT__CSERR("flex1 stack");+            dx1 = s[0];+            dy1 = s[1];+            dx2 = s[2];+            dy2 = s[3];+            dx3 = s[4];+            dy3 = s[5];+            dx4 = s[6];+            dy4 = s[7];+            dx5 = s[8];+            dy5 = s[9];+            dx6 = dy6 = s[10];+            dx = dx1+dx2+dx3+dx4+dx5;+            dy = dy1+dy2+dy3+dy4+dy5;+            if (STBTT_fabs(dx) > STBTT_fabs(dy))+               dy6 = -dy;+            else+               dx6 = -dx;+            stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);+            stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);+            break;++         default:+            return STBTT__CSERR("unimplemented");+         }+      } break;++      default:+         if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254))+            return STBTT__CSERR("reserved operator");++         // push immediate+         if (b0 == 255) {+            f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000;+         } else {+            stbtt__buf_skip(&b, -1);+            f = (float)(stbtt_int16)stbtt__cff_int(&b);+         }+         if (sp >= 48) return STBTT__CSERR("push stack overflow");+         s[sp++] = f;+         clear_stack = 0;+         break;+      }+      if (clear_stack) sp = 0;+   }+   return STBTT__CSERR("no endchar");++#undef STBTT__CSERR+}++static int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)+{+   // runs the charstring twice, once to count and once to output (to avoid realloc)+   stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1);+   stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0);+   if (stbtt__run_charstring(info, glyph_index, &count_ctx)) {+      *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata);+      output_ctx.pvertices = *pvertices;+      if (stbtt__run_charstring(info, glyph_index, &output_ctx)) {+         STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices);+         return output_ctx.num_vertices;+      }+   }+   *pvertices = NULL;+   return 0;+}++static int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)+{+   stbtt__csctx c = STBTT__CSCTX_INIT(1);+   int r = stbtt__run_charstring(info, glyph_index, &c);+   if (x0)  *x0 = r ? c.min_x : 0;+   if (y0)  *y0 = r ? c.min_y : 0;+   if (x1)  *x1 = r ? c.max_x : 0;+   if (y1)  *y1 = r ? c.max_y : 0;+   return r ? c.num_vertices : 0;+}++STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)+{+   if (!info->cff.size)+      return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices);+   else+      return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices);+}++STBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing)+{+   stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34);+   if (glyph_index < numOfLongHorMetrics) {+      if (advanceWidth)     *advanceWidth    = ttSHORT(info->data + info->hmtx + 4*glyph_index);+      if (leftSideBearing)  *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2);+   } else {+      if (advanceWidth)     *advanceWidth    = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1));+      if (leftSideBearing)  *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics));+   }+}++static int  stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)+{+   stbtt_uint8 *data = info->data + info->kern;+   stbtt_uint32 needle, straw;+   int l, r, m;++   // we only look at the first table. it must be 'horizontal' and format 0.+   if (!info->kern)+      return 0;+   if (ttUSHORT(data+2) < 1) // number of tables, need at least 1+      return 0;+   if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format+      return 0;++   l = 0;+   r = ttUSHORT(data+10) - 1;+   needle = glyph1 << 16 | glyph2;+   while (l <= r) {+      m = (l + r) >> 1;+      straw = ttULONG(data+18+(m*6)); // note: unaligned read+      if (needle < straw)+         r = m - 1;+      else if (needle > straw)+         l = m + 1;+      else+         return ttSHORT(data+22+(m*6));+   }+   return 0;+}++static stbtt_int32  stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph)+{+    stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);+    switch(coverageFormat) {+        case 1: {+            stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);++            // Binary search.+            stbtt_int32 l=0, r=glyphCount-1, m;+            int straw, needle=glyph;+            while (l <= r) {+                stbtt_uint8 *glyphArray = coverageTable + 4;+                stbtt_uint16 glyphID;+                m = (l + r) >> 1;+                glyphID = ttUSHORT(glyphArray + 2 * m);+                straw = glyphID;+                if (needle < straw)+                    r = m - 1;+                else if (needle > straw)+                    l = m + 1;+                else {+                     return m;+                }+            }+        } break;++        case 2: {+            stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);+            stbtt_uint8 *rangeArray = coverageTable + 4;++            // Binary search.+            stbtt_int32 l=0, r=rangeCount-1, m;+            int strawStart, strawEnd, needle=glyph;+            while (l <= r) {+                stbtt_uint8 *rangeRecord;+                m = (l + r) >> 1;+                rangeRecord = rangeArray + 6 * m;+                strawStart = ttUSHORT(rangeRecord);+                strawEnd = ttUSHORT(rangeRecord + 2);+                if (needle < strawStart)+                    r = m - 1;+                else if (needle > strawEnd)+                    l = m + 1;+                else {+                    stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4);+                    return startCoverageIndex + glyph - strawStart;+                }+            }+        } break;++        default: {+            // There are no other cases.+            STBTT_assert(0);+        } break;+    }++    return -1;+}++static stbtt_int32  stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)+{+    stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);+    switch(classDefFormat)+    {+        case 1: {+            stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);+            stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4);+            stbtt_uint8 *classDef1ValueArray = classDefTable + 6;++            if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)+                return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));++            classDefTable = classDef1ValueArray + 2 * glyphCount;+        } break;++        case 2: {+            stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);+            stbtt_uint8 *classRangeRecords = classDefTable + 4;++            // Binary search.+            stbtt_int32 l=0, r=classRangeCount-1, m;+            int strawStart, strawEnd, needle=glyph;+            while (l <= r) {+                stbtt_uint8 *classRangeRecord;+                m = (l + r) >> 1;+                classRangeRecord = classRangeRecords + 6 * m;+                strawStart = ttUSHORT(classRangeRecord);+                strawEnd = ttUSHORT(classRangeRecord + 2);+                if (needle < strawStart)+                    r = m - 1;+                else if (needle > strawEnd)+                    l = m + 1;+                else+                    return (stbtt_int32)ttUSHORT(classRangeRecord + 4);+            }++            classDefTable = classRangeRecords + 6 * classRangeCount;+        } break;++        default: {+            // There are no other cases.+            STBTT_assert(0);+        } break;+    }++    return -1;+}++// Define to STBTT_assert(x) if you want to break on unimplemented formats.+#define STBTT_GPOS_TODO_assert(x)++static stbtt_int32  stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)+{+    stbtt_uint16 lookupListOffset;+    stbtt_uint8 *lookupList;+    stbtt_uint16 lookupCount;+    stbtt_uint8 *data;+    stbtt_int32 i;++    if (!info->gpos) return 0;++    data = info->data + info->gpos;++    if (ttUSHORT(data+0) != 1) return 0; // Major version 1+    if (ttUSHORT(data+2) != 0) return 0; // Minor version 0++    lookupListOffset = ttUSHORT(data+8);+    lookupList = data + lookupListOffset;+    lookupCount = ttUSHORT(lookupList);++    for (i=0; i<lookupCount; ++i) {+        stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i);+        stbtt_uint8 *lookupTable = lookupList + lookupOffset;++        stbtt_uint16 lookupType = ttUSHORT(lookupTable);+        stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);+        stbtt_uint8 *subTableOffsets = lookupTable + 6;+        switch(lookupType) {+            case 2: { // Pair Adjustment Positioning Subtable+                stbtt_int32 sti;+                for (sti=0; sti<subTableCount; sti++) {+                    stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);+                    stbtt_uint8 *table = lookupTable + subtableOffset;+                    stbtt_uint16 posFormat = ttUSHORT(table);+                    stbtt_uint16 coverageOffset = ttUSHORT(table + 2);+                    stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1);+                    if (coverageIndex == -1) continue;++                    switch (posFormat) {+                        case 1: {+                            stbtt_int32 l, r, m;+                            int straw, needle;+                            stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);+                            stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);+                            stbtt_int32 valueRecordPairSizeInBytes = 2;+                            stbtt_uint16 pairSetCount = ttUSHORT(table + 8);+                            stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);+                            stbtt_uint8 *pairValueTable = table + pairPosOffset;+                            stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);+                            stbtt_uint8 *pairValueArray = pairValueTable + 2;+                            // TODO: Support more formats.+                            STBTT_GPOS_TODO_assert(valueFormat1 == 4);+                            if (valueFormat1 != 4) return 0;+                            STBTT_GPOS_TODO_assert(valueFormat2 == 0);+                            if (valueFormat2 != 0) return 0;++                            STBTT_assert(coverageIndex < pairSetCount);++                            needle=glyph2;+                            r=pairValueCount-1;+                            l=0;++                            // Binary search.+                            while (l <= r) {+                                stbtt_uint16 secondGlyph;+                                stbtt_uint8 *pairValue;+                                m = (l + r) >> 1;+                                pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m;+                                secondGlyph = ttUSHORT(pairValue);+                                straw = secondGlyph;+                                if (needle < straw)+                                    r = m - 1;+                                else if (needle > straw)+                                    l = m + 1;+                                else {+                                    stbtt_int16 xAdvance = ttSHORT(pairValue + 2);+                                    return xAdvance;+                                }+                            }+                        } break;++                        case 2: {+                            stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);+                            stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);++                            stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);+                            stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);+                            int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);+                            int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2);++                            stbtt_uint16 class1Count = ttUSHORT(table + 12);+                            stbtt_uint16 class2Count = ttUSHORT(table + 14);+                            STBTT_assert(glyph1class < class1Count);+                            STBTT_assert(glyph2class < class2Count);++                            // TODO: Support more formats.+                            STBTT_GPOS_TODO_assert(valueFormat1 == 4);+                            if (valueFormat1 != 4) return 0;+                            STBTT_GPOS_TODO_assert(valueFormat2 == 0);+                            if (valueFormat2 != 0) return 0;++                            if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) {+                                stbtt_uint8 *class1Records = table + 16;+                                stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count);+                                stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class);+                                return xAdvance;+                            }+                        } break;++                        default: {+                            // There are no other cases.+                            STBTT_assert(0);+                            break;+                        };+                    }+                }+                break;+            };++            default:+                // TODO: Implement other stuff.+                break;+        }+    }++    return 0;+}++STBTT_DEF int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2)+{+   int xAdvance = 0;++   if (info->gpos)+      xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2);++   if (info->kern)+      xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2);++   return xAdvance;+}++STBTT_DEF int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2)+{+   if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs+      return 0;+   return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2));+}++STBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing)+{+   stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing);+}++STBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap)+{+   if (ascent ) *ascent  = ttSHORT(info->data+info->hhea + 4);+   if (descent) *descent = ttSHORT(info->data+info->hhea + 6);+   if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8);+}++STBTT_DEF int  stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap)+{+   int tab = stbtt__find_table(info->data, info->fontstart, "OS/2");+   if (!tab)+      return 0;+   if (typoAscent ) *typoAscent  = ttSHORT(info->data+tab + 68);+   if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70);+   if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72);+   return 1;+}++STBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1)+{+   *x0 = ttSHORT(info->data + info->head + 36);+   *y0 = ttSHORT(info->data + info->head + 38);+   *x1 = ttSHORT(info->data + info->head + 40);+   *y1 = ttSHORT(info->data + info->head + 42);+}++STBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height)+{+   int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6);+   return (float) height / fheight;+}++STBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels)+{+   int unitsPerEm = ttUSHORT(info->data + info->head + 18);+   return pixels / unitsPerEm;+}++STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)+{+   STBTT_free(v, info->userdata);+}++//////////////////////////////////////////////////////////////////////////////+//+// antialiasing software rasterizer+//++STBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)+{+   int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning+   if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) {+      // e.g. space character+      if (ix0) *ix0 = 0;+      if (iy0) *iy0 = 0;+      if (ix1) *ix1 = 0;+      if (iy1) *iy1 = 0;+   } else {+      // move to integral bboxes (treating pixels as little squares, what pixels get touched)?+      if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x);+      if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y);+      if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x);+      if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y);+   }+}++STBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)+{+   stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1);+}++STBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)+{+   stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1);+}++STBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)+{+   stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1);+}++//////////////////////////////////////////////////////////////////////////////+//+//  Rasterizer++typedef struct stbtt__hheap_chunk+{+   struct stbtt__hheap_chunk *next;+} stbtt__hheap_chunk;++typedef struct stbtt__hheap+{+   struct stbtt__hheap_chunk *head;+   void   *first_free;+   int    num_remaining_in_head_chunk;+} stbtt__hheap;++static void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata)+{+   if (hh->first_free) {+      void *p = hh->first_free;+      hh->first_free = * (void **) p;+      return p;+   } else {+      if (hh->num_remaining_in_head_chunk == 0) {+         int count = (size < 32 ? 2000 : size < 128 ? 800 : 100);+         stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata);+         if (c == NULL)+            return NULL;+         c->next = hh->head;+         hh->head = c;+         hh->num_remaining_in_head_chunk = count;+      }+      --hh->num_remaining_in_head_chunk;+      return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk;+   }+}++static void stbtt__hheap_free(stbtt__hheap *hh, void *p)+{+   *(void **) p = hh->first_free;+   hh->first_free = p;+}++static void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata)+{+   stbtt__hheap_chunk *c = hh->head;+   while (c) {+      stbtt__hheap_chunk *n = c->next;+      STBTT_free(c, userdata);+      c = n;+   }+}++typedef struct stbtt__edge {+   float x0,y0, x1,y1;+   int invert;+} stbtt__edge;+++typedef struct stbtt__active_edge+{+   struct stbtt__active_edge *next;+   #if STBTT_RASTERIZER_VERSION==1+   int x,dx;+   float ey;+   int direction;+   #elif STBTT_RASTERIZER_VERSION==2+   float fx,fdx,fdy;+   float direction;+   float sy;+   float ey;+   #else+   #error "Unrecognized value of STBTT_RASTERIZER_VERSION"+   #endif+} stbtt__active_edge;++#if STBTT_RASTERIZER_VERSION == 1+#define STBTT_FIXSHIFT   10+#define STBTT_FIX        (1 << STBTT_FIXSHIFT)+#define STBTT_FIXMASK    (STBTT_FIX-1)++static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)+{+   stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);+   float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);+   STBTT_assert(z != NULL);+   if (!z) return z;+   +   // round dx down to avoid overshooting+   if (dxdy < 0)+      z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy);+   else+      z->dx = STBTT_ifloor(STBTT_FIX * dxdy);++   z->x = STBTT_ifloor(STBTT_FIX * e->x0 + z->dx * (start_point - e->y0)); // use z->dx so when we offset later it's by the same amount+   z->x -= off_x * STBTT_FIX;++   z->ey = e->y1;+   z->next = 0;+   z->direction = e->invert ? 1 : -1;+   return z;+}+#elif STBTT_RASTERIZER_VERSION == 2+static stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)+{+   stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);+   float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);+   STBTT_assert(z != NULL);+   //STBTT_assert(e->y0 <= start_point);+   if (!z) return z;+   z->fdx = dxdy;+   z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f;+   z->fx = e->x0 + dxdy * (start_point - e->y0);+   z->fx -= off_x;+   z->direction = e->invert ? 1.0f : -1.0f;+   z->sy = e->y0;+   z->ey = e->y1;+   z->next = 0;+   return z;+}+#else+#error "Unrecognized value of STBTT_RASTERIZER_VERSION"+#endif++#if STBTT_RASTERIZER_VERSION == 1+// note: this routine clips fills that extend off the edges... ideally this+// wouldn't happen, but it could happen if the truetype glyph bounding boxes+// are wrong, or if the user supplies a too-small bitmap+static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight)+{+   // non-zero winding fill+   int x0=0, w=0;++   while (e) {+      if (w == 0) {+         // if we're currently at zero, we need to record the edge start point+         x0 = e->x; w += e->direction;+      } else {+         int x1 = e->x; w += e->direction;+         // if we went to zero, we need to draw+         if (w == 0) {+            int i = x0 >> STBTT_FIXSHIFT;+            int j = x1 >> STBTT_FIXSHIFT;++            if (i < len && j >= 0) {+               if (i == j) {+                  // x0,x1 are the same pixel, so compute combined coverage+                  scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT);+               } else {+                  if (i >= 0) // add antialiasing for x0+                     scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT);+                  else+                     i = -1; // clip++                  if (j < len) // add antialiasing for x1+                     scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT);+                  else+                     j = len; // clip++                  for (++i; i < j; ++i) // fill pixels between x0 and x1+                     scanline[i] = scanline[i] + (stbtt_uint8) max_weight;+               }+            }+         }+      }+      +      e = e->next;+   }+}++static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)+{+   stbtt__hheap hh = { 0, 0, 0 };+   stbtt__active_edge *active = NULL;+   int y,j=0;+   int max_weight = (255 / vsubsample);  // weight per vertical scanline+   int s; // vertical subsample index+   unsigned char scanline_data[512], *scanline;++   if (result->w > 512)+      scanline = (unsigned char *) STBTT_malloc(result->w, userdata);+   else+      scanline = scanline_data;++   y = off_y * vsubsample;+   e[n].y0 = (off_y + result->h) * (float) vsubsample + 1;++   while (j < result->h) {+      STBTT_memset(scanline, 0, result->w);+      for (s=0; s < vsubsample; ++s) {+         // find center of pixel for this scanline+         float scan_y = y + 0.5f;+         stbtt__active_edge **step = &active;++         // update all active edges;+         // remove all active edges that terminate before the center of this scanline+         while (*step) {+            stbtt__active_edge * z = *step;+            if (z->ey <= scan_y) {+               *step = z->next; // delete from list+               STBTT_assert(z->direction);+               z->direction = 0;+               stbtt__hheap_free(&hh, z);+            } else {+               z->x += z->dx; // advance to position for current scanline+               step = &((*step)->next); // advance through list+            }+         }++         // resort the list if needed+         for(;;) {+            int changed=0;+            step = &active;+            while (*step && (*step)->next) {+               if ((*step)->x > (*step)->next->x) {+                  stbtt__active_edge *t = *step;+                  stbtt__active_edge *q = t->next;++                  t->next = q->next;+                  q->next = t;+                  *step = q;+                  changed = 1;+               }+               step = &(*step)->next;+            }+            if (!changed) break;+         }++         // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline+         while (e->y0 <= scan_y) {+            if (e->y1 > scan_y) {+               stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata);+               if (z != NULL) {+                  // find insertion point+                  if (active == NULL)+                     active = z;+                  else if (z->x < active->x) {+                     // insert at front+                     z->next = active;+                     active = z;+                  } else {+                     // find thing to insert AFTER+                     stbtt__active_edge *p = active;+                     while (p->next && p->next->x < z->x)+                        p = p->next;+                     // at this point, p->next->x is NOT < z->x+                     z->next = p->next;+                     p->next = z;+                  }+               }+            }+            ++e;+         }++         // now process all active edges in XOR fashion+         if (active)+            stbtt__fill_active_edges(scanline, result->w, active, max_weight);++         ++y;+      }+      STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w);+      ++j;+   }++   stbtt__hheap_cleanup(&hh, userdata);++   if (scanline != scanline_data)+      STBTT_free(scanline, userdata);+}++#elif STBTT_RASTERIZER_VERSION == 2++// the edge passed in here does not cross the vertical line at x or the vertical line at x+1+// (i.e. it has already been clipped to those)+static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1)+{+   if (y0 == y1) return;+   STBTT_assert(y0 < y1);+   STBTT_assert(e->sy <= e->ey);+   if (y0 > e->ey) return;+   if (y1 < e->sy) return;+   if (y0 < e->sy) {+      x0 += (x1-x0) * (e->sy - y0) / (y1-y0);+      y0 = e->sy;+   }+   if (y1 > e->ey) {+      x1 += (x1-x0) * (e->ey - y1) / (y1-y0);+      y1 = e->ey;+   }++   if (x0 == x)+      STBTT_assert(x1 <= x+1);+   else if (x0 == x+1)+      STBTT_assert(x1 >= x);+   else if (x0 <= x)+      STBTT_assert(x1 <= x);+   else if (x0 >= x+1)+      STBTT_assert(x1 >= x+1);+   else+      STBTT_assert(x1 >= x && x1 <= x+1);++   if (x0 <= x && x1 <= x)+      scanline[x] += e->direction * (y1-y0);+   else if (x0 >= x+1 && x1 >= x+1)+      ;+   else {+      STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1);+      scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position+   }+}++static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top)+{+   float y_bottom = y_top+1;++   while (e) {+      // brute force every pixel++      // compute intersection points with top & bottom+      STBTT_assert(e->ey >= y_top);++      if (e->fdx == 0) {+         float x0 = e->fx;+         if (x0 < len) {+            if (x0 >= 0) {+               stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom);+               stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom);+            } else {+               stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom);+            }+         }+      } else {+         float x0 = e->fx;+         float dx = e->fdx;+         float xb = x0 + dx;+         float x_top, x_bottom;+         float sy0,sy1;+         float dy = e->fdy;+         STBTT_assert(e->sy <= y_bottom && e->ey >= y_top);++         // compute endpoints of line segment clipped to this scanline (if the+         // line segment starts on this scanline. x0 is the intersection of the+         // line with y_top, but that may be off the line segment.+         if (e->sy > y_top) {+            x_top = x0 + dx * (e->sy - y_top);+            sy0 = e->sy;+         } else {+            x_top = x0;+            sy0 = y_top;+         }+         if (e->ey < y_bottom) {+            x_bottom = x0 + dx * (e->ey - y_top);+            sy1 = e->ey;+         } else {+            x_bottom = xb;+            sy1 = y_bottom;+         }++         if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) {+            // from here on, we don't have to range check x values++            if ((int) x_top == (int) x_bottom) {+               float height;+               // simple case, only spans one pixel+               int x = (int) x_top;+               height = sy1 - sy0;+               STBTT_assert(x >= 0 && x < len);+               scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2)  * height;+               scanline_fill[x] += e->direction * height; // everything right of this pixel is filled+            } else {+               int x,x1,x2;+               float y_crossing, step, sign, area;+               // covers 2+ pixels+               if (x_top > x_bottom) {+                  // flip scanline vertically; signed area is the same+                  float t;+                  sy0 = y_bottom - (sy0 - y_top);+                  sy1 = y_bottom - (sy1 - y_top);+                  t = sy0, sy0 = sy1, sy1 = t;+                  t = x_bottom, x_bottom = x_top, x_top = t;+                  dx = -dx;+                  dy = -dy;+                  t = x0, x0 = xb, xb = t;+               }++               x1 = (int) x_top;+               x2 = (int) x_bottom;+               // compute intersection with y axis at x1+1+               y_crossing = (x1+1 - x0) * dy + y_top;++               sign = e->direction;+               // area of the rectangle covered from y0..y_crossing+               area = sign * (y_crossing-sy0);+               // area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing)+               scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2);++               step = sign * dy;+               for (x = x1+1; x < x2; ++x) {+                  scanline[x] += area + step/2;+                  area += step;+               }+               y_crossing += dy * (x2 - (x1+1));++               STBTT_assert(STBTT_fabs(area) <= 1.01f);++               scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing);++               scanline_fill[x2] += sign * (sy1-sy0);+            }+         } else {+            // if edge goes outside of box we're drawing, we require+            // clipping logic. since this does not match the intended use+            // of this library, we use a different, very slow brute+            // force implementation+            int x;+            for (x=0; x < len; ++x) {+               // cases:+               //+               // there can be up to two intersections with the pixel. any intersection+               // with left or right edges can be handled by splitting into two (or three)+               // regions. intersections with top & bottom do not necessitate case-wise logic.+               //+               // the old way of doing this found the intersections with the left & right edges,+               // then used some simple logic to produce up to three segments in sorted order+               // from top-to-bottom. however, this had a problem: if an x edge was epsilon+               // across the x border, then the corresponding y position might not be distinct+               // from the other y segment, and it might ignored as an empty segment. to avoid+               // that, we need to explicitly produce segments based on x positions.++               // rename variables to clearly-defined pairs+               float y0 = y_top;+               float x1 = (float) (x);+               float x2 = (float) (x+1);+               float x3 = xb;+               float y3 = y_bottom;++               // x = e->x + e->dx * (y-y_top)+               // (y-y_top) = (x - e->x) / e->dx+               // y = (x - e->x) / e->dx + y_top+               float y1 = (x - x0) / dx + y_top;+               float y2 = (x+1 - x0) / dx + y_top;++               if (x0 < x1 && x3 > x2) {         // three segments descending down-right+                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);+                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2);+                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);+               } else if (x3 < x1 && x0 > x2) {  // three segments descending down-left+                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);+                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1);+                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);+               } else if (x0 < x1 && x3 > x1) {  // two segments across x, down-right+                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);+                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);+               } else if (x3 < x1 && x0 > x1) {  // two segments across x, down-left+                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);+                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);+               } else if (x0 < x2 && x3 > x2) {  // two segments across x+1, down-right+                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);+                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);+               } else if (x3 < x2 && x0 > x2) {  // two segments across x+1, down-left+                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);+                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);+               } else {  // one segment+                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3);+               }+            }+         }+      }+      e = e->next;+   }+}++// directly AA rasterize edges w/o supersampling+static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)+{+   stbtt__hheap hh = { 0, 0, 0 };+   stbtt__active_edge *active = NULL;+   int y,j=0, i;+   float scanline_data[129], *scanline, *scanline2;++   STBTT__NOTUSED(vsubsample);++   if (result->w > 64)+      scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata);+   else+      scanline = scanline_data;++   scanline2 = scanline + result->w;++   y = off_y;+   e[n].y0 = (float) (off_y + result->h) + 1;++   while (j < result->h) {+      // find center of pixel for this scanline+      float scan_y_top    = y + 0.0f;+      float scan_y_bottom = y + 1.0f;+      stbtt__active_edge **step = &active;++      STBTT_memset(scanline , 0, result->w*sizeof(scanline[0]));+      STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0]));++      // update all active edges;+      // remove all active edges that terminate before the top of this scanline+      while (*step) {+         stbtt__active_edge * z = *step;+         if (z->ey <= scan_y_top) {+            *step = z->next; // delete from list+            STBTT_assert(z->direction);+            z->direction = 0;+            stbtt__hheap_free(&hh, z);+         } else {+            step = &((*step)->next); // advance through list+         }+      }++      // insert all edges that start before the bottom of this scanline+      while (e->y0 <= scan_y_bottom) {+         if (e->y0 != e->y1) {+            stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata);+            if (z != NULL) {+               STBTT_assert(z->ey >= scan_y_top);+               // insert at front+               z->next = active;+               active = z;+            }+         }+         ++e;+      }++      // now process all active edges+      if (active)+         stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top);++      {+         float sum = 0;+         for (i=0; i < result->w; ++i) {+            float k;+            int m;+            sum += scanline2[i];+            k = scanline[i] + sum;+            k = (float) STBTT_fabs(k)*255 + 0.5f;+            m = (int) k;+            if (m > 255) m = 255;+            result->pixels[j*result->stride + i] = (unsigned char) m;+         }+      }+      // advance all the edges+      step = &active;+      while (*step) {+         stbtt__active_edge *z = *step;+         z->fx += z->fdx; // advance to position for current scanline+         step = &((*step)->next); // advance through list+      }++      ++y;+      ++j;+   }++   stbtt__hheap_cleanup(&hh, userdata);++   if (scanline != scanline_data)+      STBTT_free(scanline, userdata);+}+#else+#error "Unrecognized value of STBTT_RASTERIZER_VERSION"+#endif++#define STBTT__COMPARE(a,b)  ((a)->y0 < (b)->y0)++static void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n)+{+   int i,j;+   for (i=1; i < n; ++i) {+      stbtt__edge t = p[i], *a = &t;+      j = i;+      while (j > 0) {+         stbtt__edge *b = &p[j-1];+         int c = STBTT__COMPARE(a,b);+         if (!c) break;+         p[j] = p[j-1];+         --j;+      }+      if (i != j)+         p[j] = t;+   }+}++static void stbtt__sort_edges_quicksort(stbtt__edge *p, int n)+{+   /* threshhold for transitioning to insertion sort */+   while (n > 12) {+      stbtt__edge t;+      int c01,c12,c,m,i,j;++      /* compute median of three */+      m = n >> 1;+      c01 = STBTT__COMPARE(&p[0],&p[m]);+      c12 = STBTT__COMPARE(&p[m],&p[n-1]);+      /* if 0 >= mid >= end, or 0 < mid < end, then use mid */+      if (c01 != c12) {+         /* otherwise, we'll need to swap something else to middle */+         int z;+         c = STBTT__COMPARE(&p[0],&p[n-1]);+         /* 0>mid && mid<n:  0>n => n; 0<n => 0 */+         /* 0<mid && mid>n:  0>n => 0; 0<n => n */+         z = (c == c12) ? 0 : n-1;+         t = p[z];+         p[z] = p[m];+         p[m] = t;+      }+      /* now p[m] is the median-of-three */+      /* swap it to the beginning so it won't move around */+      t = p[0];+      p[0] = p[m];+      p[m] = t;++      /* partition loop */+      i=1;+      j=n-1;+      for(;;) {+         /* handling of equality is crucial here */+         /* for sentinels & efficiency with duplicates */+         for (;;++i) {+            if (!STBTT__COMPARE(&p[i], &p[0])) break;+         }+         for (;;--j) {+            if (!STBTT__COMPARE(&p[0], &p[j])) break;+         }+         /* make sure we haven't crossed */+         if (i >= j) break;+         t = p[i];+         p[i] = p[j];+         p[j] = t;++         ++i;+         --j;+      }+      /* recurse on smaller side, iterate on larger */+      if (j < (n-i)) {+         stbtt__sort_edges_quicksort(p,j);+         p = p+i;+         n = n-i;+      } else {+         stbtt__sort_edges_quicksort(p+i, n-i);+         n = j;+      }+   }+}++static void stbtt__sort_edges(stbtt__edge *p, int n)+{+   stbtt__sort_edges_quicksort(p, n);+   stbtt__sort_edges_ins_sort(p, n);+}++typedef struct+{+   float x,y;+} stbtt__point;++static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata)+{+   float y_scale_inv = invert ? -scale_y : scale_y;+   stbtt__edge *e;+   int n,i,j,k,m;+#if STBTT_RASTERIZER_VERSION == 1+   int vsubsample = result->h < 8 ? 15 : 5;+#elif STBTT_RASTERIZER_VERSION == 2+   int vsubsample = 1;+#else+   #error "Unrecognized value of STBTT_RASTERIZER_VERSION"+#endif+   // vsubsample should divide 255 evenly; otherwise we won't reach full opacity++   // now we have to blow out the windings into explicit edge lists+   n = 0;+   for (i=0; i < windings; ++i)+      n += wcount[i];++   e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel+   if (e == 0) return;+   n = 0;++   m=0;+   for (i=0; i < windings; ++i) {+      stbtt__point *p = pts + m;+      m += wcount[i];+      j = wcount[i]-1;+      for (k=0; k < wcount[i]; j=k++) {+         int a=k,b=j;+         // skip the edge if horizontal+         if (p[j].y == p[k].y)+            continue;+         // add edge from j to k to the list+         e[n].invert = 0;+         if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) {+            e[n].invert = 1;+            a=j,b=k;+         }+         e[n].x0 = p[a].x * scale_x + shift_x;+         e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample;+         e[n].x1 = p[b].x * scale_x + shift_x;+         e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample;+         ++n;+      }+   }++   // now sort the edges by their highest point (should snap to integer, and then by x)+   //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare);+   stbtt__sort_edges(e, n);++   // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule+   stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata);++   STBTT_free(e, userdata);+}++static void stbtt__add_point(stbtt__point *points, int n, float x, float y)+{+   if (!points) return; // during first pass, it's unallocated+   points[n].x = x;+   points[n].y = y;+}++// tesselate until threshhold p is happy... @TODO warped to compensate for non-linear stretching+static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n)+{+   // midpoint+   float mx = (x0 + 2*x1 + x2)/4;+   float my = (y0 + 2*y1 + y2)/4;+   // versus directly drawn line+   float dx = (x0+x2)/2 - mx;+   float dy = (y0+y2)/2 - my;+   if (n > 16) // 65536 segments on one curve better be enough!+      return 1;+   if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA+      stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1);+      stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1);+   } else {+      stbtt__add_point(points, *num_points,x2,y2);+      *num_points = *num_points+1;+   }+   return 1;+}++static void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n)+{+   // @TODO this "flatness" calculation is just made-up nonsense that seems to work well enough+   float dx0 = x1-x0;+   float dy0 = y1-y0;+   float dx1 = x2-x1;+   float dy1 = y2-y1;+   float dx2 = x3-x2;+   float dy2 = y3-y2;+   float dx = x3-x0;+   float dy = y3-y0;+   float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2));+   float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy);+   float flatness_squared = longlen*longlen-shortlen*shortlen;++   if (n > 16) // 65536 segments on one curve better be enough!+      return;++   if (flatness_squared > objspace_flatness_squared) {+      float x01 = (x0+x1)/2;+      float y01 = (y0+y1)/2;+      float x12 = (x1+x2)/2;+      float y12 = (y1+y2)/2;+      float x23 = (x2+x3)/2;+      float y23 = (y2+y3)/2;++      float xa = (x01+x12)/2;+      float ya = (y01+y12)/2;+      float xb = (x12+x23)/2;+      float yb = (y12+y23)/2;++      float mx = (xa+xb)/2;+      float my = (ya+yb)/2;++      stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1);+      stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1);+   } else {+      stbtt__add_point(points, *num_points,x3,y3);+      *num_points = *num_points+1;+   }+}++// returns number of contours+static stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata)+{+   stbtt__point *points=0;+   int num_points=0;++   float objspace_flatness_squared = objspace_flatness * objspace_flatness;+   int i,n=0,start=0, pass;++   // count how many "moves" there are to get the contour count+   for (i=0; i < num_verts; ++i)+      if (vertices[i].type == STBTT_vmove)+         ++n;++   *num_contours = n;+   if (n == 0) return 0;++   *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata);++   if (*contour_lengths == 0) {+      *num_contours = 0;+      return 0;+   }++   // make two passes through the points so we don't need to realloc+   for (pass=0; pass < 2; ++pass) {+      float x=0,y=0;+      if (pass == 1) {+         points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata);+         if (points == NULL) goto error;+      }+      num_points = 0;+      n= -1;+      for (i=0; i < num_verts; ++i) {+         switch (vertices[i].type) {+            case STBTT_vmove:+               // start the next contour+               if (n >= 0)+                  (*contour_lengths)[n] = num_points - start;+               ++n;+               start = num_points;++               x = vertices[i].x, y = vertices[i].y;+               stbtt__add_point(points, num_points++, x,y);+               break;+            case STBTT_vline:+               x = vertices[i].x, y = vertices[i].y;+               stbtt__add_point(points, num_points++, x, y);+               break;+            case STBTT_vcurve:+               stbtt__tesselate_curve(points, &num_points, x,y,+                                        vertices[i].cx, vertices[i].cy,+                                        vertices[i].x,  vertices[i].y,+                                        objspace_flatness_squared, 0);+               x = vertices[i].x, y = vertices[i].y;+               break;+            case STBTT_vcubic:+               stbtt__tesselate_cubic(points, &num_points, x,y,+                                        vertices[i].cx, vertices[i].cy,+                                        vertices[i].cx1, vertices[i].cy1,+                                        vertices[i].x,  vertices[i].y,+                                        objspace_flatness_squared, 0);+               x = vertices[i].x, y = vertices[i].y;+               break;+         }+      }+      (*contour_lengths)[n] = num_points - start;+   }++   return points;+error:+   STBTT_free(points, userdata);+   STBTT_free(*contour_lengths, userdata);+   *contour_lengths = 0;+   *num_contours = 0;+   return NULL;+}++STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata)+{+   float scale            = scale_x > scale_y ? scale_y : scale_x;+   int winding_count      = 0;+   int *winding_lengths   = NULL;+   stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);+   if (windings) {+      stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata);+      STBTT_free(winding_lengths, userdata);+      STBTT_free(windings, userdata);+   }+}++STBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata)+{+   STBTT_free(bitmap, userdata);+}++STBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff)+{+   int ix0,iy0,ix1,iy1;+   stbtt__bitmap gbm;+   stbtt_vertex *vertices;   +   int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);++   if (scale_x == 0) scale_x = scale_y;+   if (scale_y == 0) {+      if (scale_x == 0) {+         STBTT_free(vertices, info->userdata);+         return NULL;+      }+      scale_y = scale_x;+   }++   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1);++   // now we get the size+   gbm.w = (ix1 - ix0);+   gbm.h = (iy1 - iy0);+   gbm.pixels = NULL; // in case we error++   if (width ) *width  = gbm.w;+   if (height) *height = gbm.h;+   if (xoff  ) *xoff   = ix0;+   if (yoff  ) *yoff   = iy0;+   +   if (gbm.w && gbm.h) {+      gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata);+      if (gbm.pixels) {+         gbm.stride = gbm.w;++         stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata);+      }+   }+   STBTT_free(vertices, info->userdata);+   return gbm.pixels;+}   ++STBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff)+{+   return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff);+}++STBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph)+{+   int ix0,iy0;+   stbtt_vertex *vertices;+   int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);+   stbtt__bitmap gbm;   ++   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0);+   gbm.pixels = output;+   gbm.w = out_w;+   gbm.h = out_h;+   gbm.stride = out_stride;++   if (gbm.w && gbm.h)+      stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata);++   STBTT_free(vertices, info->userdata);+}++STBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph)+{+   stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph);+}++STBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff)+{+   return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);+}   ++STBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint)+{+   stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint));+}++STBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint)+{+   stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint));+}++STBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff)+{+   return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff);+}   ++STBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint)+{+   stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint);+}++//////////////////////////////////////////////////////////////////////////////+//+// bitmap baking+//+// This is SUPER-CRAPPY packing to keep source code small++static int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset,  // font location (use offset=0 for plain .ttf)+                                float pixel_height,                     // height of font in pixels+                                unsigned char *pixels, int pw, int ph,  // bitmap to be filled in+                                int first_char, int num_chars,          // characters to bake+                                stbtt_bakedchar *chardata)+{+   float scale;+   int x,y,bottom_y, i;+   stbtt_fontinfo f;+   f.userdata = NULL;+   if (!stbtt_InitFont(&f, data, offset))+      return -1;+   STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels+   x=y=1;+   bottom_y = 1;++   scale = stbtt_ScaleForPixelHeight(&f, pixel_height);++   for (i=0; i < num_chars; ++i) {+      int advance, lsb, x0,y0,x1,y1,gw,gh;+      int g = stbtt_FindGlyphIndex(&f, first_char + i);+      stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb);+      stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1);+      gw = x1-x0;+      gh = y1-y0;+      if (x + gw + 1 >= pw)+         y = bottom_y, x = 1; // advance to next row+      if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row+         return -i;+      STBTT_assert(x+gw < pw);+      STBTT_assert(y+gh < ph);+      stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g);+      chardata[i].x0 = (stbtt_int16) x;+      chardata[i].y0 = (stbtt_int16) y;+      chardata[i].x1 = (stbtt_int16) (x + gw);+      chardata[i].y1 = (stbtt_int16) (y + gh);+      chardata[i].xadvance = scale * advance;+      chardata[i].xoff     = (float) x0;+      chardata[i].yoff     = (float) y0;+      x = x + gw + 1;+      if (y+gh+1 > bottom_y)+         bottom_y = y+gh+1;+   }+   return bottom_y;+}++STBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule)+{+   float d3d_bias = opengl_fillrule ? 0 : -0.5f;+   float ipw = 1.0f / pw, iph = 1.0f / ph;+   const stbtt_bakedchar *b = chardata + char_index;+   int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f);+   int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f);++   q->x0 = round_x + d3d_bias;+   q->y0 = round_y + d3d_bias;+   q->x1 = round_x + b->x1 - b->x0 + d3d_bias;+   q->y1 = round_y + b->y1 - b->y0 + d3d_bias;++   q->s0 = b->x0 * ipw;+   q->t0 = b->y0 * iph;+   q->s1 = b->x1 * ipw;+   q->t1 = b->y1 * iph;++   *xpos += b->xadvance;+}++//////////////////////////////////////////////////////////////////////////////+//+// rectangle packing replacement routines if you don't have stb_rect_pack.h+//++#ifndef STB_RECT_PACK_VERSION++typedef int stbrp_coord;++////////////////////////////////////////////////////////////////////////////////////+//                                                                                //+//                                                                                //+// COMPILER WARNING ?!?!?                                                         //+//                                                                                //+//                                                                                //+// if you get a compile warning due to these symbols being defined more than      //+// once, move #include "stb_rect_pack.h" before #include "stb_truetype.h"         //+//                                                                                //+////////////////////////////////////////////////////////////////////////////////////++typedef struct+{+   int width,height;+   int x,y,bottom_y;+} stbrp_context;++typedef struct+{+   unsigned char x;+} stbrp_node;++struct stbrp_rect+{+   stbrp_coord x,y;+   int id,w,h,was_packed;+};++static void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes)+{+   con->width  = pw;+   con->height = ph;+   con->x = 0;+   con->y = 0;+   con->bottom_y = 0;+   STBTT__NOTUSED(nodes);+   STBTT__NOTUSED(num_nodes);   +}++static void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects)+{+   int i;+   for (i=0; i < num_rects; ++i) {+      if (con->x + rects[i].w > con->width) {+         con->x = 0;+         con->y = con->bottom_y;+      }+      if (con->y + rects[i].h > con->height)+         break;+      rects[i].x = con->x;+      rects[i].y = con->y;+      rects[i].was_packed = 1;+      con->x += rects[i].w;+      if (con->y + rects[i].h > con->bottom_y)+         con->bottom_y = con->y + rects[i].h;+   }+   for (   ; i < num_rects; ++i)+      rects[i].was_packed = 0;+}+#endif++//////////////////////////////////////////////////////////////////////////////+//+// bitmap baking+//+// This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If+// stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy.++STBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context)+{+   stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context)            ,alloc_context);+   int            num_nodes = pw - padding;+   stbrp_node    *nodes   = (stbrp_node    *) STBTT_malloc(sizeof(*nodes  ) * num_nodes,alloc_context);++   if (context == NULL || nodes == NULL) {+      if (context != NULL) STBTT_free(context, alloc_context);+      if (nodes   != NULL) STBTT_free(nodes  , alloc_context);+      return 0;+   }++   spc->user_allocator_context = alloc_context;+   spc->width = pw;+   spc->height = ph;+   spc->pixels = pixels;+   spc->pack_info = context;+   spc->nodes = nodes;+   spc->padding = padding;+   spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw;+   spc->h_oversample = 1;+   spc->v_oversample = 1;++   stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes);++   if (pixels)+      STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels++   return 1;+}++STBTT_DEF void stbtt_PackEnd  (stbtt_pack_context *spc)+{+   STBTT_free(spc->nodes    , spc->user_allocator_context);+   STBTT_free(spc->pack_info, spc->user_allocator_context);+}++STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample)+{+   STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE);+   STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE);+   if (h_oversample <= STBTT_MAX_OVERSAMPLE)+      spc->h_oversample = h_oversample;+   if (v_oversample <= STBTT_MAX_OVERSAMPLE)+      spc->v_oversample = v_oversample;+}++#define STBTT__OVER_MASK  (STBTT_MAX_OVERSAMPLE-1)++static void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)+{+   unsigned char buffer[STBTT_MAX_OVERSAMPLE];+   int safe_w = w - kernel_width;+   int j;+   STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze+   for (j=0; j < h; ++j) {+      int i;+      unsigned int total;+      STBTT_memset(buffer, 0, kernel_width);++      total = 0;++      // make kernel_width a constant in common cases so compiler can optimize out the divide+      switch (kernel_width) {+         case 2:+            for (i=0; i <= safe_w; ++i) {+               total += pixels[i] - buffer[i & STBTT__OVER_MASK];+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];+               pixels[i] = (unsigned char) (total / 2);+            }+            break;+         case 3:+            for (i=0; i <= safe_w; ++i) {+               total += pixels[i] - buffer[i & STBTT__OVER_MASK];+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];+               pixels[i] = (unsigned char) (total / 3);+            }+            break;+         case 4:+            for (i=0; i <= safe_w; ++i) {+               total += pixels[i] - buffer[i & STBTT__OVER_MASK];+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];+               pixels[i] = (unsigned char) (total / 4);+            }+            break;+         case 5:+            for (i=0; i <= safe_w; ++i) {+               total += pixels[i] - buffer[i & STBTT__OVER_MASK];+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];+               pixels[i] = (unsigned char) (total / 5);+            }+            break;+         default:+            for (i=0; i <= safe_w; ++i) {+               total += pixels[i] - buffer[i & STBTT__OVER_MASK];+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];+               pixels[i] = (unsigned char) (total / kernel_width);+            }+            break;+      }++      for (; i < w; ++i) {+         STBTT_assert(pixels[i] == 0);+         total -= buffer[i & STBTT__OVER_MASK];+         pixels[i] = (unsigned char) (total / kernel_width);+      }++      pixels += stride_in_bytes;+   }+}++static void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)+{+   unsigned char buffer[STBTT_MAX_OVERSAMPLE];+   int safe_h = h - kernel_width;+   int j;+   STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze+   for (j=0; j < w; ++j) {+      int i;+      unsigned int total;+      STBTT_memset(buffer, 0, kernel_width);++      total = 0;++      // make kernel_width a constant in common cases so compiler can optimize out the divide+      switch (kernel_width) {+         case 2:+            for (i=0; i <= safe_h; ++i) {+               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];+               pixels[i*stride_in_bytes] = (unsigned char) (total / 2);+            }+            break;+         case 3:+            for (i=0; i <= safe_h; ++i) {+               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];+               pixels[i*stride_in_bytes] = (unsigned char) (total / 3);+            }+            break;+         case 4:+            for (i=0; i <= safe_h; ++i) {+               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];+               pixels[i*stride_in_bytes] = (unsigned char) (total / 4);+            }+            break;+         case 5:+            for (i=0; i <= safe_h; ++i) {+               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];+               pixels[i*stride_in_bytes] = (unsigned char) (total / 5);+            }+            break;+         default:+            for (i=0; i <= safe_h; ++i) {+               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];+               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];+               pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);+            }+            break;+      }++      for (; i < h; ++i) {+         STBTT_assert(pixels[i*stride_in_bytes] == 0);+         total -= buffer[i & STBTT__OVER_MASK];+         pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);+      }++      pixels += 1;+   }+}++static float stbtt__oversample_shift(int oversample)+{+   if (!oversample)+      return 0.0f;++   // The prefilter is a box filter of width "oversample",+   // which shifts phase by (oversample - 1)/2 pixels in+   // oversampled space. We want to shift in the opposite+   // direction to counter this.+   return (float)-(oversample - 1) / (2.0f * (float)oversample);+}++// rects array must be big enough to accommodate all characters in the given ranges+STBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)+{+   int i,j,k;++   k=0;+   for (i=0; i < num_ranges; ++i) {+      float fh = ranges[i].font_size;+      float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);+      ranges[i].h_oversample = (unsigned char) spc->h_oversample;+      ranges[i].v_oversample = (unsigned char) spc->v_oversample;+      for (j=0; j < ranges[i].num_chars; ++j) {+         int x0,y0,x1,y1;+         int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];+         int glyph = stbtt_FindGlyphIndex(info, codepoint);+         stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,+                                         scale * spc->h_oversample,+                                         scale * spc->v_oversample,+                                         0,0,+                                         &x0,&y0,&x1,&y1);+         rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);+         rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);+         ++k;+      }+   }++   return k;+}++STBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph)+{+   stbtt_MakeGlyphBitmapSubpixel(info,+                                 output,+                                 out_w - (prefilter_x - 1),+                                 out_h - (prefilter_y - 1),+                                 out_stride,+                                 scale_x,+                                 scale_y,+                                 shift_x,+                                 shift_y,+                                 glyph);++   if (prefilter_x > 1)+      stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x);++   if (prefilter_y > 1)+      stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y);++   *sub_x = stbtt__oversample_shift(prefilter_x);+   *sub_y = stbtt__oversample_shift(prefilter_y);+}++// rects array must be big enough to accommodate all characters in the given ranges+STBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)+{+   int i,j,k, return_value = 1;++   // save current values+   int old_h_over = spc->h_oversample;+   int old_v_over = spc->v_oversample;++   k = 0;+   for (i=0; i < num_ranges; ++i) {+      float fh = ranges[i].font_size;+      float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);+      float recip_h,recip_v,sub_x,sub_y;+      spc->h_oversample = ranges[i].h_oversample;+      spc->v_oversample = ranges[i].v_oversample;+      recip_h = 1.0f / spc->h_oversample;+      recip_v = 1.0f / spc->v_oversample;+      sub_x = stbtt__oversample_shift(spc->h_oversample);+      sub_y = stbtt__oversample_shift(spc->v_oversample);+      for (j=0; j < ranges[i].num_chars; ++j) {+         stbrp_rect *r = &rects[k];+         if (r->was_packed) {+            stbtt_packedchar *bc = &ranges[i].chardata_for_range[j];+            int advance, lsb, x0,y0,x1,y1;+            int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];+            int glyph = stbtt_FindGlyphIndex(info, codepoint);+            stbrp_coord pad = (stbrp_coord) spc->padding;++            // pad on left and top+            r->x += pad;+            r->y += pad;+            r->w -= pad;+            r->h -= pad;+            stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb);+            stbtt_GetGlyphBitmapBox(info, glyph,+                                    scale * spc->h_oversample,+                                    scale * spc->v_oversample,+                                    &x0,&y0,&x1,&y1);+            stbtt_MakeGlyphBitmapSubpixel(info,+                                          spc->pixels + r->x + r->y*spc->stride_in_bytes,+                                          r->w - spc->h_oversample+1,+                                          r->h - spc->v_oversample+1,+                                          spc->stride_in_bytes,+                                          scale * spc->h_oversample,+                                          scale * spc->v_oversample,+                                          0,0,+                                          glyph);++            if (spc->h_oversample > 1)+               stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,+                                  r->w, r->h, spc->stride_in_bytes,+                                  spc->h_oversample);++            if (spc->v_oversample > 1)+               stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,+                                  r->w, r->h, spc->stride_in_bytes,+                                  spc->v_oversample);++            bc->x0       = (stbtt_int16)  r->x;+            bc->y0       = (stbtt_int16)  r->y;+            bc->x1       = (stbtt_int16) (r->x + r->w);+            bc->y1       = (stbtt_int16) (r->y + r->h);+            bc->xadvance =                scale * advance;+            bc->xoff     =       (float)  x0 * recip_h + sub_x;+            bc->yoff     =       (float)  y0 * recip_v + sub_y;+            bc->xoff2    =                (x0 + r->w) * recip_h + sub_x;+            bc->yoff2    =                (y0 + r->h) * recip_v + sub_y;+         } else {+            return_value = 0; // if any fail, report failure+         }++         ++k;+      }+   }++   // restore original values+   spc->h_oversample = old_h_over;+   spc->v_oversample = old_v_over;++   return return_value;+}++STBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects)+{+   stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects);+}++STBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges)+{+   stbtt_fontinfo info;+   int i,j,n, return_value = 1;+   //stbrp_context *context = (stbrp_context *) spc->pack_info;+   stbrp_rect    *rects;++   // flag all characters as NOT packed+   for (i=0; i < num_ranges; ++i)+      for (j=0; j < ranges[i].num_chars; ++j)+         ranges[i].chardata_for_range[j].x0 =+         ranges[i].chardata_for_range[j].y0 =+         ranges[i].chardata_for_range[j].x1 =+         ranges[i].chardata_for_range[j].y1 = 0;++   n = 0;+   for (i=0; i < num_ranges; ++i)+      n += ranges[i].num_chars;+         +   rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context);+   if (rects == NULL)+      return 0;++   info.userdata = spc->user_allocator_context;+   stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index));++   n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects);++   stbtt_PackFontRangesPackRects(spc, rects, n);+  +   return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects);++   STBTT_free(rects, spc->user_allocator_context);+   return return_value;+}++STBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,+            int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range)+{+   stbtt_pack_range range;+   range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range;+   range.array_of_unicode_codepoints = NULL;+   range.num_chars                   = num_chars_in_range;+   range.chardata_for_range          = chardata_for_range;+   range.font_size                   = font_size;+   return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1);+}++STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer)+{+   float ipw = 1.0f / pw, iph = 1.0f / ph;+   const stbtt_packedchar *b = chardata + char_index;++   if (align_to_integer) {+      float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f);+      float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f);+      q->x0 = x;+      q->y0 = y;+      q->x1 = x + b->xoff2 - b->xoff;+      q->y1 = y + b->yoff2 - b->yoff;+   } else {+      q->x0 = *xpos + b->xoff;+      q->y0 = *ypos + b->yoff;+      q->x1 = *xpos + b->xoff2;+      q->y1 = *ypos + b->yoff2;+   }++   q->s0 = b->x0 * ipw;+   q->t0 = b->y0 * iph;+   q->s1 = b->x1 * ipw;+   q->t1 = b->y1 * iph;++   *xpos += b->xadvance;+}++//////////////////////////////////////////////////////////////////////////////+//+// sdf computation+//++#define STBTT_min(a,b)  ((a) < (b) ? (a) : (b))+#define STBTT_max(a,b)  ((a) < (b) ? (b) : (a))++static int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2])+{+   float q0perp = q0[1]*ray[0] - q0[0]*ray[1];+   float q1perp = q1[1]*ray[0] - q1[0]*ray[1];+   float q2perp = q2[1]*ray[0] - q2[0]*ray[1];+   float roperp = orig[1]*ray[0] - orig[0]*ray[1];++   float a = q0perp - 2*q1perp + q2perp;+   float b = q1perp - q0perp;+   float c = q0perp - roperp;++   float s0 = 0., s1 = 0.;+   int num_s = 0;++   if (a != 0.0) {+      float discr = b*b - a*c;+      if (discr > 0.0) {+         float rcpna = -1 / a;+         float d = (float) STBTT_sqrt(discr);+         s0 = (b+d) * rcpna;+         s1 = (b-d) * rcpna;+         if (s0 >= 0.0 && s0 <= 1.0)+            num_s = 1;+         if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) {+            if (num_s == 0) s0 = s1;+            ++num_s;+         }+      }+   } else {+      // 2*b*s + c = 0+      // s = -c / (2*b)+      s0 = c / (-2 * b);+      if (s0 >= 0.0 && s0 <= 1.0)+         num_s = 1;+   }++   if (num_s == 0)+      return 0;+   else {+      float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]);+      float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2;++      float q0d =   q0[0]*rayn_x +   q0[1]*rayn_y;+      float q1d =   q1[0]*rayn_x +   q1[1]*rayn_y;+      float q2d =   q2[0]*rayn_x +   q2[1]*rayn_y;+      float rod = orig[0]*rayn_x + orig[1]*rayn_y;++      float q10d = q1d - q0d;+      float q20d = q2d - q0d;+      float q0rd = q0d - rod;++      hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d;+      hits[0][1] = a*s0+b;++      if (num_s > 1) {+         hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d;+         hits[1][1] = a*s1+b;+         return 2;+      } else {+         return 1;+      }+   }+}++static int equal(float *a, float *b)+{+   return (a[0] == b[0] && a[1] == b[1]);+}++static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts)+{+   int i;+   float orig[2], ray[2] = { 1, 0 };+   float y_frac;+   int winding = 0;++   orig[0] = x;+   orig[1] = y;++   // make sure y never passes through a vertex of the shape+   y_frac = (float) STBTT_fmod(y, 1.0f);+   if (y_frac < 0.01f)+      y += 0.01f;+   else if (y_frac > 0.99f)+      y -= 0.01f;+   orig[1] = y;++   // test a ray from (-infinity,y) to (x,y)+   for (i=0; i < nverts; ++i) {+      if (verts[i].type == STBTT_vline) {+         int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y;+         int x1 = (int) verts[i  ].x, y1 = (int) verts[i  ].y;+         if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {+            float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;+            if (x_inter < x)  +               winding += (y0 < y1) ? 1 : -1;+         }+      }+      if (verts[i].type == STBTT_vcurve) {+         int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ;+         int x1 = (int) verts[i  ].cx, y1 = (int) verts[i  ].cy;+         int x2 = (int) verts[i  ].x , y2 = (int) verts[i  ].y ;+         int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2));+         int by = STBTT_max(y0,STBTT_max(y1,y2));+         if (y > ay && y < by && x > ax) {+            float q0[2],q1[2],q2[2];+            float hits[2][2];+            q0[0] = (float)x0;+            q0[1] = (float)y0;+            q1[0] = (float)x1;+            q1[1] = (float)y1;+            q2[0] = (float)x2;+            q2[1] = (float)y2;+            if (equal(q0,q1) || equal(q1,q2)) {+               x0 = (int)verts[i-1].x;+               y0 = (int)verts[i-1].y;+               x1 = (int)verts[i  ].x;+               y1 = (int)verts[i  ].y;+               if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {+                  float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;+                  if (x_inter < x)  +                     winding += (y0 < y1) ? 1 : -1;+               }+            } else {+               int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits);+               if (num_hits >= 1)+                  if (hits[0][0] < 0)+                     winding += (hits[0][1] < 0 ? -1 : 1);+               if (num_hits >= 2)+                  if (hits[1][0] < 0)+                     winding += (hits[1][1] < 0 ? -1 : 1);+            }+         } +      }+   }+   return winding;+}++static float stbtt__cuberoot( float x )+{+   if (x<0)+      return -(float) STBTT_pow(-x,1.0f/3.0f);+   else+      return  (float) STBTT_pow( x,1.0f/3.0f);+}++// x^3 + c*x^2 + b*x + a = 0+static int stbtt__solve_cubic(float a, float b, float c, float* r)+{+	float s = -a / 3;+	float p = b - a*a / 3;+	float q = a * (2*a*a - 9*b) / 27 + c;+   float p3 = p*p*p;+	float d = q*q + 4*p3 / 27;+	if (d >= 0) {+		float z = (float) STBTT_sqrt(d);+		float u = (-q + z) / 2;+		float v = (-q - z) / 2;+		u = stbtt__cuberoot(u);+		v = stbtt__cuberoot(v);+		r[0] = s + u + v;+		return 1;+	} else {+	   float u = (float) STBTT_sqrt(-p/3);+	   float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative+	   float m = (float) STBTT_cos(v);+      float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f;+	   r[0] = s + u * 2 * m;+	   r[1] = s - u * (m + n);+	   r[2] = s - u * (m - n);++      //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f);  // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe?+      //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f);+      //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f);+   	return 3;+   }+}++STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)+{+   float scale_x = scale, scale_y = scale;+   int ix0,iy0,ix1,iy1;+   int w,h;+   unsigned char *data;++   // if one scale is 0, use same scale for both+   if (scale_x == 0) scale_x = scale_y;+   if (scale_y == 0) {+      if (scale_x == 0) return NULL;  // if both scales are 0, return NULL+      scale_y = scale_x;+   }++   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1);++   // if empty, return NULL+   if (ix0 == ix1 || iy0 == iy1)+      return NULL;++   ix0 -= padding;+   iy0 -= padding;+   ix1 += padding;+   iy1 += padding;++   w = (ix1 - ix0);+   h = (iy1 - iy0);++   if (width ) *width  = w;+   if (height) *height = h;+   if (xoff  ) *xoff   = ix0;+   if (yoff  ) *yoff   = iy0;++   // invert for y-downwards bitmaps+   scale_y = -scale_y;+      +   {+      int x,y,i,j;+      float *precompute;+      stbtt_vertex *verts;+      int num_verts = stbtt_GetGlyphShape(info, glyph, &verts);+      data = (unsigned char *) STBTT_malloc(w * h, info->userdata);+      precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata);++      for (i=0,j=num_verts-1; i < num_verts; j=i++) {+         if (verts[i].type == STBTT_vline) {+            float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;+            float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y;+            float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0));+            precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist;+         } else if (verts[i].type == STBTT_vcurve) {+            float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y;+            float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y;+            float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y;+            float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;+            float len2 = bx*bx + by*by;+            if (len2 != 0.0f)+               precompute[i] = 1.0f / (bx*bx + by*by);+            else+               precompute[i] = 0.0f;+         } else+            precompute[i] = 0.0f;+      }++      for (y=iy0; y < iy1; ++y) {+         for (x=ix0; x < ix1; ++x) {+            float val;+            float min_dist = 999999.0f;+            float sx = (float) x + 0.5f;+            float sy = (float) y + 0.5f;+            float x_gspace = (sx / scale_x);+            float y_gspace = (sy / scale_y);++            int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path++            for (i=0; i < num_verts; ++i) {+               float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;++               // check against every point here rather than inside line/curve primitives -- @TODO: wrong if multiple 'moves' in a row produce a garbage point, and given culling, probably more efficient to do within line/curve+               float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);+               if (dist2 < min_dist*min_dist)+                  min_dist = (float) STBTT_sqrt(dist2);++               if (verts[i].type == STBTT_vline) {+                  float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;++                  // coarse culling against bbox+                  //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist &&+                  //    sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist)+                  float dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];+                  STBTT_assert(i != 0);+                  if (dist < min_dist) {+                     // check position along line+                     // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0)+                     // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy)+                     float dx = x1-x0, dy = y1-y0;+                     float px = x0-sx, py = y0-sy;+                     // minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy+                     // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve+                     float t = -(px*dx + py*dy) / (dx*dx + dy*dy);+                     if (t >= 0.0f && t <= 1.0f)+                        min_dist = dist;+                  }+               } else if (verts[i].type == STBTT_vcurve) {+                  float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y;+                  float x1 = verts[i  ].cx*scale_x, y1 = verts[i  ].cy*scale_y;+                  float box_x0 = STBTT_min(STBTT_min(x0,x1),x2);+                  float box_y0 = STBTT_min(STBTT_min(y0,y1),y2);+                  float box_x1 = STBTT_max(STBTT_max(x0,x1),x2);+                  float box_y1 = STBTT_max(STBTT_max(y0,y1),y2);+                  // coarse culling against bbox to avoid computing cubic unnecessarily+                  if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) {+                     int num=0;+                     float ax = x1-x0, ay = y1-y0;+                     float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;+                     float mx = x0 - sx, my = y0 - sy;+                     float res[3],px,py,t,it;+                     float a_inv = precompute[i];+                     if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula+                        float a = 3*(ax*bx + ay*by);+                        float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by);+                        float c = mx*ax+my*ay;+                        if (a == 0.0) { // if a is 0, it's linear+                           if (b != 0.0) {+                              res[num++] = -c/b;+                           }+                        } else {+                           float discriminant = b*b - 4*a*c;+                           if (discriminant < 0)+                              num = 0;+                           else {+                              float root = (float) STBTT_sqrt(discriminant);+                              res[0] = (-b - root)/(2*a);+                              res[1] = (-b + root)/(2*a);+                              num = 2; // don't bother distinguishing 1-solution case, as code below will still work+                           }+                        }+                     } else {+                        float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point+                        float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv;+                        float d = (mx*ax+my*ay) * a_inv;+                        num = stbtt__solve_cubic(b, c, d, res);+                     }+                     if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {+                        t = res[0], it = 1.0f - t;+                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;+                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;+                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);+                        if (dist2 < min_dist * min_dist)+                           min_dist = (float) STBTT_sqrt(dist2);+                     }+                     if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) {+                        t = res[1], it = 1.0f - t;+                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;+                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;+                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);+                        if (dist2 < min_dist * min_dist)+                           min_dist = (float) STBTT_sqrt(dist2);+                     }+                     if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) {+                        t = res[2], it = 1.0f - t;+                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;+                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;+                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);+                        if (dist2 < min_dist * min_dist)+                           min_dist = (float) STBTT_sqrt(dist2);+                     }+                  }+               }+            }+            if (winding == 0)+               min_dist = -min_dist;  // if outside the shape, value is negative+            val = onedge_value + pixel_dist_scale * min_dist;+            if (val < 0)+               val = 0;+            else if (val > 255)+               val = 255;+            data[(y-iy0)*w+(x-ix0)] = (unsigned char) val;+         }+      }+      STBTT_free(precompute, info->userdata);+      STBTT_free(verts, info->userdata);+   }+   return data;+}   ++STBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)+{+   return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff);+}++STBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata)+{+   STBTT_free(bitmap, userdata);+}++//////////////////////////////////////////////////////////////////////////////+//+// font name matching -- recommended not to use this+//++// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string+static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) +{+   stbtt_int32 i=0;++   // convert utf16 to utf8 and compare the results while converting+   while (len2) {+      stbtt_uint16 ch = s2[0]*256 + s2[1];+      if (ch < 0x80) {+         if (i >= len1) return -1;+         if (s1[i++] != ch) return -1;+      } else if (ch < 0x800) {+         if (i+1 >= len1) return -1;+         if (s1[i++] != 0xc0 + (ch >> 6)) return -1;+         if (s1[i++] != 0x80 + (ch & 0x3f)) return -1;+      } else if (ch >= 0xd800 && ch < 0xdc00) {+         stbtt_uint32 c;+         stbtt_uint16 ch2 = s2[2]*256 + s2[3];+         if (i+3 >= len1) return -1;+         c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000;+         if (s1[i++] != 0xf0 + (c >> 18)) return -1;+         if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1;+         if (s1[i++] != 0x80 + ((c >>  6) & 0x3f)) return -1;+         if (s1[i++] != 0x80 + ((c      ) & 0x3f)) return -1;+         s2 += 2; // plus another 2 below+         len2 -= 2;+      } else if (ch >= 0xdc00 && ch < 0xe000) {+         return -1;+      } else {+         if (i+2 >= len1) return -1;+         if (s1[i++] != 0xe0 + (ch >> 12)) return -1;+         if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1;+         if (s1[i++] != 0x80 + ((ch     ) & 0x3f)) return -1;+      }+      s2 += 2;+      len2 -= 2;+   }+   return i;+}++static int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2) +{+   return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2);+}++// returns results in whatever encoding you request... but note that 2-byte encodings+// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare+STBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID)+{+   stbtt_int32 i,count,stringOffset;+   stbtt_uint8 *fc = font->data;+   stbtt_uint32 offset = font->fontstart;+   stbtt_uint32 nm = stbtt__find_table(fc, offset, "name");+   if (!nm) return NULL;++   count = ttUSHORT(fc+nm+2);+   stringOffset = nm + ttUSHORT(fc+nm+4);+   for (i=0; i < count; ++i) {+      stbtt_uint32 loc = nm + 6 + 12 * i;+      if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2)+          && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) {+         *length = ttUSHORT(fc+loc+8);+         return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10));+      }+   }+   return NULL;+}++static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id)+{+   stbtt_int32 i;+   stbtt_int32 count = ttUSHORT(fc+nm+2);+   stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4);++   for (i=0; i < count; ++i) {+      stbtt_uint32 loc = nm + 6 + 12 * i;+      stbtt_int32 id = ttUSHORT(fc+loc+6);+      if (id == target_id) {+         // find the encoding+         stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4);++         // is this a Unicode encoding?+         if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) {+            stbtt_int32 slen = ttUSHORT(fc+loc+8);+            stbtt_int32 off = ttUSHORT(fc+loc+10);++            // check if there's a prefix match+            stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen);+            if (matchlen >= 0) {+               // check for target_id+1 immediately following, with same encoding & language+               if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) {+                  slen = ttUSHORT(fc+loc+12+8);+                  off = ttUSHORT(fc+loc+12+10);+                  if (slen == 0) {+                     if (matchlen == nlen)+                        return 1;+                  } else if (matchlen < nlen && name[matchlen] == ' ') {+                     ++matchlen;+                     if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen))+                        return 1;+                  }+               } else {+                  // if nothing immediately following+                  if (matchlen == nlen)+                     return 1;+               }+            }+         }++         // @TODO handle other encodings+      }+   }+   return 0;+}++static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags)+{+   stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name);+   stbtt_uint32 nm,hd;+   if (!stbtt__isfont(fc+offset)) return 0;++   // check italics/bold/underline flags in macStyle...+   if (flags) {+      hd = stbtt__find_table(fc, offset, "head");+      if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0;+   }++   nm = stbtt__find_table(fc, offset, "name");+   if (!nm) return 0;++   if (flags) {+      // if we checked the macStyle flags, then just check the family and ignore the subfamily+      if (stbtt__matchpair(fc, nm, name, nlen, 16, -1))  return 1;+      if (stbtt__matchpair(fc, nm, name, nlen,  1, -1))  return 1;+      if (stbtt__matchpair(fc, nm, name, nlen,  3, -1))  return 1;+   } else {+      if (stbtt__matchpair(fc, nm, name, nlen, 16, 17))  return 1;+      if (stbtt__matchpair(fc, nm, name, nlen,  1,  2))  return 1;+      if (stbtt__matchpair(fc, nm, name, nlen,  3, -1))  return 1;+   }++   return 0;+}++static int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags)+{+   stbtt_int32 i;+   for (i=0;;++i) {+      stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i);+      if (off < 0) return off;+      if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags))+         return off;+   }+}++#if defined(__GNUC__) || defined(__clang__)+#pragma GCC diagnostic push+#pragma GCC diagnostic ignored "-Wcast-qual"+#endif++STBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,+                                float pixel_height, unsigned char *pixels, int pw, int ph,+                                int first_char, int num_chars, stbtt_bakedchar *chardata)+{+   return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata);+}++STBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index)+{+   return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index);   +}++STBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data)+{+   return stbtt_GetNumberOfFonts_internal((unsigned char *) data);+}++STBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset)+{+   return stbtt_InitFont_internal(info, (unsigned char *) data, offset);+}++STBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags)+{+   return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags);+}++STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2)+{+   return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2);+}++#if defined(__GNUC__) || defined(__clang__)+#pragma GCC diagnostic pop+#endif++#endif // STB_TRUETYPE_IMPLEMENTATION+++// FULL VERSION HISTORY+//+//   1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod+//   1.18 (2018-01-29) add missing function+//   1.17 (2017-07-23) make more arguments const; doc fix+//   1.16 (2017-07-12) SDF support+//   1.15 (2017-03-03) make more arguments const+//   1.14 (2017-01-16) num-fonts-in-TTC function+//   1.13 (2017-01-02) support OpenType fonts, certain Apple fonts+//   1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual+//   1.11 (2016-04-02) fix unused-variable warning+//   1.10 (2016-04-02) allow user-defined fabs() replacement+//                     fix memory leak if fontsize=0.0+//                     fix warning from duplicate typedef+//   1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges+//   1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges+//   1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;+//                     allow PackFontRanges to pack and render in separate phases;+//                     fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);+//                     fixed an assert() bug in the new rasterizer+//                     replace assert() with STBTT_assert() in new rasterizer+//   1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine)+//                     also more precise AA rasterizer, except if shapes overlap+//                     remove need for STBTT_sort+//   1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC+//   1.04 (2015-04-15) typo in example+//   1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes+//   1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C+++//   1.01 (2014-12-08) fix subpixel position when oversampling to exactly match+//                        non-oversampled; STBTT_POINT_SIZE for packed case only+//   1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling+//   0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg)+//   0.9  (2014-08-07) support certain mac/iOS fonts without an MS platformID+//   0.8b (2014-07-07) fix a warning+//   0.8  (2014-05-25) fix a few more warnings+//   0.7  (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back+//   0.6c (2012-07-24) improve documentation+//   0.6b (2012-07-20) fix a few more warnings+//   0.6  (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels,+//                        stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty+//   0.5  (2011-12-09) bugfixes:+//                        subpixel glyph renderer computed wrong bounding box+//                        first vertex of shape can be off-curve (FreeSans)+//   0.4b (2011-12-03) fixed an error in the font baking example+//   0.4  (2011-12-01) kerning, subpixel rendering (tor)+//                    bugfixes for:+//                        codepoint-to-glyph conversion using table fmt=12+//                        codepoint-to-glyph conversion using table fmt=4+//                        stbtt_GetBakedQuad with non-square texture (Zer)+//                    updated Hello World! sample to use kerning and subpixel+//                    fixed some warnings+//   0.3  (2009-06-24) cmap fmt=12, compound shapes (MM)+//                    userdata, malloc-from-userdata, non-zero fill (stb)+//   0.2  (2009-03-11) Fix unsigned/signed char warnings+//   0.1  (2009-03-09) First public release+//++/*+------------------------------------------------------------------------------+This software is available under 2 licenses -- choose whichever you prefer.+------------------------------------------------------------------------------+ALTERNATIVE A - MIT License+Copyright (c) 2017 Sean Barrett+Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions:+The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.+------------------------------------------------------------------------------+ALTERNATIVE B - Public Domain (www.unlicense.org)+This is free and unencumbered software released into the public domain.+Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means.+In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law.+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.+------------------------------------------------------------------------------+*/
cbits/wrapper.c view
@@ -1,6 +1,18 @@ +#include <stdint.h> +/*+typedef uint8_t   stbtt_uint8;+typedef int8_t    stbtt_int8;+typedef uint16_t  stbtt_uint16;+typedef int16_t   stbtt_int16;+typedef uint32_t  stbtt_uint32;+typedef int32_t   stbtt_int32;+#define stbtt_override_uint8+*/+ #define STB_TRUETYPE_IMPLEMENTATION #include "stb_truetype.h" -+int sizeof_stbtt__buf()     { return sizeof(stbtt__buf);     }+int sizeof_stbtt_fontinfo() { return sizeof(stbtt_fontinfo); }
+ example/example.hs view
@@ -0,0 +1,96 @@++-- This small example programs renders a single character as ASCII art++module Main where++--------------------------------------------------------------------------------++import Control.Monad++import Data.Array.IArray+import Data.Word+import Text.Read++import System.Environment+import System.Exit++import Foreign.Ptr+import Foreign.Marshal++import Graphics.Rendering.TrueType.STB ++--------------------------------------------------------------------------------++defaultSize = 32  :: Int+defaultChar = 'A' :: Char++wordToChar :: Word8 -> Char+wordToChar w +  | w ==  0   = ' '+  | w <  50   = '.' +  | w < 100   = '+' +  | w < 150   = 'o' +  | w < 200   = '$'+  | otherwise = '@'++--------------------------------------------------------------------------------++myError :: String -> IO a+myError msg = do+  putStrLn msg+  exitWith ExitSuccess++printLetter :: FilePath -> Char -> Int -> IO ()+printLetter fpath ch height = do+  ttfPackage <- loadTTF fpath+  ofsList <- enumerateFonts ttfPackage+  ofs <- case ofsList of  +    []    -> myError "error: empty TrueType font"+    (o:_) -> return o+  font <- initFont ttfPackage ofs+  mbGlyph <- findGlyph font ch+  case mbGlyph of+    Nothing -> myError "the given character is not found in the font"+    Just glyph -> renderGlyph font glyph height++renderGlyph :: Font -> Glyph -> Int -> IO ()+renderGlyph font glyph height = do++  vmu <- getFontVerticalMetrics font+  let s = scaleForPixelHeight vmu (fromIntegral height)++  (bm,ofs) <- newGlyphBitmap font glyph (s,s) +  putStrLn $ "offset = " ++ show ofs+  arr <- bitmapArray bm+  let ((y1,x1),(y2,x2)) = bounds arr+  putStrLn ('+' : replicate (2*(x2-x1+1)) '-' ++ "+")+  forM_ [y1..y2] $ \y -> do+    putChar '|'+    forM_ [x1..x2] $ \x -> do+      let c = wordToChar $ arr!(y,x)+      putChar c+      putChar c+    putStrLn "|"+  putStrLn ('+' : replicate (2*(x2-x1+1)) '-' ++ "+")++--------------------------------------------------------------------------------++main = do+  args <- getArgs+  case args of +    [fname]         -> printLetter fname 'A'        defaultSize+    [fname,str]     -> printLetter fname (head str) defaultSize+    [fname,str,siz] -> case readMaybe siz of+      Just h  -> printLetter fname (head str) h+      Nothing -> printUsage+    _ -> printUsage++printUsage = do+  putStrLn "usage:\n"+  putStrLn "stb-truetype-example <font.ttf>"+  putStrLn "stb-truetype-example <font.ttf> <character>"+  putStrLn "stb-truetype-example <font.ttf> <character> <size>"++--------------------------------------------------------------------------------++
stb-truetype.cabal view
@@ -1,5 +1,5 @@ Name:                stb-truetype-Version:             0.1.2+Version:             0.1.4 Synopsis:            A wrapper around Sean Barrett's TrueType rasterizer library. Description:         A wrapper around Sean Barrett's TrueType rasterizer library. License:             PublicDomain@@ -9,34 +9,34 @@ Homepage:            http://code.haskell.org/~bkomuves/ Stability:           Experimental Category:            Graphics-Tested-With:         GHC == 6.10.1-Cabal-Version:       >= 1.2+Tested-With:         GHC == 8.0.2, GHC == 8.2.1+Cabal-Version:       >= 1.24 Build-Type:          Simple -extra-source-files:  cbits/stb_truetype.h+extra-source-files:  cbits/stb_truetype.h,+                     example/example.hs -Flag splitBase-  Description: Choose the new smaller, split-up base package.+source-repository head+  type:                darcs +  location:            http://moire.be/haskell/projects/stb-truetype/  Flag base4   Description: Base v4  Library-  if flag(splitBase)-    if flag(base4)-      Build-Depends:   base >= 4 && < 5, array, containers, bytestring-      cpp-options:     -DBASE_VERSION=4-    else-      Build-Depends:   base >= 3 && < 4, array, containers, bytestring-      cpp-options:     -DBASE_VERSION=3+  if flag(base4)+    Build-Depends:   base >= 4 && < 5 , array >= 0.4 , containers , bytestring+    cpp-options:     -DBASE_VERSION=4   else-    Build-Depends:   base >=2 && < 3-    cpp-options:     -DBASE_VERSION=2+    Build-Depends:   base >= 3 && < 4 , array >= 0.4 , containers , bytestring+    cpp-options:     -DBASE_VERSION=3        Exposed-Modules:     Graphics.Rendering.TrueType.STB    Hs-Source-Dirs:      .-  Extensions:          ForeignFunctionInterface, CPP++  Default-Language:    Haskell2010+  Default-Extensions:  CPP, BangPatterns, ForeignFunctionInterface    C-Sources:           cbits/wrapper.c    Include-Dirs:        cbits