aboutsummaryrefslogtreecommitdiff
path: root/dep/recastnavigation/recastnavigation.diff
diff options
context:
space:
mode:
Diffstat (limited to 'dep/recastnavigation/recastnavigation.diff')
-rw-r--r--dep/recastnavigation/recastnavigation.diff4066
1 files changed, 4066 insertions, 0 deletions
diff --git a/dep/recastnavigation/recastnavigation.diff b/dep/recastnavigation/recastnavigation.diff
new file mode 100644
index 00000000000..68e976c955e
--- /dev/null
+++ b/dep/recastnavigation/recastnavigation.diff
@@ -0,0 +1,4066 @@
+ Detour/Include/DetourNavMesh.h | 76 +-
+ Detour/Include/DetourNavMeshQuery.h | 0
+ Detour/Include/DetourNode.h | 0
+ Detour/Source/DetourCommon.cpp | 4 +-
+ Detour/Source/DetourNavMesh.cpp | 32 +-
+ Detour/Source/DetourNavMeshBuilder.cpp | 6 +-
+ Detour/Source/DetourNavMeshQuery.cpp | 9 +-
+ Detour/Source/DetourNode.cpp | 29 +-
+ DetourCrowd/Include/DetourObstacleAvoidance.h | 0
+ DetourCrowd/Source/DetourObstacleAvoidance.cpp | 6 +-
+ Recast/Include/Recast.h | 8 +-
+ Recast/Source/RecastContour.cpp | 0
+ Recast/Source/RecastLayers.cpp | 0
+ Recast/Source/RecastMesh.cpp | 0
+ Recast/Source/RecastMeshDetail.cpp | 0
+ Recast/Source/RecastRegion.cpp | 0
+ RecastDemo/Contrib/stb_truetype.h | 3612 ++++++++++++------------
+ RecastDemo/Include/NavMeshPruneTool.h | 0
+ 18 files changed, 1865 insertions(+), 1917 deletions(-)
+
+diff --git a/Detour/Include/DetourNavMesh.h b/Detour/Include/DetourNavMesh.h
+index 95a63e4..cdd473f 100644
+--- a/Detour/Include/DetourNavMesh.h
++++ b/Detour/Include/DetourNavMesh.h
+@@ -22,39 +22,35 @@
+ #include "DetourAlloc.h"
+ #include "DetourStatus.h"
+
+-// Undefine (or define in a build cofnig) the following line to use 64bit polyref.
+-// Generally not needed, useful for very large worlds.
+-// Note: tiles build using 32bit refs are not compatible with 64bit refs!
+-//#define DT_POLYREF64 1
+-
+-#ifdef DT_POLYREF64
+-// TODO: figure out a multiplatform version of uint64_t
+-// - maybe: https://code.google.com/p/msinttypes/
+-// - or: http://www.azillionmonkeys.com/qed/pstdint.h
++
++// Edited by TC
++#if defined(WIN32) && !defined(__MINGW32__)
++/// Do not rename back to uint64. Otherwise mac complains about typedef redefinition
++typedef unsigned __int64 uint64_d;
++#else
+ #include <stdint.h>
++#ifndef uint64_t
++#ifdef __linux__
++#include <linux/types.h>
++#endif
+ #endif
++/// Do not rename back to uint64. Otherwise mac complains about typedef redefinition
++typedef uint64_t uint64_d;
++#endif
+
+ // Note: If you want to use 64-bit refs, change the types of both dtPolyRef & dtTileRef.
+ // It is also recommended that you change dtHashRef() to a proper 64-bit hash.
+
++// Edited by TC
++// We cannot have over 31 bits for either tile nor poly
++// without changing polyCount to use 64bits too.
+ /// A handle to a polygon within a navigation mesh tile.
+ /// @ingroup detour
+-#ifdef DT_POLYREF64
+-static const unsigned int DT_SALT_BITS = 16;
+-static const unsigned int DT_TILE_BITS = 28;
+-static const unsigned int DT_POLY_BITS = 20;
+-typedef uint64_t dtPolyRef;
+-#else
+-typedef unsigned int dtPolyRef;
+-#endif
++typedef uint64_d dtPolyRef; // Edited by TC
+
+ /// A handle to a tile within a navigation mesh.
+ /// @ingroup detour
+-#ifdef DT_POLYREF64
+-typedef uint64_t dtTileRef;
+-#else
+-typedef unsigned int dtTileRef;
+-#endif
++typedef uint64_d dtTileRef; // Edited by TC
+
+ /// The maximum number of vertices per navigation polygon.
+ /// @ingroup detour
+@@ -94,6 +90,12 @@ static const unsigned int DT_OFFMESH_CON_BIDIR = 1;
+ /// @ingroup detour
+ static const int DT_MAX_AREAS = 64;
+
++static const int STATIC_SALT_BITS = 12;
++static const int STATIC_TILE_BITS = 21;
++static const int STATIC_POLY_BITS = 31;
++// we cannot have over 31 bits for either tile nor poly
++// without changing polyCount to use 64bits too.
++
+ /// Tile flags used for various functions and fields.
+ /// For an example, see dtNavMesh::addTile().
+ enum dtTileFlags
+@@ -492,11 +494,7 @@ public:
+ /// @param[in] ip The index of the polygon within the tile.
+ inline dtPolyRef encodePolyId(unsigned int salt, unsigned int it, unsigned int ip) const
+ {
+-#ifdef DT_POLYREF64
+- return ((dtPolyRef)salt << (DT_POLY_BITS+DT_TILE_BITS)) | ((dtPolyRef)it << DT_POLY_BITS) | (dtPolyRef)ip;
+-#else
+ return ((dtPolyRef)salt << (m_polyBits+m_tileBits)) | ((dtPolyRef)it << m_polyBits) | (dtPolyRef)ip;
+-#endif
+ }
+
+ /// Decodes a standard polygon reference.
+@@ -508,21 +506,12 @@ public:
+ /// @see #encodePolyId
+ inline void decodePolyId(dtPolyRef ref, unsigned int& salt, unsigned int& it, unsigned int& ip) const
+ {
+-#ifdef DT_POLYREF64
+- const dtPolyRef saltMask = ((dtPolyRef)1<<DT_SALT_BITS)-1;
+- const dtPolyRef tileMask = ((dtPolyRef)1<<DT_TILE_BITS)-1;
+- const dtPolyRef polyMask = ((dtPolyRef)1<<DT_POLY_BITS)-1;
+- salt = (unsigned int)((ref >> (DT_POLY_BITS+DT_TILE_BITS)) & saltMask);
+- it = (unsigned int)((ref >> DT_POLY_BITS) & tileMask);
+- ip = (unsigned int)(ref & polyMask);
+-#else
+ const dtPolyRef saltMask = ((dtPolyRef)1<<m_saltBits)-1;
+ const dtPolyRef tileMask = ((dtPolyRef)1<<m_tileBits)-1;
+ const dtPolyRef polyMask = ((dtPolyRef)1<<m_polyBits)-1;
+ salt = (unsigned int)((ref >> (m_polyBits+m_tileBits)) & saltMask);
+ it = (unsigned int)((ref >> m_polyBits) & tileMask);
+ ip = (unsigned int)(ref & polyMask);
+-#endif
+ }
+
+ /// Extracts a tile's salt value from the specified polygon reference.
+@@ -531,13 +520,8 @@ public:
+ /// @see #encodePolyId
+ inline unsigned int decodePolyIdSalt(dtPolyRef ref) const
+ {
+-#ifdef DT_POLYREF64
+- const dtPolyRef saltMask = ((dtPolyRef)1<<DT_SALT_BITS)-1;
+- return (unsigned int)((ref >> (DT_POLY_BITS+DT_TILE_BITS)) & saltMask);
+-#else
+ const dtPolyRef saltMask = ((dtPolyRef)1<<m_saltBits)-1;
+ return (unsigned int)((ref >> (m_polyBits+m_tileBits)) & saltMask);
+-#endif
+ }
+
+ /// Extracts the tile's index from the specified polygon reference.
+@@ -546,13 +530,8 @@ public:
+ /// @see #encodePolyId
+ inline unsigned int decodePolyIdTile(dtPolyRef ref) const
+ {
+-#ifdef DT_POLYREF64
+- const dtPolyRef tileMask = ((dtPolyRef)1<<DT_TILE_BITS)-1;
+- return (unsigned int)((ref >> DT_POLY_BITS) & tileMask);
+-#else
+ const dtPolyRef tileMask = ((dtPolyRef)1<<m_tileBits)-1;
+ return (unsigned int)((ref >> m_polyBits) & tileMask);
+-#endif
+ }
+
+ /// Extracts the polygon's index (within its tile) from the specified polygon reference.
+@@ -561,13 +540,8 @@ public:
+ /// @see #encodePolyId
+ inline unsigned int decodePolyIdPoly(dtPolyRef ref) const
+ {
+-#ifdef DT_POLYREF64
+- const dtPolyRef polyMask = ((dtPolyRef)1<<DT_POLY_BITS)-1;
+- return (unsigned int)(ref & polyMask);
+-#else
+ const dtPolyRef polyMask = ((dtPolyRef)1<<m_polyBits)-1;
+ return (unsigned int)(ref & polyMask);
+-#endif
+ }
+
+ /// @}
+@@ -626,11 +600,9 @@ private:
+ dtMeshTile* m_nextFree; ///< Freelist of tiles.
+ dtMeshTile* m_tiles; ///< List of tiles.
+
+-#ifndef DT_POLYREF64
+ unsigned int m_saltBits; ///< Number of salt bits in the tile ID.
+ unsigned int m_tileBits; ///< Number of tile bits in the tile ID.
+ unsigned int m_polyBits; ///< Number of poly bits in the tile ID.
+-#endif
+ };
+
+ /// Allocates a navigation mesh object using the Detour allocator.
+diff --git a/Detour/Source/DetourCommon.cpp b/Detour/Source/DetourCommon.cpp
+index a98d8c8..b5700f5 100644
+--- a/Detour/Source/DetourCommon.cpp
++++ b/Detour/Source/DetourCommon.cpp
+@@ -16,14 +16,14 @@
+ // 3. This notice may not be removed or altered from any source distribution.
+ //
+
++#include <math.h>
+ #include "DetourCommon.h"
+-#include "DetourMath.h"
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+
+ float dtSqrt(float x)
+ {
+- return dtMathSqrtf(x);
++ return sqrtf(x);
+ }
+
+ void dtClosestPtPointTriangle(float* closest, const float* p,
+diff --git a/Detour/Source/DetourNavMesh.cpp b/Detour/Source/DetourNavMesh.cpp
+index 9d627be..5174050 100644
+--- a/Detour/Source/DetourNavMesh.cpp
++++ b/Detour/Source/DetourNavMesh.cpp
+@@ -16,13 +16,13 @@
+ // 3. This notice may not be removed or altered from any source distribution.
+ //
+
++#include <math.h>
+ #include <float.h>
+ #include <string.h>
+ #include <stdio.h>
+ #include "DetourNavMesh.h"
+ #include "DetourNode.h"
+ #include "DetourCommon.h"
+-#include "DetourMath.h"
+ #include "DetourAlloc.h"
+ #include "DetourAssert.h"
+ #include <new>
+@@ -193,13 +193,11 @@ dtNavMesh::dtNavMesh() :
+ m_tileLutMask(0),
+ m_posLookup(0),
+ m_nextFree(0),
+- m_tiles(0)
++ m_tiles(0),
++ m_saltBits(0),
++ m_tileBits(0),
++ m_polyBits(0)
+ {
+-#ifndef DT_POLYREF64
+- m_saltBits = 0;
+- m_tileBits = 0;
+- m_polyBits = 0;
+-#endif
+ memset(&m_params, 0, sizeof(dtNavMeshParams));
+ m_orig[0] = 0;
+ m_orig[1] = 0;
+@@ -250,17 +248,11 @@ dtStatus dtNavMesh::init(const dtNavMeshParams* params)
+ m_nextFree = &m_tiles[i];
+ }
+
+- // Init ID generator values.
+-#ifndef DT_POLYREF64
+- m_tileBits = dtIlog2(dtNextPow2((unsigned int)params->maxTiles));
+- m_polyBits = dtIlog2(dtNextPow2((unsigned int)params->maxPolys));
+- // Only allow 31 salt bits, since the salt mask is calculated using 32bit uint and it will overflow.
+- m_saltBits = dtMin((unsigned int)31, 32 - m_tileBits - m_polyBits);
+-
+- if (m_saltBits < 10)
+- return DT_FAILURE | DT_INVALID_PARAM;
+-#endif
+-
++ // Edited by TC
++ m_tileBits = STATIC_TILE_BITS;
++ m_polyBits = STATIC_POLY_BITS;
++ m_saltBits = STATIC_SALT_BITS;
++
+ return DT_SUCCESS;
+ }
+
+@@ -1242,11 +1234,7 @@ dtStatus dtNavMesh::removeTile(dtTileRef ref, unsigned char** data, int* dataSiz
+ tile->offMeshCons = 0;
+
+ // Update salt, salt should never be zero.
+-#ifdef DT_POLYREF64
+- tile->salt = (tile->salt+1) & ((1<<DT_SALT_BITS)-1);
+-#else
+ tile->salt = (tile->salt+1) & ((1<<m_saltBits)-1);
+-#endif
+ if (tile->salt == 0)
+ tile->salt++;
+
+diff --git a/Detour/Source/DetourNavMeshBuilder.cpp b/Detour/Source/DetourNavMeshBuilder.cpp
+index 1bf271b..9d8471b 100644
+--- a/Detour/Source/DetourNavMeshBuilder.cpp
++++ b/Detour/Source/DetourNavMeshBuilder.cpp
+@@ -16,13 +16,13 @@
+ // 3. This notice may not be removed or altered from any source distribution.
+ //
+
++#include <math.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <float.h>
+ #include "DetourNavMesh.h"
+ #include "DetourCommon.h"
+-#include "DetourMath.h"
+ #include "DetourNavMeshBuilder.h"
+ #include "DetourAlloc.h"
+ #include "DetourAssert.h"
+@@ -202,8 +202,8 @@ static int createBVTree(const unsigned short* verts, const int /*nverts*/,
+ if (z > it.bmax[2]) it.bmax[2] = z;
+ }
+ // Remap y
+- it.bmin[1] = (unsigned short)dtMathFloorf((float)it.bmin[1]*ch/cs);
+- it.bmax[1] = (unsigned short)dtMathCeilf((float)it.bmax[1]*ch/cs);
++ it.bmin[1] = (unsigned short)floorf((float)it.bmin[1]*ch/cs);
++ it.bmax[1] = (unsigned short)ceilf((float)it.bmax[1]*ch/cs);
+ }
+
+ int curNode = 0;
+diff --git a/Detour/Source/DetourNavMeshQuery.cpp b/Detour/Source/DetourNavMeshQuery.cpp
+index 2e30464..f1709df 100644
+--- a/Detour/Source/DetourNavMeshQuery.cpp
++++ b/Detour/Source/DetourNavMeshQuery.cpp
+@@ -16,13 +16,13 @@
+ // 3. This notice may not be removed or altered from any source distribution.
+ //
+
++#include <math.h>
+ #include <float.h>
+ #include <string.h>
+ #include "DetourNavMeshQuery.h"
+ #include "DetourNavMesh.h"
+ #include "DetourNode.h"
+ #include "DetourCommon.h"
+-#include "DetourMath.h"
+ #include "DetourAlloc.h"
+ #include "DetourAssert.h"
+ #include <new>
+@@ -99,8 +99,9 @@ inline float dtQueryFilter::getCost(const float* pa, const float* pb,
+ return dtVdist(pa, pb) * m_areaCost[curPoly->getArea()];
+ }
+ #endif
+-
+-static const float H_SCALE = 0.999f; // Search heuristic scale.
++
++// Edited by TC
++static const float H_SCALE = 2.0f; // Search heuristic scale.
+
+
+ dtNavMeshQuery* dtAllocNavMeshQuery()
+@@ -3305,7 +3306,7 @@ dtStatus dtNavMeshQuery::findDistanceToWall(dtPolyRef startRef, const float* cen
+ dtVsub(hitNormal, centerPos, hitPos);
+ dtVnormalize(hitNormal);
+
+- *hitDist = dtMathSqrtf(radiusSqr);
++ *hitDist = sqrtf(radiusSqr);
+
+ return status;
+ }
+diff --git a/Detour/Source/DetourNode.cpp b/Detour/Source/DetourNode.cpp
+index 57cb206..4c8215e 100644
+--- a/Detour/Source/DetourNode.cpp
++++ b/Detour/Source/DetourNode.cpp
+@@ -22,30 +22,17 @@
+ #include "DetourCommon.h"
+ #include <string.h>
+
+-#ifdef DT_POLYREF64
+-// From Thomas Wang, https://gist.github.com/badboy/6267743
+ inline unsigned int dtHashRef(dtPolyRef a)
+ {
+- a = (~a) + (a << 18); // a = (a << 18) - a - 1;
+- a = a ^ (a >> 31);
+- a = a * 21; // a = (a + (a << 2)) + (a << 4);
+- a = a ^ (a >> 11);
+- a = a + (a << 6);
+- a = a ^ (a >> 22);
+- return (unsigned int)a;
++ // Edited by TC
++ a = (~a) + (a << 18);
++ a = a ^ (a >> 31);
++ a = a * 21;
++ a = a ^ (a >> 11);
++ a = a + (a << 6);
++ a = a ^ (a >> 22);
++ return (unsigned int)a;
+ }
+-#else
+-inline unsigned int dtHashRef(dtPolyRef a)
+-{
+- a += ~(a<<15);
+- a ^= (a>>10);
+- a += (a<<3);
+- a ^= (a>>6);
+- a += ~(a<<11);
+- a ^= (a>>16);
+- return (unsigned int)a;
+-}
+-#endif
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+ dtNodePool::dtNodePool(int maxNodes, int hashSize) :
+diff --git a/DetourCrowd/Source/DetourObstacleAvoidance.cpp b/DetourCrowd/Source/DetourObstacleAvoidance.cpp
+index 0fad9ef..d3f90b7 100644
+--- a/DetourCrowd/Source/DetourObstacleAvoidance.cpp
++++ b/DetourCrowd/Source/DetourObstacleAvoidance.cpp
+@@ -18,10 +18,10 @@
+
+ #include "DetourObstacleAvoidance.h"
+ #include "DetourCommon.h"
+-#include "DetourMath.h"
+ #include "DetourAlloc.h"
+ #include "DetourAssert.h"
+ #include <string.h>
++#include <math.h>
+ #include <float.h>
+ #include <new>
+
+@@ -58,7 +58,7 @@ static int isectRaySeg(const float* ap, const float* u,
+ dtVsub(v,bq,bp);
+ dtVsub(w,ap,bp);
+ float d = dtVperp2D(u,v);
+- if (dtMathFabs(d) < 1e-6f) return 0;
++ if (fabsf(d) < 1e-6f) return 0;
+ d = 1.0f/d;
+ t = dtVperp2D(v,w) * d;
+ if (t < 0 || t > 1) return 0;
+@@ -482,7 +482,7 @@ int dtObstacleAvoidanceQuery::sampleVelocityAdaptive(const float* pos, const flo
+ const int nd = dtClamp(ndivs, 1, DT_MAX_PATTERN_DIVS);
+ const int nr = dtClamp(nrings, 1, DT_MAX_PATTERN_RINGS);
+ const float da = (1.0f/nd) * DT_PI*2;
+- const float dang = dtMathAtan2f(dvel[2], dvel[0]);
++ const float dang = atan2f(dvel[2], dvel[0]);
+
+ // Always add sample at zero
+ pat[npat*2+0] = 0;
+diff --git a/Recast/Include/Recast.h b/Recast/Include/Recast.h
+index 336837e..3f4ae96 100644
+--- a/Recast/Include/Recast.h
++++ b/Recast/Include/Recast.h
+@@ -243,7 +243,7 @@ struct rcConfig
+ };
+
+ /// Defines the number of bits allocated to rcSpan::smin and rcSpan::smax.
+-static const int RC_SPAN_HEIGHT_BITS = 13;
++static const int RC_SPAN_HEIGHT_BITS = 16; // EDITED BY TC
+ /// Defines the maximum value for rcSpan::smin and rcSpan::smax.
+ static const int RC_SPAN_MAX_HEIGHT = (1<<RC_SPAN_HEIGHT_BITS)-1;
+
+@@ -255,9 +255,9 @@ static const int RC_SPANS_PER_POOL = 2048;
+ /// @see rcHeightfield
+ struct rcSpan
+ {
+- unsigned int smin : 13; ///< The lower limit of the span. [Limit: < #smax]
+- unsigned int smax : 13; ///< The upper limit of the span. [Limit: <= #RC_SPAN_MAX_HEIGHT]
+- unsigned int area : 6; ///< The area id assigned to the span.
++ unsigned int smin : 16; ///< The lower limit of the span. [Limit: < #smax]
++ unsigned int smax : 16; ///< The upper limit of the span. [Limit: <= #RC_SPAN_MAX_HEIGHT]
++ unsigned char area; ///< The area id assigned to the span.
+ rcSpan* next; ///< The next span higher up in column.
+ };
+
+diff --git a/RecastDemo/Contrib/stb_truetype.h b/RecastDemo/Contrib/stb_truetype.h
+index fd72578..92dc8c2 100644
+--- a/RecastDemo/Contrib/stb_truetype.h
++++ b/RecastDemo/Contrib/stb_truetype.h
+@@ -1,1806 +1,1806 @@
+-// 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
+- #include <malloc.h>
+- #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, 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;
+-}
+-
+-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;
+- 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 - 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
++ #include <malloc.h>
++ #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, 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;
++}
++
++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;
++ 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