diff options
Diffstat (limited to 'dep/recastnavigation/recastnavigation.diff')
-rw-r--r-- | dep/recastnavigation/recastnavigation.diff | 4066 |
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 |