1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
#include "stb_loader.h"
#include "stb_image.c"
#define STB_TRUETYPE_IMPLEMENTATION
#include "stb_truetype.h"
#include "utf8decoder.h"
#include <algorithm>
static void do_free(char *ptr)
{
free((void *)ptr);
}
static void do_free_stbi(char *ptr)
{
stbi_image_free((stbi_uc *)ptr);
}
StbLoader_RGBA *
StbLoader::decode_image(void *buffer, size_t len)
{
int w, h;
stbi_uc *pixels = stbi_load_from_memory((stbi_uc *)buffer, len, &w, &h, NULL, 4);
return new StbLoader_RGBA((char *)pixels, w, h, do_free_stbi);
}
StbLoader_RGBA *
StbLoader::render_font(void *buffer, size_t len, StbLoader_Color color, int size, const char *text)
{
stbtt_fontinfo font;
stbtt_fontinfo *f = &font;
stbtt_InitFont(f, (const unsigned char *)buffer,
stbtt_GetFontOffsetForIndex((const unsigned char *)buffer, 0));
// Need to scale this a bit, so it looks roughly the same
// size as the font rendered in other renderers
float addscale = 1.25;
int w = 0;
int h = size * addscale;
float scale = stbtt_ScaleForPixelHeight(f, size * addscale);
int ascent, descent, lineGap;
stbtt_GetFontVMetrics(f, &ascent, &descent, &lineGap);
ascent *= scale;
descent *= scale;
lineGap *= scale;
uint32_t codepoint = 0;
uint32_t state = 0;
const unsigned char *p = (const unsigned char *)text;
// First pass: Get size of bitmap to render
for (; *p; ++p) {
if (utf8_decode(&state, &codepoint, *p) != UTF8_ACCEPT) {
continue;
}
int cw, ch;
int xo, yo;
stbtt_FreeBitmap(stbtt_GetCodepointBitmap(f, scale, scale,
codepoint, &cw, &ch, &xo, &yo), nullptr);
int advance, bearing;
stbtt_GetCodepointHMetrics(f, codepoint, &advance, &bearing);
advance *= scale;
bearing *= scale;
w += std::max(cw + xo, advance);
}
unsigned char *pixels = (unsigned char *)malloc(w * h * 4);
memset(pixels, 0x00 /* set to 0x77 for debugging */, w * h * 4);
int x = 0;
codepoint = 0; state = 0; p = (const unsigned char *)text;
// Second pass: Render RGBA bitmap
for (; *p; ++p) {
if (utf8_decode(&state, &codepoint, *p) != UTF8_ACCEPT) {
continue;
}
int cw, ch;
int xo, yo;
unsigned char *cb = stbtt_GetCodepointBitmap(f, scale, scale,
codepoint, &cw, &ch, &xo, &yo);
int advance, bearing;
stbtt_GetCodepointHMetrics(f, codepoint, &advance, &bearing);
advance *= scale;
bearing *= scale;
x += xo;
int y = h + yo + descent;
for (int dx=0; dx<cw; dx++) {
for (int dy=0; dy<ch; dy++) {
/* Clipping */
if (x + dx < 0 || x + dx >= w) {
continue;
} else if (y + dy < 0 || y + dy >= h) {
continue;
}
// RGB
pixels[4 * ((x + dx) + w * (y + dy)) + 0] = 255*color.r;
pixels[4 * ((x + dx) + w * (y + dy)) + 1] = 255*color.g;
pixels[4 * ((x + dx) + w * (y + dy)) + 2] = 255*color.b;
// Alpha
unsigned char &a = pixels[4 * ((x + dx) + w * (y + dy)) + 3];
a = std::min(0xFF, a + cb[dx+dy*cw]);
}
}
x += advance - bearing;
stbtt_FreeBitmap(cb, nullptr);
}
return new StbLoader_RGBA((char *)pixels, w, h, do_free);
}
|