2015-04-16 16:55:32 +00:00
|
|
|
//
|
|
|
|
// Copyright (c) 2011 Andreas Krinke andreas.krinke@gmx.de
|
|
|
|
// Copyright (c) 2009 Mikko Mononen memon@inside.org
|
|
|
|
//
|
|
|
|
// This software is provided 'as-is', without any express or implied
|
|
|
|
// warranty. In no event will the authors be held liable for any damages
|
|
|
|
// arising from the use of this software.
|
|
|
|
// Permission is granted to anyone to use this software for any purpose,
|
|
|
|
// including commercial applications, and to alter it and redistribute it
|
|
|
|
// freely, subject to the following restrictions:
|
|
|
|
// 1. The origin of this software must not be misrepresented; you must not
|
|
|
|
// claim that you wrote the original software. If you use this software
|
|
|
|
// in a product, an acknowledgment in the product documentation would be
|
|
|
|
// appreciated but is not required.
|
|
|
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
|
|
// misrepresented as being the original software.
|
|
|
|
// 3. This notice may not be removed or altered from any source distribution.
|
|
|
|
//
|
|
|
|
|
|
|
|
#define STB_TRUETYPE_IMPLEMENTATION
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#ifdef _WIN32
|
|
|
|
#include <windows.h>
|
|
|
|
#endif
|
|
|
|
#include "fontstash.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define BORDER_X_LEFT 2
|
|
|
|
#define BORDER_X_RIGHT 2
|
|
|
|
#define BORDER_Y_TOP 2
|
|
|
|
#define BORDER_Y_BOTTOM 2
|
|
|
|
#define ADDITIONAL_HEIGHT 2
|
|
|
|
|
|
|
|
#define STB_TRUETYPE_IMPLEMENTATION
|
|
|
|
#define STBTT_malloc(x,u) malloc(x)
|
|
|
|
#define STBTT_free(x,u) free(x)
|
|
|
|
#include "stb_truetype.h"
|
|
|
|
|
|
|
|
#define HASH_LUT_SIZE 256
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define TTFONT_FILE 1
|
|
|
|
#define TTFONT_MEM 2
|
|
|
|
#define BMFONT 3
|
|
|
|
|
|
|
|
static int idx = 1;
|
|
|
|
static float s_retinaScale = 1;
|
|
|
|
|
|
|
|
static unsigned int hashint(unsigned int a)
|
|
|
|
{
|
|
|
|
a += ~(a<<15);
|
|
|
|
a ^= (a>>10);
|
|
|
|
a += (a<<3);
|
|
|
|
a ^= (a>>6);
|
|
|
|
a += ~(a<<11);
|
|
|
|
a ^= (a>>16);
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct sth_font
|
|
|
|
{
|
|
|
|
int idx;
|
|
|
|
int type;
|
|
|
|
stbtt_fontinfo font;
|
|
|
|
unsigned char* data;
|
|
|
|
struct sth_glyph* glyphs;
|
|
|
|
int lut[HASH_LUT_SIZE];
|
|
|
|
int nglyphs;
|
|
|
|
float ascender;
|
|
|
|
float descender;
|
|
|
|
float lineh;
|
|
|
|
struct sth_font* next;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct sth_stash
|
|
|
|
{
|
|
|
|
int tw,th;
|
|
|
|
float itw,ith;
|
|
|
|
struct sth_texture* textures;
|
|
|
|
struct sth_font* fonts;
|
|
|
|
int drawing;
|
|
|
|
|
|
|
|
RenderCallbacks* m_renderCallbacks;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
|
|
|
|
// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details.
|
|
|
|
|
|
|
|
#define UTF8_ACCEPT 0
|
|
|
|
#define UTF8_REJECT 1
|
|
|
|
|
|
|
|
static const unsigned char utf8d[] = {
|
|
|
|
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, // 00..1f
|
|
|
|
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, // 20..3f
|
|
|
|
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, // 40..5f
|
|
|
|
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, // 60..7f
|
|
|
|
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, // 80..9f
|
|
|
|
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, // a0..bf
|
|
|
|
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, // c0..df
|
|
|
|
0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
|
|
|
|
0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
|
|
|
|
0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
|
|
|
|
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
|
|
|
|
1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
|
|
|
|
1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
|
|
|
|
1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
|
|
|
|
};
|
|
|
|
|
|
|
|
static unsigned int decutf8(unsigned int* state, unsigned int* codep, unsigned int byte)
|
|
|
|
{
|
|
|
|
unsigned int type = utf8d[byte];
|
|
|
|
*codep = (*state != UTF8_ACCEPT) ?
|
|
|
|
(byte & 0x3fu) | (*codep << 6) :
|
|
|
|
(0xff >> type) & (byte);
|
|
|
|
*state = utf8d[256 + *state*16 + type];
|
|
|
|
return *state;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct sth_stash* sth_create(int cachew, int cacheh, RenderCallbacks* renderCallbacks)
|
|
|
|
{
|
|
|
|
struct sth_stash* stash = NULL;
|
|
|
|
struct sth_texture* texture = NULL;
|
|
|
|
|
|
|
|
// Allocate memory for the font stash.
|
|
|
|
stash = (struct sth_stash*)malloc(sizeof(struct sth_stash));
|
|
|
|
if (stash == NULL)
|
|
|
|
{
|
|
|
|
assert(0);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
memset(stash,0,sizeof(struct sth_stash));
|
|
|
|
|
|
|
|
stash->m_renderCallbacks = renderCallbacks;
|
|
|
|
|
|
|
|
// Allocate memory for the first texture
|
|
|
|
texture = (struct sth_texture*)malloc(sizeof(struct sth_texture));
|
|
|
|
if (texture == NULL)
|
|
|
|
{
|
|
|
|
assert(0);
|
|
|
|
free(stash);
|
|
|
|
}
|
|
|
|
memset(texture,0,sizeof(struct sth_texture));
|
|
|
|
|
|
|
|
// Create first texture for the cache.
|
|
|
|
stash->tw = cachew;
|
|
|
|
stash->th = cacheh;
|
|
|
|
stash->itw = 1.0f/cachew;
|
|
|
|
stash->ith = 1.0f/cacheh;
|
|
|
|
stash->textures = texture;
|
|
|
|
|
|
|
|
stash->m_renderCallbacks->updateTexture(texture, 0, stash->tw, stash->th);
|
|
|
|
|
|
|
|
return stash;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int sth_add_font_from_memory(struct sth_stash* stash, unsigned char* buffer)
|
|
|
|
{
|
|
|
|
int i, ascent, descent, fh, lineGap;
|
|
|
|
struct sth_font* fnt = NULL;
|
|
|
|
|
|
|
|
fnt = (struct sth_font*)malloc(sizeof(struct sth_font));
|
|
|
|
if (fnt == NULL) goto error;
|
|
|
|
memset(fnt,0,sizeof(struct sth_font));
|
|
|
|
|
|
|
|
|
|
|
|
// Init hash lookup.
|
|
|
|
for (i = 0; i < HASH_LUT_SIZE; ++i)
|
|
|
|
fnt->lut[i] = -1;
|
|
|
|
|
|
|
|
fnt->data = buffer;
|
|
|
|
|
|
|
|
// Init stb_truetype
|
|
|
|
if (!stbtt_InitFont(&fnt->font, fnt->data, 0))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
|
|
|
|
// Store normalized line height. The real line height is got
|
|
|
|
// by multiplying the lineh by font size.
|
|
|
|
stbtt_GetFontVMetrics(&fnt->font, &ascent, &descent, &lineGap);
|
|
|
|
|
|
|
|
fh = ascent - descent;
|
|
|
|
fnt->ascender = (float)ascent / (float)fh;
|
|
|
|
fnt->descender = (float)descent / (float)fh;
|
|
|
|
fnt->lineh = (float)(fh + lineGap) / (float)fh;
|
|
|
|
|
|
|
|
fnt->idx = idx;
|
|
|
|
fnt->type = TTFONT_MEM;
|
|
|
|
fnt->next = stash->fonts;
|
|
|
|
stash->fonts = fnt;
|
|
|
|
|
|
|
|
|
|
|
|
return idx++;
|
|
|
|
|
|
|
|
error:
|
|
|
|
if (fnt) {
|
|
|
|
if (fnt->glyphs) free(fnt->glyphs);
|
|
|
|
free(fnt);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sth_add_font(struct sth_stash* stash, const char* path)
|
|
|
|
{
|
|
|
|
FILE* fp = 0;
|
|
|
|
int datasize;
|
|
|
|
unsigned char* data = NULL;
|
|
|
|
int idx=0;
|
|
|
|
|
|
|
|
// Read in the font data.
|
|
|
|
fp = fopen(path, "rb");
|
|
|
|
if (!fp) goto error;
|
|
|
|
fseek(fp,0,SEEK_END);
|
|
|
|
datasize = (int)ftell(fp);
|
|
|
|
fseek(fp,0,SEEK_SET);
|
|
|
|
data = (unsigned char*)malloc(datasize);
|
|
|
|
if (data == NULL) goto error;
|
|
|
|
int bytesRead;
|
|
|
|
bytesRead = fread(data, 1, datasize, fp);
|
|
|
|
if (bytesRead)
|
|
|
|
{
|
|
|
|
idx = sth_add_font_from_memory(stash, data);
|
|
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
fp = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// Modify type of the loaded font.
|
|
|
|
if (idx)
|
|
|
|
stash->fonts->type = TTFONT_FILE;
|
|
|
|
else
|
|
|
|
free(data);
|
|
|
|
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
error:
|
|
|
|
if (data) free(data);
|
|
|
|
if (fp) fclose(fp);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sth_add_bitmap_font(struct sth_stash* stash, int ascent, int descent, int line_gap)
|
|
|
|
{
|
|
|
|
int i, fh;
|
|
|
|
struct sth_font* fnt = NULL;
|
|
|
|
|
|
|
|
fnt = (struct sth_font*)malloc(sizeof(struct sth_font));
|
|
|
|
if (fnt == NULL) goto error;
|
|
|
|
memset(fnt,0,sizeof(struct sth_font));
|
|
|
|
|
|
|
|
// Init hash lookup.
|
|
|
|
for (i = 0; i < HASH_LUT_SIZE; ++i) fnt->lut[i] = -1;
|
|
|
|
|
|
|
|
// Store normalized line height. The real line height is got
|
|
|
|
// by multiplying the lineh by font size.
|
|
|
|
fh = ascent - descent;
|
|
|
|
fnt->ascender = (float)ascent / (float)fh;
|
|
|
|
fnt->descender = (float)descent / (float)fh;
|
|
|
|
fnt->lineh = (float)(fh + line_gap) / (float)fh;
|
|
|
|
|
|
|
|
fnt->idx = idx;
|
|
|
|
fnt->type = BMFONT;
|
|
|
|
fnt->next = stash->fonts;
|
|
|
|
stash->fonts = fnt;
|
|
|
|
|
|
|
|
return idx++;
|
|
|
|
|
|
|
|
error:
|
|
|
|
if (fnt) free(fnt);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*void sth_add_glyph(struct sth_stash* stash,
|
|
|
|
int idx,
|
|
|
|
unsigned int id1,
|
|
|
|
const char* s,
|
|
|
|
short size, short base,
|
|
|
|
int x, int y, int w, int h,
|
|
|
|
float xoffset, float yoffset, float xadvance)
|
|
|
|
{
|
|
|
|
struct sth_texture* texture = NULL;
|
|
|
|
struct sth_font* fnt = NULL;
|
|
|
|
struct sth_glyph* glyph = NULL;
|
|
|
|
unsigned int codepoint;
|
|
|
|
unsigned int state = 0;
|
|
|
|
|
|
|
|
if (stash == NULL) return;
|
|
|
|
texture = stash->textures;
|
|
|
|
while (texture != NULL && texture->id != id)
|
|
|
|
texture = texture->next;
|
|
|
|
|
|
|
|
if (texture == NULL)
|
|
|
|
{
|
|
|
|
// Create new texture
|
|
|
|
texture = (struct sth_texture*)malloc(sizeof(struct sth_texture));
|
|
|
|
if (texture == NULL) return;
|
|
|
|
memset(texture, 0, sizeof(struct sth_texture));
|
|
|
|
texture->id = id;
|
|
|
|
texture->next = stash->textures;
|
|
|
|
stash->textures = texture;
|
|
|
|
}
|
|
|
|
|
|
|
|
fnt = stash->fonts;
|
|
|
|
while (fnt != NULL && fnt->idx != idx) fnt = fnt->next;
|
|
|
|
if (fnt == NULL) return;
|
|
|
|
if (fnt->type != BMFONT) return;
|
|
|
|
|
|
|
|
for (; *s; ++s)
|
|
|
|
{
|
|
|
|
if (!decutf8(&state, &codepoint, *(unsigned char*)s)) break;
|
|
|
|
}
|
|
|
|
if (state != UTF8_ACCEPT) return;
|
|
|
|
|
|
|
|
// Alloc space for new glyph.
|
|
|
|
fnt->nglyphs++;
|
|
|
|
fnt->glyphs = (sth_glyph*)realloc(fnt->glyphs, fnt->nglyphs*sizeof(struct sth_glyph));
|
|
|
|
if (!fnt->glyphs) return;
|
|
|
|
|
|
|
|
// Init glyph.
|
|
|
|
glyph = &fnt->glyphs[fnt->nglyphs-1];
|
|
|
|
memset(glyph, 0, sizeof(struct sth_glyph));
|
|
|
|
glyph->codepoint = codepoint;
|
|
|
|
glyph->size = size;
|
|
|
|
glyph->texture = texture;
|
|
|
|
glyph->x0_ = x;
|
|
|
|
glyph->y0 = y;
|
|
|
|
glyph->x1 = glyph->x0_+w;
|
|
|
|
glyph->y1 = glyph->y0+h;
|
|
|
|
glyph->xoff = xoffset;
|
|
|
|
glyph->yoff = yoffset - base;
|
|
|
|
glyph->xadv = xadvance;
|
|
|
|
|
|
|
|
// Find code point and size.
|
|
|
|
h = hashint(codepoint) & (HASH_LUT_SIZE-1);
|
|
|
|
// Insert char to hash lookup.
|
|
|
|
glyph->next = fnt->lut[h];
|
|
|
|
fnt->lut[h] = fnt->nglyphs-1;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
static struct sth_glyph* get_glyph(struct sth_stash* stash, struct sth_font* fnt, unsigned int codepoint, short isize)
|
|
|
|
{
|
|
|
|
int i,g,advance,lsb,x0,y0,x1,y1,gw,gh;
|
|
|
|
float scale;
|
|
|
|
struct sth_texture* texture = NULL;
|
|
|
|
struct sth_glyph* glyph = NULL;
|
|
|
|
|
|
|
|
unsigned int h;
|
|
|
|
float size = isize/10.0f;
|
|
|
|
int rh;
|
|
|
|
struct sth_row* br = NULL;
|
|
|
|
|
|
|
|
// Find code point and size.
|
|
|
|
h = hashint(codepoint) & (HASH_LUT_SIZE-1);
|
|
|
|
i = fnt->lut[h];
|
|
|
|
while (i != -1)
|
|
|
|
{
|
|
|
|
if (fnt->glyphs[i].codepoint == codepoint && (fnt->type == BMFONT || fnt->glyphs[i].size == isize))
|
|
|
|
return &fnt->glyphs[i];
|
|
|
|
i = fnt->glyphs[i].next;
|
|
|
|
}
|
|
|
|
// Could not find glyph.
|
|
|
|
|
|
|
|
// For bitmap fonts: ignore this glyph.
|
|
|
|
if (fnt->type == BMFONT) return 0;
|
|
|
|
|
|
|
|
// For truetype fonts: create this glyph.
|
|
|
|
scale = stbtt_ScaleForPixelHeight(&fnt->font, size);
|
|
|
|
g = stbtt_FindGlyphIndex(&fnt->font, codepoint);
|
|
|
|
stbtt_GetGlyphHMetrics(&fnt->font, g, &advance, &lsb);
|
|
|
|
stbtt_GetGlyphBitmapBox(&fnt->font, g, scale,scale, &x0,&y0,&x1,&y1);
|
|
|
|
gw = x1-x0;
|
|
|
|
gh = y1-y0;
|
|
|
|
|
|
|
|
// Check if glyph is larger than maximum texture size
|
|
|
|
if (gw >= stash->tw || gh >= stash->th)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// Find texture and row where the glyph can be fit.
|
|
|
|
br = NULL;
|
|
|
|
rh = (gh+7) & ~7;
|
|
|
|
texture = stash->textures;
|
|
|
|
while(br == NULL)
|
|
|
|
{
|
|
|
|
for (i = 0; i < texture->nrows; ++i)
|
|
|
|
{
|
|
|
|
if (texture->rows[i].h >= rh && texture->rows[i].x+gw+1 <= stash->tw)
|
|
|
|
br = &texture->rows[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
// If no row is found, there are 3 possibilities:
|
|
|
|
// - add new row
|
|
|
|
// - try next texture
|
|
|
|
// - create new texture
|
|
|
|
if (br == NULL)
|
|
|
|
{
|
|
|
|
short py = BORDER_Y_TOP;
|
|
|
|
// Check that there is enough space.
|
|
|
|
if (texture->nrows)
|
|
|
|
{
|
|
|
|
py = texture->rows[texture->nrows-1].y + texture->rows[texture->nrows-1].h+1;
|
|
|
|
if (py+rh > stash->th)
|
|
|
|
{
|
|
|
|
if (texture->next != NULL)
|
|
|
|
{
|
|
|
|
texture = texture->next;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Create new texture
|
|
|
|
texture->next = (struct sth_texture*)malloc(sizeof(struct sth_texture));
|
|
|
|
texture = texture->next;
|
|
|
|
if (texture == NULL) goto error;
|
|
|
|
memset(texture,0,sizeof(struct sth_texture));
|
|
|
|
|
|
|
|
stash->m_renderCallbacks->updateTexture(texture,0,stash->tw,stash->th);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Init and add row
|
|
|
|
br = &texture->rows[texture->nrows];
|
|
|
|
br->x = BORDER_X_LEFT;
|
|
|
|
br->y = py+BORDER_Y_BOTTOM;
|
|
|
|
br->h = rh+ADDITIONAL_HEIGHT;
|
|
|
|
texture->nrows++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Alloc space for new glyph.
|
|
|
|
fnt->nglyphs++;
|
|
|
|
fnt->glyphs = (sth_glyph*)realloc(fnt->glyphs, fnt->nglyphs*sizeof(struct sth_glyph));
|
|
|
|
if (!fnt->glyphs) return 0;
|
|
|
|
|
|
|
|
// Init glyph.
|
|
|
|
glyph = &fnt->glyphs[fnt->nglyphs-1];
|
|
|
|
memset(glyph, 0, sizeof(struct sth_glyph));
|
|
|
|
glyph->codepoint = codepoint;
|
|
|
|
glyph->size = isize;
|
|
|
|
glyph->texture = texture;
|
|
|
|
glyph->x0_ = br->x;
|
|
|
|
glyph->y0 = br->y;
|
|
|
|
glyph->x1 = glyph->x0_+gw;
|
|
|
|
glyph->y1 = glyph->y0+gh;
|
|
|
|
glyph->xadv = scale * advance;
|
|
|
|
glyph->xoff = (float)x0;
|
|
|
|
glyph->yoff = (float)y0;
|
|
|
|
glyph->next = 0;
|
|
|
|
|
|
|
|
// Advance row location.
|
|
|
|
br->x += gw+BORDER_X_RIGHT;
|
|
|
|
|
|
|
|
// Insert char to hash lookup.
|
|
|
|
glyph->next = fnt->lut[h];
|
|
|
|
fnt->lut[h] = fnt->nglyphs-1;
|
|
|
|
|
|
|
|
// Rasterize
|
|
|
|
{
|
|
|
|
unsigned char* ptr = texture->m_texels+glyph->x0_+glyph->y0*stash->tw;
|
|
|
|
stbtt_MakeGlyphBitmap(&fnt->font,ptr , gw,gh,stash->tw, scale,scale, g);
|
|
|
|
|
|
|
|
stash->m_renderCallbacks->updateTexture(texture,glyph, stash->tw, stash->th);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return glyph;
|
|
|
|
|
|
|
|
error:
|
|
|
|
if (texture)
|
|
|
|
free(texture);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_quad(struct sth_stash* stash, struct sth_font* fnt, struct sth_glyph* glyph, short isize, float* x, float* y, struct sth_quad* q)
|
|
|
|
{
|
|
|
|
float rx,ry;
|
|
|
|
float scale = 1.f/s_retinaScale;//1.0f;
|
|
|
|
|
|
|
|
if (fnt->type == BMFONT)
|
|
|
|
scale = isize/(glyph->size*10.0f);
|
|
|
|
|
|
|
|
rx = (*x + scale * float(glyph->xoff));
|
|
|
|
ry = (*y + scale * float(glyph->yoff));
|
|
|
|
|
|
|
|
q->x0 = rx;
|
|
|
|
q->y0 = ry + 1.5f*0.5f*float(isize)/10.f;
|
|
|
|
|
|
|
|
q->x1 = rx + scale * float(glyph->x1 - glyph->x0_);
|
|
|
|
q->y1 = ry + scale * float(glyph->y1 - glyph->y0)+ 1.5f*0.5f*float(isize)/10.f;
|
|
|
|
|
|
|
|
q->s0 = float(glyph->x0_) * stash->itw;
|
|
|
|
q->t0 = float(glyph->y0) * stash->ith;
|
|
|
|
q->s1 = float(glyph->x1) * stash->itw;
|
|
|
|
q->t1 = float(glyph->y1) * stash->ith;
|
|
|
|
|
|
|
|
*x += scale * glyph->xadv;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Vertex* setv(Vertex* v, float x, float y, float s, float t, float width, float height)
|
|
|
|
{
|
|
|
|
bool scale=true;
|
|
|
|
if (scale)
|
|
|
|
{
|
|
|
|
v->position.p[0] = (x*2-width)/(width);
|
|
|
|
v->position.p[1] = 1-(y)/(height/2);
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
v->position.p[0] = (x-width)/(width);
|
|
|
|
v->position.p[1] = (height-y)/(height);
|
|
|
|
}
|
|
|
|
v->position.p[2] = 0.f;
|
|
|
|
v->position.p[3] = 1.f;
|
|
|
|
|
|
|
|
v->uv.p[0] = s;
|
|
|
|
v->uv.p[1] = t;
|
|
|
|
|
|
|
|
v->colour.p[0] = 0.1f;//1.f;
|
|
|
|
v->colour.p[1] = 0.1f;
|
|
|
|
v->colour.p[2] = 0.1f;
|
|
|
|
v->colour.p[3] = 1.f;
|
|
|
|
|
|
|
|
return v+1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void flush_draw(struct sth_stash* stash)
|
|
|
|
{
|
|
|
|
struct sth_texture* texture = stash->textures;
|
|
|
|
while (texture)
|
|
|
|
{
|
|
|
|
if (texture->nverts > 0)
|
|
|
|
{
|
|
|
|
stash->m_renderCallbacks->render(texture);
|
|
|
|
texture->nverts = 0;
|
|
|
|
}
|
|
|
|
texture = texture->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void sth_begin_draw(struct sth_stash* stash)
|
|
|
|
{
|
|
|
|
if (stash == NULL) return;
|
|
|
|
if (stash->drawing)
|
|
|
|
flush_draw(stash);
|
|
|
|
stash->drawing = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void sth_end_draw(struct sth_stash* stash)
|
|
|
|
{
|
|
|
|
if (stash == NULL) return;
|
|
|
|
if (!stash->drawing) return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
// Debug dump.
|
|
|
|
if (stash->nverts+6 < VERT_COUNT)
|
|
|
|
{
|
|
|
|
float x = 500, y = 100;
|
|
|
|
float* v = &stash->verts[stash->nverts*4];
|
|
|
|
|
|
|
|
v = setv(v, x, y, 0, 0);
|
|
|
|
v = setv(v, x+stash->tw, y, 1, 0);
|
|
|
|
v = setv(v, x+stash->tw, y+stash->th, 1, 1);
|
|
|
|
|
|
|
|
v = setv(v, x, y, 0, 0);
|
|
|
|
v = setv(v, x+stash->tw, y+stash->th, 1, 1);
|
|
|
|
v = setv(v, x, y+stash->th, 0, 1);
|
|
|
|
|
|
|
|
stash->nverts += 6;
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
flush_draw(stash);
|
|
|
|
stash->drawing = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void sth_draw_texture(struct sth_stash* stash,
|
|
|
|
int idx, float size,
|
|
|
|
float x, float y,
|
|
|
|
int screenwidth, int screenheight,
|
|
|
|
const char* s, float* dx)
|
|
|
|
{
|
|
|
|
int width = stash->tw;
|
|
|
|
int height=stash->th;
|
|
|
|
|
|
|
|
unsigned int codepoint;
|
|
|
|
struct sth_glyph* glyph = NULL;
|
|
|
|
struct sth_texture* texture = NULL;
|
|
|
|
unsigned int state = 0;
|
|
|
|
struct sth_quad q;
|
|
|
|
short isize = (short)(size*10.0f);
|
|
|
|
Vertex* v;
|
|
|
|
struct sth_font* fnt = NULL;
|
|
|
|
|
|
|
|
if (stash == NULL) return;
|
|
|
|
|
|
|
|
if (!stash->textures) return;
|
|
|
|
fnt = stash->fonts;
|
|
|
|
while(fnt != NULL && fnt->idx != idx) fnt = fnt->next;
|
|
|
|
if (fnt == NULL) return;
|
|
|
|
if (fnt->type != BMFONT && !fnt->data) return;
|
|
|
|
|
|
|
|
int once = true;
|
|
|
|
for (; once; ++s)
|
|
|
|
{
|
|
|
|
once=false;
|
|
|
|
if (decutf8(&state, &codepoint, *(unsigned char*)s))
|
|
|
|
continue;
|
|
|
|
glyph = get_glyph(stash, fnt, codepoint, isize);
|
|
|
|
if (!glyph)
|
|
|
|
continue;
|
|
|
|
texture = glyph->texture;
|
|
|
|
if (texture->nverts+6 >= VERT_COUNT)
|
|
|
|
flush_draw(stash);
|
|
|
|
|
|
|
|
if (!get_quad(stash, fnt, glyph, isize, &x, &y, &q))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
v = &texture->newverts[texture->nverts];
|
|
|
|
q.x0 = 0;
|
|
|
|
q.y0 = 0;
|
|
|
|
q.x1 = q.x0+width;
|
|
|
|
q.y1 = q.y0+height;
|
|
|
|
|
|
|
|
v = setv(v, q.x0, q.y0, 0,0,(float)screenwidth,(float)screenheight);
|
|
|
|
v = setv(v, q.x1, q.y0, 1,0,(float)screenwidth,(float)screenheight);
|
|
|
|
v = setv(v, q.x1, q.y1, 1,1,(float)screenwidth,(float)screenheight);
|
|
|
|
|
|
|
|
v = setv(v, q.x0, q.y0, 0,0,(float)screenwidth,(float)screenheight);
|
|
|
|
v = setv(v, q.x1, q.y1, 1,1,(float)screenwidth,(float)screenheight);
|
|
|
|
v = setv(v, q.x0, q.y1, 0,1,(float)screenwidth,(float)screenheight);
|
|
|
|
texture->nverts += 6;
|
|
|
|
}
|
|
|
|
|
|
|
|
flush_draw(stash);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (dx) *dx = x;
|
|
|
|
}
|
|
|
|
|
|
|
|
void sth_flush_draw(struct sth_stash* stash)
|
|
|
|
{
|
|
|
|
flush_draw(stash);
|
|
|
|
}
|
|
|
|
void sth_draw_text(struct sth_stash* stash,
|
|
|
|
int idx, float size,
|
|
|
|
float x, float y,
|
|
|
|
const char* s, float* dx, int screenwidth, int screenheight, int measureOnly, float retinaScale)
|
|
|
|
{
|
|
|
|
|
|
|
|
unsigned int codepoint;
|
|
|
|
struct sth_glyph* glyph = NULL;
|
|
|
|
struct sth_texture* texture = NULL;
|
|
|
|
unsigned int state = 0;
|
|
|
|
struct sth_quad q;
|
|
|
|
short isize = (short)(size*10.0f);
|
|
|
|
Vertex* v;
|
|
|
|
struct sth_font* fnt = NULL;
|
|
|
|
|
|
|
|
s_retinaScale = retinaScale;
|
|
|
|
if (stash == NULL) return;
|
|
|
|
|
|
|
|
if (!stash->textures) return;
|
|
|
|
fnt = stash->fonts;
|
|
|
|
while(fnt != NULL && fnt->idx != idx) fnt = fnt->next;
|
|
|
|
if (fnt == NULL) return;
|
|
|
|
if (fnt->type != BMFONT && !fnt->data) return;
|
|
|
|
|
|
|
|
for (; *s; ++s)
|
|
|
|
{
|
|
|
|
if (decutf8(&state, &codepoint, *(unsigned char*)s))
|
|
|
|
continue;
|
|
|
|
glyph = get_glyph(stash, fnt, codepoint, isize);
|
|
|
|
if (!glyph) continue;
|
|
|
|
texture = glyph->texture;
|
|
|
|
|
|
|
|
if (!measureOnly)
|
|
|
|
{
|
|
|
|
if (texture->nverts+6 >= VERT_COUNT)
|
|
|
|
flush_draw(stash);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!get_quad(stash, fnt, glyph, isize, &x, &y, &q)) continue;
|
|
|
|
|
|
|
|
if (!measureOnly)
|
|
|
|
{
|
|
|
|
v = &texture->newverts[texture->nverts];
|
|
|
|
|
|
|
|
v = setv(v, q.x0, q.y0, q.s0, q.t0,(float)screenwidth,(float)screenheight);
|
|
|
|
v = setv(v, q.x1, q.y0, q.s1, q.t0,(float)screenwidth,(float)screenheight);
|
|
|
|
v = setv(v, q.x1, q.y1, q.s1, q.t1,(float)screenwidth,(float)screenheight);
|
|
|
|
|
|
|
|
v = setv(v, q.x0, q.y0, q.s0, q.t0,(float)screenwidth,(float)screenheight);
|
|
|
|
v = setv(v, q.x1, q.y1, q.s1, q.t1,(float)screenwidth,(float)screenheight);
|
|
|
|
v = setv(v, q.x0, q.y1, q.s0, q.t1,(float)screenwidth,(float)screenheight);
|
|
|
|
|
|
|
|
texture->nverts += 6;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dx) *dx = x;
|
|
|
|
}
|
|
|
|
|
|
|
|
void sth_dim_text(struct sth_stash* stash,
|
|
|
|
int idx, float size,
|
|
|
|
const char* s,
|
|
|
|
float* minx, float* miny, float* maxx, float* maxy)
|
|
|
|
{
|
|
|
|
unsigned int codepoint;
|
|
|
|
struct sth_glyph* glyph = NULL;
|
|
|
|
unsigned int state = 0;
|
|
|
|
struct sth_quad q;
|
|
|
|
short isize = (short)(size*10.0f);
|
|
|
|
struct sth_font* fnt = NULL;
|
|
|
|
float x = 0, y = 0;
|
|
|
|
|
|
|
|
if (stash == NULL)
|
|
|
|
return;
|
|
|
|
if (!stash->textures)
|
|
|
|
return;
|
|
|
|
fnt = stash->fonts;
|
|
|
|
while(fnt != NULL && fnt->idx != idx) fnt = fnt->next;
|
|
|
|
if (fnt == NULL) return;
|
|
|
|
if (fnt->type != BMFONT && !fnt->data) return;
|
|
|
|
|
|
|
|
*minx = *maxx = x;
|
|
|
|
*miny = *maxy = y;
|
|
|
|
|
|
|
|
for (; *s; ++s)
|
|
|
|
{
|
|
|
|
if (decutf8(&state, &codepoint, *(unsigned char*)s)) continue;
|
|
|
|
glyph = get_glyph(stash, fnt, codepoint, isize);
|
|
|
|
if (!glyph) continue;
|
|
|
|
if (!get_quad(stash, fnt, glyph, isize, &x, &y, &q)) continue;
|
|
|
|
if (q.x0 < *minx) *minx = q.x0;
|
|
|
|
if (q.x1 > *maxx) *maxx = q.x1;
|
|
|
|
if (q.y1 < *miny) *miny = q.y1;
|
|
|
|
if (q.y0 > *maxy) *maxy = q.y0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void sth_vmetrics(struct sth_stash* stash,
|
|
|
|
int idx, float size,
|
|
|
|
float* ascender, float* descender, float* lineh)
|
|
|
|
{
|
|
|
|
struct sth_font* fnt = NULL;
|
|
|
|
|
|
|
|
if (stash == NULL) return;
|
|
|
|
if (!stash->textures) return;
|
|
|
|
fnt = stash->fonts;
|
|
|
|
while(fnt != NULL && fnt->idx != idx) fnt = fnt->next;
|
|
|
|
if (fnt == NULL) return;
|
|
|
|
if (fnt->type != BMFONT && !fnt->data) return;
|
|
|
|
if (ascender)
|
|
|
|
*ascender = fnt->ascender*size;
|
|
|
|
if (descender)
|
|
|
|
*descender = fnt->descender*size;
|
|
|
|
if (lineh)
|
|
|
|
*lineh = fnt->lineh*size;
|
|
|
|
}
|
|
|
|
|
|
|
|
void sth_delete(struct sth_stash* stash)
|
|
|
|
{
|
|
|
|
struct sth_texture* tex = NULL;
|
|
|
|
struct sth_texture* curtex = NULL;
|
|
|
|
struct sth_font* fnt = NULL;
|
|
|
|
struct sth_font* curfnt = NULL;
|
|
|
|
|
|
|
|
if (!stash) return;
|
|
|
|
|
|
|
|
tex = stash->textures;
|
|
|
|
while(tex != NULL) {
|
|
|
|
curtex = tex;
|
2016-10-21 00:11:33 +00:00
|
|
|
free(tex->m_texels);
|
2015-04-16 16:55:32 +00:00
|
|
|
tex->m_texels=0;
|
|
|
|
tex = tex->next;
|
|
|
|
stash->m_renderCallbacks->updateTexture(curtex,0,0,0);
|
|
|
|
free(curtex);
|
|
|
|
}
|
|
|
|
|
|
|
|
fnt = stash->fonts;
|
|
|
|
while(fnt != NULL) {
|
|
|
|
curfnt = fnt;
|
|
|
|
fnt = fnt->next;
|
|
|
|
if (curfnt->glyphs)
|
|
|
|
{
|
|
|
|
free(curfnt->glyphs);
|
|
|
|
}
|
|
|
|
if (curfnt->type == TTFONT_FILE && curfnt->data)
|
|
|
|
{
|
|
|
|
free(curfnt->data);
|
|
|
|
}
|
|
|
|
free(curfnt);
|
|
|
|
}
|
|
|
|
free(stash);
|
|
|
|
}
|