mirror of
https://github.com/buserror/mii_emu.git
synced 2024-12-11 06:50:29 +00:00
5650323d05
Also fixes a crashing bug in cg.c, and various other bits.
663 lines
18 KiB
C
663 lines
18 KiB
C
/*
|
|
* stb_ttc.h
|
|
*
|
|
* Copyright (C) 2020 Michel Pollet <buserror@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#ifndef STB_TTC_H_
|
|
#define STB_TTC_H_
|
|
|
|
#include "stb_truetype.h"
|
|
|
|
#define STB_TTC_PACKED __attribute__((packed))
|
|
/* Number of bins in the hash table(s) */
|
|
#define STB_TTC_BINCOUNT 16
|
|
/* Number of structures we prealocate when resizing arrays */
|
|
#define STB_TTC_PAGESIZE 16
|
|
|
|
/*
|
|
* This is used in the hash table mapping the glyph/scale pair to the
|
|
* primary array of cached glyphs.
|
|
*/
|
|
typedef struct stb_ttc_index {
|
|
unsigned int intscale, glyph, index;
|
|
} STB_TTC_PACKED stb_ttc_index;
|
|
|
|
/*
|
|
* This is used by MeasureText. Returns the number os glyphs in the string,
|
|
* the ascent and descent /of that text/ and the bounding box of that text.
|
|
* Note that x0 can be negative, if the first character is for example, a 'j'
|
|
*/
|
|
typedef struct stb_ttc_measure {
|
|
short glyph_count;
|
|
short ascent, descent;
|
|
short x0,y0,x1,y1;
|
|
} STB_TTC_PACKED stb_ttc_measure;
|
|
|
|
/*
|
|
* A glyph info for a certain scale. You can have the same glyph at multiple
|
|
* scales in one cache.
|
|
*/
|
|
typedef struct stb_ttc_g {
|
|
unsigned int index; // index in global table
|
|
unsigned int intscale; // for comparison purpose
|
|
float scale;
|
|
unsigned int glyph;
|
|
int advance, lsb;
|
|
short x0,y0,x1,y1;
|
|
// position in the pixel cache, or 0xffff if not yet cached.
|
|
unsigned short p_x, p_y;
|
|
} STB_TTC_PACKED stb_ttc_g;
|
|
|
|
/*
|
|
* Used to cache the codepoints to glyphs map in a hash table
|
|
*/
|
|
typedef struct stb_ttc_cp_gl {
|
|
unsigned int cp;
|
|
unsigned int glyph;
|
|
} STB_TTC_PACKED stb_ttc_cp_gl;
|
|
|
|
/*
|
|
* Used to cache the kerning between cp1 and cp2 in a hash
|
|
*/
|
|
typedef struct stb_ttc_cp_kern {
|
|
unsigned int hash;
|
|
unsigned int cp1, cp2;
|
|
int kern;
|
|
} STB_TTC_PACKED stb_ttc_cp_kern;
|
|
|
|
// to remap codepoint->glyph without calling back into stb
|
|
struct _stb_ttc_cp_bin {
|
|
unsigned int cp_count;
|
|
stb_ttc_cp_gl * cp_gl;
|
|
};
|
|
// to remap codepoint pairs to associated kerning
|
|
struct _stb_ttc_kn_bin {
|
|
unsigned int kn_count;
|
|
stb_ttc_cp_kern * cp_kn;
|
|
};
|
|
// for glyph -> position in the glyph array
|
|
struct _stb_ttc_g_bin {
|
|
unsigned int i_count;
|
|
stb_ttc_index * index;
|
|
};
|
|
|
|
/*
|
|
* Main STB TrueType Cache structure.
|
|
*/
|
|
typedef struct stb_ttc_info {
|
|
stbtt_fontinfo font;
|
|
unsigned int font_size;
|
|
unsigned font_mmap: 1; // is font from a file
|
|
int ascent, descent;
|
|
// hash to remap codepoint->glyph without calling back into stb
|
|
struct _stb_ttc_cp_bin cp_bin[STB_TTC_BINCOUNT];
|
|
// hash to remap codepoint pairs to associated kerning
|
|
struct _stb_ttc_kn_bin kn_bin[STB_TTC_BINCOUNT];
|
|
// hash that for glyph -> position in the glyph array
|
|
struct _stb_ttc_g_bin g_bin[STB_TTC_BINCOUNT];
|
|
// glyph array, contains glyph dimensions, and x,y of pixel in cache
|
|
unsigned int g_count;
|
|
stb_ttc_g * glyph;
|
|
// pixels cache for glyphs
|
|
unsigned int p_stride;
|
|
unsigned int p_height; // current total height
|
|
unsigned int p_line_height; // current glyph line height
|
|
unsigned int p_line_x, p_line_y; // current x,y position in pixels
|
|
unsigned char * pixels;
|
|
} stb_ttc_info;
|
|
|
|
|
|
#ifdef STBTTC_STATIC
|
|
#define STBTTC_DEF static
|
|
#else
|
|
#define STBTTC_DEF extern
|
|
#endif
|
|
|
|
/*
|
|
* Preload a range of codepoints into the glyph cache. This doesn't add the
|
|
* pixels, it just load the glyph measurement, advance, lsb into the cache
|
|
*/
|
|
STBTTC_DEF int
|
|
stb_ttc_CacheCodepointRange(
|
|
struct stb_ttc_info * ttc,
|
|
unsigned int cp,
|
|
unsigned int count,
|
|
float scale );
|
|
/*
|
|
* This walks the cache for glyphs that haven't been pre-rendered and
|
|
* render them in the cache. Also, it attempts to sort the glyphs by height
|
|
* into the cache to save a little bit of memory
|
|
* Note: This call is optional, the glyph renderer will populate the pixel
|
|
* cache lazily on the fly.
|
|
*/
|
|
STBTTC_DEF int
|
|
stb_ttc_RenderAllCachedGlyphs(
|
|
struct stb_ttc_info * ttc );
|
|
|
|
STBTTC_DEF int
|
|
stb_ttc_MeasureText(
|
|
struct stb_ttc_info * ttc,
|
|
float scale,
|
|
const char * text,
|
|
stb_ttc_measure *out);
|
|
|
|
STBTTC_DEF int
|
|
stb_ttc_DrawText(
|
|
struct stb_ttc_info * ttc,
|
|
float scale,
|
|
const char * text,
|
|
unsigned int dx,
|
|
unsigned int base_dy,
|
|
unsigned char * pixels,
|
|
unsigned int p_w,
|
|
unsigned int p_h,
|
|
unsigned int p_stride);
|
|
// load a font from a file
|
|
STBTTC_DEF int
|
|
stb_ttc_MapFont(
|
|
struct stb_ttc_info * ttc,
|
|
const char * font_file);
|
|
// load a font from memory
|
|
STBTTC_DEF int
|
|
stb_ttc_LoadFont(
|
|
struct stb_ttc_info * ttc,
|
|
const void * font_data,
|
|
unsigned int font_size);
|
|
STBTTC_DEF void
|
|
stb_ttc_Free(
|
|
struct stb_ttc_info * ttc);
|
|
|
|
#ifdef STB_TTC_IMPLEMENTATION
|
|
/*
|
|
* return font glyph index from codepoint, cache the result if it wasn't.
|
|
*/
|
|
static int
|
|
stb_ttc__CodepointGetGlyph(
|
|
struct stb_ttc_info *fi,
|
|
unsigned int cp )
|
|
{
|
|
struct _stb_ttc_cp_bin *b = &fi->cp_bin[cp & (STB_TTC_BINCOUNT - 1)];
|
|
int di = 0;
|
|
for (unsigned int gi = 0; gi < b->cp_count; gi++, di++)
|
|
if (b->cp_gl[gi].cp == cp)
|
|
return b->cp_gl[gi].glyph;
|
|
else if (b->cp_gl[gi].cp > cp)
|
|
break;
|
|
int gl = stbtt_FindGlyphIndex(&fi->font, cp);
|
|
if (gl == 0)
|
|
return -1;
|
|
if (!(b->cp_count % STB_TTC_PAGESIZE))
|
|
b->cp_gl = realloc(b->cp_gl,
|
|
sizeof(b->cp_gl[0]) * (b->cp_count + STB_TTC_PAGESIZE));
|
|
memmove(b->cp_gl + di + 1, b->cp_gl + di,
|
|
sizeof(b->cp_gl[0]) * (b->cp_count - di));
|
|
b->cp_count++;
|
|
b->cp_gl[di].cp = cp;
|
|
b->cp_gl[di].glyph = gl;
|
|
return gl;
|
|
}
|
|
|
|
/*
|
|
* return kerning for 2 codepoints, cache the result.
|
|
*/
|
|
static int
|
|
stb_ttc__CodepointsGetKerning(
|
|
struct stb_ttc_info *fi,
|
|
unsigned int cp1,
|
|
unsigned int cp2 )
|
|
{
|
|
unsigned int hash = cp1 + ((cp1 * 100) * cp2);
|
|
struct _stb_ttc_kn_bin *b = &fi->kn_bin[hash & (STB_TTC_BINCOUNT - 1)];
|
|
int di = 0;
|
|
for (unsigned int gi = 0; gi < b->kn_count; gi++, di++)
|
|
if (b->cp_kn[gi].hash == hash &&
|
|
b->cp_kn[gi].cp1 == cp1 &&
|
|
b->cp_kn[gi].cp2 == cp2)
|
|
return b->cp_kn[gi].kern;
|
|
else if (b->cp_kn[gi].hash > hash)
|
|
break;
|
|
int kern = stbtt_GetCodepointKernAdvance(&fi->font, cp1, cp2);
|
|
|
|
if (!(b->kn_count % STB_TTC_PAGESIZE))
|
|
b->cp_kn = realloc(b->cp_kn,
|
|
sizeof(b->cp_kn[0]) * (b->kn_count + STB_TTC_PAGESIZE));
|
|
memmove(b->cp_kn + di + 1, b->cp_kn + di,
|
|
sizeof(b->cp_kn[0]) * (b->kn_count - di));
|
|
stb_ttc_cp_kern k = {
|
|
.hash = hash,
|
|
.cp1 = cp1,
|
|
.cp2 = cp2,
|
|
.kern = kern,
|
|
};
|
|
b->kn_count++;
|
|
b->cp_kn[di] = k;
|
|
return kern;
|
|
}
|
|
|
|
/*
|
|
* returns the index of glyph in the glyph table, or -1
|
|
*/
|
|
static int
|
|
stb_ttc__ScaledGlyphGetOffset(
|
|
struct stb_ttc_info *fi,
|
|
unsigned int glyph,
|
|
float scale )
|
|
{
|
|
unsigned int intscale = 1.0f / scale * 1000;
|
|
unsigned int hash = glyph + (glyph * intscale);
|
|
struct _stb_ttc_g_bin *b = &fi->g_bin[hash & (STB_TTC_BINCOUNT - 1)];
|
|
for (unsigned int gi = 0; gi < b->i_count; gi++)
|
|
if (b->index[gi].intscale == intscale &&
|
|
b->index[gi].glyph == glyph)
|
|
return b->index[gi].index;
|
|
else if (b->index[gi].glyph > glyph)
|
|
break;
|
|
return -1;
|
|
}
|
|
|
|
static struct stb_ttc_g *
|
|
stb_ttc__ScaledGlyphGetCache(
|
|
struct stb_ttc_info *ttc,
|
|
unsigned int glyph,
|
|
float scale )
|
|
{
|
|
if (glyph == (unsigned int)-1)
|
|
return NULL;
|
|
int cached_index = stb_ttc__ScaledGlyphGetOffset(ttc, glyph, scale);
|
|
if (cached_index != -1)
|
|
return &ttc->glyph[cached_index];
|
|
|
|
stb_ttc_g gc = { };
|
|
|
|
gc.glyph = glyph;
|
|
gc.intscale = 1.0f / scale * 1000;
|
|
gc.scale = scale;
|
|
gc.p_x = gc.p_y = -1; // not initialised yet
|
|
// we use locals, as we are storing values in shorter types
|
|
{
|
|
int advance, lsb, x0, y0, x1, y1;
|
|
stbtt_GetGlyphHMetrics(&ttc->font, glyph, &advance, &lsb);
|
|
stbtt_GetGlyphBitmapBox(&ttc->font, glyph, scale, scale, &x0, &y0, &x1,
|
|
&y1);
|
|
gc.advance = advance;
|
|
gc.lsb = lsb;
|
|
gc.x0 = x0;
|
|
gc.y0 = y0;
|
|
gc.x1 = x1;
|
|
gc.y1 = y1;
|
|
}
|
|
if (!(ttc->g_count % STB_TTC_PAGESIZE))
|
|
ttc->glyph = realloc(ttc->glyph,
|
|
sizeof(ttc->glyph[0]) * (ttc->g_count + STB_TTC_PAGESIZE));
|
|
stb_ttc_index gh = {
|
|
.intscale = gc.intscale,
|
|
.glyph = glyph,
|
|
.index = ttc->g_count
|
|
};
|
|
gc.index = ttc->g_count;
|
|
ttc->g_count++;
|
|
|
|
unsigned int hash = glyph + (glyph * gc.intscale);
|
|
struct _stb_ttc_g_bin *b = &ttc->g_bin[hash & (STB_TTC_BINCOUNT - 1)];
|
|
|
|
if (!(b->i_count % STB_TTC_PAGESIZE))
|
|
b->index = realloc(b->index,
|
|
sizeof(b->index[0]) * (b->i_count + STB_TTC_PAGESIZE));
|
|
unsigned int di = b->i_count;
|
|
for (unsigned int i = 0; i < b->i_count; i++)
|
|
if (b->index[i].glyph > glyph) {
|
|
di = i;
|
|
break;
|
|
}
|
|
if (b->i_count - di)
|
|
memmove(&b->index[di + 1], &b->index[di],
|
|
sizeof(b->index[0]) * (b->i_count - di));
|
|
b->index[di] = gh;
|
|
b->i_count++;
|
|
ttc->glyph[gh.index] = gc;
|
|
return &ttc->glyph[gh.index];
|
|
}
|
|
|
|
static void
|
|
stb_ttc__ScaledGlyphRenderToCache(
|
|
struct stb_ttc_info *fi,
|
|
struct stb_ttc_g *g )
|
|
{
|
|
int wt = g->x1 - g->x0;
|
|
wt = (wt + 3) & ~3;
|
|
unsigned int ht = g->y1 - g->y0;
|
|
// find the new horizontal position for glyph, "wrap" next line if needed
|
|
if (fi->p_line_x + wt > fi->p_stride) {
|
|
fi->p_line_x = 0;
|
|
fi->p_line_y += fi->p_line_height;
|
|
fi->p_line_height = 0;
|
|
}
|
|
if (ht > fi->p_line_height)
|
|
fi->p_line_height = ht;
|
|
// reallocate the pixel cache to accommodate more lines, if needed
|
|
if (fi->p_line_y + ht > fi->p_height) {
|
|
int add = fi->p_line_y + ht - fi->p_height;
|
|
fi->pixels = realloc(fi->pixels, (fi->p_height + add) * fi->p_stride);
|
|
memset(fi->pixels + (fi->p_height * fi->p_stride), 0xff,
|
|
add * fi->p_stride);
|
|
fi->p_height += add;
|
|
}
|
|
g->p_x = fi->p_line_x;
|
|
g->p_y = fi->p_line_y;
|
|
stbtt_MakeGlyphBitmap(&fi->font,
|
|
fi->pixels + (g->p_y * fi->p_stride) + g->p_x, g->x1 - g->x0,
|
|
g->y1 - g->y0, fi->p_stride, g->scale, g->scale, g->glyph);
|
|
fi->p_line_x += wt;
|
|
}
|
|
|
|
static void
|
|
stb_ttc__GlyphRenderFromCache(
|
|
struct stb_ttc_info * fi,
|
|
struct stb_ttc_g * g,
|
|
unsigned int dx,
|
|
unsigned int base_dy,
|
|
unsigned char * pixels,
|
|
unsigned int p_w,
|
|
unsigned int p_h,
|
|
unsigned int p_stride)
|
|
{
|
|
int _dy = base_dy + g->y0;
|
|
int _sy = 0;
|
|
|
|
if (_dy >= (int)p_h || dx >= p_w || (int)base_dy + (g->y1 - g->y0) < 0)
|
|
return;
|
|
unsigned char * src = fi->pixels + (g->p_y * fi->p_stride);
|
|
|
|
// skip lines that would be over the top of dst pixels
|
|
if (_dy < 0) {
|
|
_sy -= _dy;
|
|
src += (-_dy) * fi->p_stride;
|
|
_dy = 0;
|
|
}
|
|
unsigned char * dst = pixels + (_dy * p_stride); // beginning of line in pixels
|
|
while (_dy < (int)p_h && _sy < (g->y1 - g->y0)) {
|
|
int rw = g->x1 - g->x0; // remaining width of glyph line
|
|
int line_dx = (int)dx - g->x0;
|
|
unsigned char * src_p = src + g->p_x;
|
|
// skip what would be before the left border of pixels
|
|
if (line_dx < 0) {
|
|
src_p += -line_dx;
|
|
rw += line_dx;
|
|
line_dx = 0;
|
|
}
|
|
if (line_dx + rw >= (int)p_w)
|
|
rw = p_w - line_dx;
|
|
unsigned char * dst_p = dst + line_dx;
|
|
for (; rw > 0; rw--) {
|
|
unsigned short s = *dst_p + *src_p;
|
|
unsigned char d = -(s >> 8) | (unsigned char)s;
|
|
*dst_p++ = d;
|
|
src_p++;
|
|
}
|
|
dst += p_stride;
|
|
src += fi->p_stride;
|
|
_dy++;
|
|
_sy++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Preload a range of codepoints into the glyph cache. This doesn't add the
|
|
* pixels, it just load the glyph measurement, advance, lsb into the cache
|
|
*/
|
|
STBTTC_DEF int
|
|
stb_ttc_CacheCodepointRange(
|
|
struct stb_ttc_info * ttc,
|
|
unsigned int cp,
|
|
unsigned int count,
|
|
float scale )
|
|
{
|
|
int res = 0;
|
|
for (unsigned int c = cp; c < cp + count; c++) {
|
|
int gl = stb_ttc__CodepointGetGlyph(ttc, c);
|
|
if (gl == -1)
|
|
continue;
|
|
stb_ttc__ScaledGlyphGetCache(ttc, gl, scale);
|
|
res++;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
static stb_ttc_info * _ttc;
|
|
static int
|
|
_compare(
|
|
const void *a,
|
|
const void *b)
|
|
{
|
|
stb_ttc_info *ttc = _ttc;
|
|
int g1 = *((int*)a), g2 = *((int*)b);
|
|
return (((ttc->glyph[g1].y1 - ttc->glyph[g1].y0) * 500) + ttc->glyph[g1].glyph) -
|
|
(((ttc->glyph[g2].y1 - ttc->glyph[g2].y0) * 500) + ttc->glyph[g2].glyph);
|
|
}
|
|
|
|
/*
|
|
* This walks the cache for glyphs that haven't been pre-rendered and
|
|
* render them in the cache. Also, it attempts to sort the glyphs by height
|
|
* into the cache to save a little bit of memory
|
|
* Note: This call is optional, the glyph renderer will populate the pixel
|
|
* cache lazily on the fly.
|
|
*/
|
|
STBTTC_DEF int
|
|
stb_ttc_RenderAllCachedGlyphs(
|
|
struct stb_ttc_info * ttc )
|
|
{
|
|
// go on and sort the glyph indexes by height
|
|
int * to_sort = malloc(ttc->g_count * sizeof(int));
|
|
for (int i = 0; i < (int)ttc->g_count; i++)
|
|
to_sort[i] = i;
|
|
_ttc = ttc;
|
|
qsort(to_sort, ttc->g_count, sizeof(int), _compare);
|
|
int count = 0;
|
|
// now load all the glyph pixels to the pixel cache
|
|
for (int i = 0; i < (int)ttc->g_count; i++) {
|
|
stb_ttc_g * g = &ttc->glyph[to_sort[i]];
|
|
if (g->p_y == (unsigned short)-1) {
|
|
stb_ttc__ScaledGlyphRenderToCache(ttc, &ttc->glyph[to_sort[i]]);
|
|
count++;
|
|
}
|
|
}
|
|
free(to_sort);
|
|
return count;
|
|
}
|
|
|
|
// Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
|
|
// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
|
|
#define UTF8_ACCEPT 0
|
|
#define UTF8_REJECT 12
|
|
|
|
static inline unsigned int
|
|
stb_ttc__UTF8_Decode(
|
|
unsigned int* state,
|
|
unsigned int* codep,
|
|
unsigned char byte)
|
|
{
|
|
static const unsigned char utf8d[] = {
|
|
// The first part of the table maps bytes to character classes that
|
|
// to reduce the size of the transition table and create bitmasks.
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
|
|
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
|
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
|
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
|
|
|
|
// The second part is a transition table that maps a combination
|
|
// of a state of the automaton and a character class to a state.
|
|
0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
|
|
12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
|
|
12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
|
|
12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
|
|
12,36,12,12,12,12,12,12,12,12,12,12,
|
|
};
|
|
unsigned int type = utf8d[byte];
|
|
*codep = (*state != UTF8_ACCEPT) ?
|
|
(byte & 0x3fu) | (*codep << 6) :
|
|
(0xff >> type) & (byte);
|
|
*state = utf8d[256 + *state + type];
|
|
return *state;
|
|
}
|
|
|
|
STBTTC_DEF int
|
|
stb_ttc_MeasureText(
|
|
struct stb_ttc_info * ttc,
|
|
float scale,
|
|
const char * text,
|
|
stb_ttc_measure *out)
|
|
{
|
|
unsigned int state = 0;
|
|
int xpos = 0;
|
|
unsigned int last = 0;
|
|
stb_ttc_measure m = { .ascent = ttc->ascent * scale,
|
|
.descent = ttc->descent * scale};
|
|
unsigned int cp = 0;
|
|
|
|
for (int ch = 0; text[ch]; ch++) {
|
|
if (stb_ttc__UTF8_Decode(&state, &cp, text[ch]) != UTF8_ACCEPT)
|
|
continue;
|
|
if (last) {
|
|
int kern = scale * stb_ttc__CodepointsGetKerning(ttc, last, cp);
|
|
xpos += kern;
|
|
}
|
|
last = cp;
|
|
int gl = stb_ttc__CodepointGetGlyph(ttc, cp);
|
|
if (gl == -1)
|
|
continue;
|
|
stb_ttc_g *gc = stb_ttc__ScaledGlyphGetCache(ttc, gl, scale);
|
|
if (!gc)
|
|
continue;
|
|
if (m.glyph_count == 0)
|
|
m.x0 = gc->x0;
|
|
if (gc->y0 < m.y0) m.y0 = gc->y0;
|
|
if (gc->y1 > m.y1) m.y1 = gc->y1;
|
|
m.glyph_count++;
|
|
xpos += gc->advance;
|
|
}
|
|
m.x1 = xpos * scale;
|
|
if (out) *out = m;
|
|
return m.x1 - m.x0;
|
|
}
|
|
|
|
STBTTC_DEF int
|
|
stb_ttc_DrawText(
|
|
struct stb_ttc_info * ttc,
|
|
float scale,
|
|
const char * text,
|
|
unsigned int dx,
|
|
unsigned int base_dy,
|
|
unsigned char * pixels,
|
|
unsigned int p_w,
|
|
unsigned int p_h,
|
|
unsigned int p_stride)
|
|
{
|
|
unsigned int state = 0;
|
|
int xpos = dx / scale;
|
|
unsigned int last = 0;
|
|
int glyph_count = 0;
|
|
unsigned int cp = 0;
|
|
|
|
for (int ch = 0; text[ch]; ch++) {
|
|
if (stb_ttc__UTF8_Decode(&state, &cp, text[ch]) != UTF8_ACCEPT)
|
|
continue;
|
|
if (last) {
|
|
int kern = scale * stb_ttc__CodepointsGetKerning(ttc, last, cp);
|
|
xpos += kern;
|
|
}
|
|
glyph_count++;
|
|
last = cp;
|
|
int gl = stb_ttc__CodepointGetGlyph(ttc, cp);
|
|
if (gl == -1)
|
|
continue;
|
|
stb_ttc_g *gc = stb_ttc__ScaledGlyphGetCache(ttc, gl, scale);
|
|
if (!gc)
|
|
continue;
|
|
// if (glyph_count == 1)
|
|
// xpos += -gc->x0 / scale;
|
|
if (gc->p_y == (unsigned short) -1)
|
|
stb_ttc__ScaledGlyphRenderToCache(ttc, gc);
|
|
|
|
int pxpos = gc->x0 + ((xpos + gc->lsb) * scale);
|
|
stb_ttc__GlyphRenderFromCache(ttc, gc, pxpos, base_dy,
|
|
pixels, p_w, p_h, p_stride);
|
|
xpos += gc->advance;
|
|
}
|
|
return glyph_count;
|
|
}
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <sys/mman.h>
|
|
|
|
STBTTC_DEF int
|
|
stb_ttc_MapFont(
|
|
struct stb_ttc_info * ttc,
|
|
const char * font_file)
|
|
{
|
|
int fd = open(font_file, O_RDONLY);
|
|
if (fd == -1)
|
|
return -1;
|
|
struct stat st;
|
|
if (fstat(fd, &st) == -1) {
|
|
close(fd);
|
|
return -1;
|
|
}
|
|
ttc->font_size = st.st_size;
|
|
unsigned char *map = mmap(NULL, ttc->font_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
|
close(fd);
|
|
if (map == MAP_FAILED)
|
|
return -1;
|
|
ttc->font_mmap = 1;
|
|
ttc->p_stride = 100; // default value;
|
|
// this make the code work for both ttf and ttc files
|
|
int offset = stbtt_GetFontOffsetForIndex(map, 0);
|
|
stbtt_InitFont(&ttc->font, map, offset);
|
|
stbtt_GetFontVMetrics(&ttc->font, &ttc->ascent, &ttc->descent, 0);
|
|
return 0;
|
|
}
|
|
|
|
STBTTC_DEF int
|
|
stb_ttc_LoadFont(
|
|
struct stb_ttc_info * ttc,
|
|
const void * font_data,
|
|
unsigned int font_size)
|
|
{
|
|
ttc->font_size = font_size;
|
|
unsigned char *map = (unsigned char *)font_data;
|
|
ttc->font_mmap = 0;
|
|
ttc->p_stride = 100; // default value;
|
|
// this make the code work for both ttf and ttc files
|
|
int offset = stbtt_GetFontOffsetForIndex(map, 0);
|
|
stbtt_InitFont(&ttc->font, map, offset);
|
|
stbtt_GetFontVMetrics(&ttc->font, &ttc->ascent, &ttc->descent, 0);
|
|
return 0;
|
|
}
|
|
|
|
STBTTC_DEF void
|
|
stb_ttc_Free(
|
|
struct stb_ttc_info * ttc)
|
|
{
|
|
for (int i = 0; i < STB_TTC_BINCOUNT; i++) {
|
|
free(ttc->cp_bin[i].cp_gl);
|
|
free(ttc->kn_bin[i].cp_kn);
|
|
free(ttc->g_bin[i].index);
|
|
}
|
|
free(ttc->pixels);
|
|
free(ttc->glyph);
|
|
if (ttc->font_mmap)
|
|
munmap(ttc->font.data, ttc->font_size);
|
|
}
|
|
#endif /* STB_TTC_IMPLEMENTATION */
|
|
|
|
#endif /* STB_TTC_H_ */
|