mirror of https://github.com/bjornbytes/lovr.git
Start updating Rasterizer;
This commit is contained in:
parent
cb121d3d36
commit
717f95f6bd
|
@ -4,78 +4,202 @@
|
||||||
#include <lua.h>
|
#include <lua.h>
|
||||||
#include <lauxlib.h>
|
#include <lauxlib.h>
|
||||||
|
|
||||||
static int l_lovrRasterizerGetHeight(lua_State* L) {
|
static int l_lovrRasterizerGetFontSize(lua_State* L) {
|
||||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||||
lua_pushinteger(L, lovrRasterizerGetHeight(rasterizer));
|
float size = lovrRasterizerGetFontSize(rasterizer);
|
||||||
return 1;
|
lua_pushnumber(L, size);
|
||||||
}
|
|
||||||
|
|
||||||
static int l_lovrRasterizerGetAdvance(lua_State* L) {
|
|
||||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
|
||||||
lua_pushinteger(L, lovrRasterizerGetAdvance(rasterizer));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int l_lovrRasterizerGetAscent(lua_State* L) {
|
|
||||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
|
||||||
lua_pushinteger(L, lovrRasterizerGetAscent(rasterizer));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int l_lovrRasterizerGetDescent(lua_State* L) {
|
|
||||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
|
||||||
lua_pushinteger(L, lovrRasterizerGetDescent(rasterizer));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int l_lovrRasterizerGetLineHeight(lua_State* L) {
|
|
||||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
|
||||||
lua_pushinteger(L, lovrRasterizerGetHeight(rasterizer) * 1.25f);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_lovrRasterizerGetGlyphCount(lua_State* L) {
|
static int l_lovrRasterizerGetGlyphCount(lua_State* L) {
|
||||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||||
lua_pushinteger(L, lovrRasterizerGetGlyphCount(rasterizer));
|
uint32_t count = lovrRasterizerGetGlyphCount(rasterizer);
|
||||||
|
lua_pushinteger(L, count);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_lovrRasterizerHasGlyphs(lua_State* L) {
|
static int l_lovrRasterizerHasGlyphs(lua_State* L) {
|
||||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||||
bool hasGlyphs = true;
|
|
||||||
for (int i = 2; i <= lua_gettop(L); i++) {
|
for (int i = 2; i <= lua_gettop(L); i++) {
|
||||||
if (lua_type(L, i) == LUA_TSTRING) {
|
size_t length;
|
||||||
hasGlyphs &= lovrRasterizerHasGlyphs(rasterizer, lua_tostring(L, i));
|
const char* str;
|
||||||
} else {
|
switch (lua_type(L, i)) {
|
||||||
hasGlyphs &= lovrRasterizerHasGlyph(rasterizer, luax_checku32(L, i));
|
case LUA_TSTRING:
|
||||||
|
str = lua_tolstring(L, i, &length);
|
||||||
|
if (!lovrRasterizerHasGlyphs(rasterizer, str, length)) {
|
||||||
|
lua_pushboolean(L, false);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LUA_TNUMBER:
|
||||||
|
if (!lovrRasterizerHasGlyph(rasterizer, luax_checku32(L, i))) {
|
||||||
|
lua_pushboolean(L, false);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: return luax_typeerror(L, i, "string or number");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lua_pushboolean(L, hasGlyphs);
|
lua_pushboolean(L, true);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int l_lovrRasterizerGetWidth(lua_State* L) {
|
static int l_lovrRasterizerGetAscent(lua_State* L) {
|
||||||
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||||
|
float ascent = lovrRasterizerGetAscent(rasterizer);
|
||||||
|
lua_pushnumber(L, ascent);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_lovrRasterizerGetDescent(lua_State* L) {
|
||||||
|
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||||
|
float descent = lovrRasterizerGetDescent(rasterizer);
|
||||||
|
lua_pushnumber(L, descent);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_lovrRasterizerGetLineGap(lua_State* L) {
|
||||||
|
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||||
|
float lineGap = lovrRasterizerGetLineGap(rasterizer);
|
||||||
|
lua_pushnumber(L, lineGap);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_lovrRasterizerGetLeading(lua_State* L) {
|
||||||
|
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||||
|
float leading = lovrRasterizerGetLeading(rasterizer);
|
||||||
|
lua_pushnumber(L, leading);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t luax_checkcodepoint(lua_State* L, int index) {
|
||||||
size_t length;
|
size_t length;
|
||||||
const char* string = luaL_checklstring(L, 2, &length);
|
const char* str;
|
||||||
float wrap = luax_optfloat(L, 4, 0.f);
|
uint32_t codepoint;
|
||||||
float width, lastLineWidth, height;
|
switch (lua_type(L, index)) {
|
||||||
uint32_t lineCount, glyphCount;
|
case LUA_TSTRING:
|
||||||
lovrRasterizerMeasure(rasterizer, string, length, wrap, &width, &lastLineWidth, &height, &lineCount, &glyphCount);
|
str = lua_tolstring(L, index, &length);
|
||||||
lua_pushnumber(L, width);
|
return utf8_decode(str, str + length, &codepoint) ? codepoint : 0;
|
||||||
lua_pushnumber(L, lineCount + 1);
|
case LUA_TNUMBER:
|
||||||
lua_pushnumber(L, lastLineWidth);
|
return luax_checku32(L, index);
|
||||||
|
default: return luax_typeerror(L, index, "string or number"), 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_lovrRasterizerGetKerning(lua_State* L) {
|
||||||
|
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||||
|
uint32_t prev = luax_checkcodepoint(L, 2);
|
||||||
|
uint32_t next = luax_checkcodepoint(L, 3);
|
||||||
|
float kerning = lovrRasterizerGetKerning(rasterizer, prev, next);
|
||||||
|
lua_pushnumber(L, kerning);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_lovrRasterizerGetGlyphAdvance(lua_State* L) {
|
||||||
|
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||||
|
uint32_t codepoint = luax_checkcodepoint(L, 2);
|
||||||
|
float advance = lovrRasterizerGetGlyphAdvance(rasterizer, codepoint);
|
||||||
|
lua_pushnumber(L, advance);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_lovrRasterizerGetGlyphBearing(lua_State* L) {
|
||||||
|
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||||
|
uint32_t codepoint = luax_checkcodepoint(L, 2);
|
||||||
|
float bearing = lovrRasterizerGetGlyphBearing(rasterizer, codepoint);
|
||||||
|
lua_pushnumber(L, bearing);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_lovrRasterizerGetGlyphWidth(lua_State* L) {
|
||||||
|
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||||
|
uint32_t codepoint = luax_checkcodepoint(L, 2);
|
||||||
|
float box[4];
|
||||||
|
lovrRasterizerGetGlyphBoundingBox(rasterizer, codepoint, box);
|
||||||
|
lua_pushnumber(L, box[2] - box[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_lovrRasterizerGetGlyphHeight(lua_State* L) {
|
||||||
|
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||||
|
uint32_t codepoint = luax_checkcodepoint(L, 2);
|
||||||
|
float box[4];
|
||||||
|
lovrRasterizerGetGlyphBoundingBox(rasterizer, codepoint, box);
|
||||||
|
lua_pushnumber(L, box[3] - box[1]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_lovrRasterizerGetGlyphDimensions(lua_State* L) {
|
||||||
|
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||||
|
uint32_t codepoint = luax_checkcodepoint(L, 2);
|
||||||
|
float box[4];
|
||||||
|
lovrRasterizerGetGlyphBoundingBox(rasterizer, codepoint, box);
|
||||||
|
lua_pushnumber(L, box[2] - box[0]);
|
||||||
|
lua_pushnumber(L, box[3] - box[1]);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int l_lovrRasterizerGetGlyphBoundingBox(lua_State* L) {
|
||||||
|
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||||
|
uint32_t codepoint = luax_checkcodepoint(L, 2);
|
||||||
|
float box[4];
|
||||||
|
lovrRasterizerGetGlyphBoundingBox(rasterizer, codepoint, box);
|
||||||
|
lua_pushnumber(L, box[0]);
|
||||||
|
lua_pushnumber(L, box[1]);
|
||||||
|
lua_pushnumber(L, box[2]);
|
||||||
|
lua_pushnumber(L, box[3]);
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void onCurve2D(void* context, uint32_t degree, float* points) {
|
||||||
|
lua_State* L = context;
|
||||||
|
uint32_t count = (degree + 1) * 2;
|
||||||
|
lua_createtable(L, count, 0);
|
||||||
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
|
lua_pushnumber(L, points[i]);
|
||||||
|
lua_rawseti(L, -2, i + 1);
|
||||||
|
}
|
||||||
|
lua_rawseti(L, -2, luax_len(L, -2) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void onCurve3D(void* context, uint32_t degree, float* points) {
|
||||||
|
lua_State* L = context;
|
||||||
|
lua_createtable(L, (degree + 1) * 3, 0);
|
||||||
|
for (uint32_t i = 0; i < degree + 1; i++) {
|
||||||
|
lua_pushnumber(L, points[2 * i + 0]);
|
||||||
|
lua_rawseti(L, -2, 3 * i + 1);
|
||||||
|
lua_pushnumber(L, points[2 * i + 1]);
|
||||||
|
lua_rawseti(L, -2, 3 * i + 2);
|
||||||
|
lua_pushnumber(L, 0.);
|
||||||
|
lua_rawseti(L, -2, 3 * i + 3);
|
||||||
|
}
|
||||||
|
lua_rawseti(L, -2, luax_len(L, -2) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int l_lovrRasterizerGetGlyphCurves(lua_State* L) {
|
||||||
|
Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer);
|
||||||
|
uint32_t codepoint = luax_checkcodepoint(L, 2);
|
||||||
|
bool three = lua_toboolean(L, 3);
|
||||||
|
lua_newtable(L);
|
||||||
|
lovrRasterizerGetGlyphCurves(rasterizer, codepoint, three ? onCurve3D : onCurve2D, L);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
const luaL_Reg lovrRasterizer[] = {
|
const luaL_Reg lovrRasterizer[] = {
|
||||||
{ "getHeight", l_lovrRasterizerGetHeight },
|
{ "getFontSize", l_lovrRasterizerGetFontSize },
|
||||||
{ "getAdvance", l_lovrRasterizerGetAdvance },
|
|
||||||
{ "getAscent", l_lovrRasterizerGetAscent },
|
|
||||||
{ "getDescent", l_lovrRasterizerGetDescent },
|
|
||||||
{ "getLineHeight", l_lovrRasterizerGetLineHeight },
|
|
||||||
{ "getGlyphCount", l_lovrRasterizerGetGlyphCount },
|
{ "getGlyphCount", l_lovrRasterizerGetGlyphCount },
|
||||||
{ "hasGlyphs", l_lovrRasterizerHasGlyphs },
|
{ "hasGlyphs", l_lovrRasterizerHasGlyphs },
|
||||||
{ "getWidth", l_lovrRasterizerGetWidth },
|
{ "getAscent", l_lovrRasterizerGetAscent },
|
||||||
|
{ "getDescent", l_lovrRasterizerGetDescent },
|
||||||
|
{ "getLineGap", l_lovrRasterizerGetLineGap },
|
||||||
|
{ "getLeading", l_lovrRasterizerGetLeading },
|
||||||
|
{ "getKerning", l_lovrRasterizerGetKerning },
|
||||||
|
{ "getGlyphAdvance", l_lovrRasterizerGetGlyphAdvance },
|
||||||
|
{ "getGlyphBearing", l_lovrRasterizerGetGlyphBearing },
|
||||||
|
{ "getGlyphWidth", l_lovrRasterizerGetGlyphWidth },
|
||||||
|
{ "getGlyphHeight", l_lovrRasterizerGetGlyphHeight },
|
||||||
|
{ "getGlyphDimensions", l_lovrRasterizerGetGlyphDimensions },
|
||||||
|
{ "getGlyphBoundingBox", l_lovrRasterizerGetGlyphBoundingBox },
|
||||||
|
{ "getGlyphCurves", l_lovrRasterizerGetGlyphCurves },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,25 +1,21 @@
|
||||||
#include "data/rasterizer.h"
|
#include "data/rasterizer.h"
|
||||||
#include "data/blob.h"
|
#include "data/blob.h"
|
||||||
#include "data/image.h"
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "VarelaRound.ttf.h"
|
#include "VarelaRound.ttf.h"
|
||||||
#include "lib/stb/stb_truetype.h"
|
#include "lib/stb/stb_truetype.h"
|
||||||
#include <msdfgen-c.h>
|
#include <msdfgen-c.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
struct Rasterizer {
|
struct Rasterizer {
|
||||||
uint32_t ref;
|
uint32_t ref;
|
||||||
stbtt_fontinfo font;
|
|
||||||
struct Blob* blob;
|
struct Blob* blob;
|
||||||
float size;
|
float size;
|
||||||
float scale;
|
float scale;
|
||||||
int glyphCount;
|
float ascent;
|
||||||
int height;
|
float descent;
|
||||||
int advance;
|
float lineGap;
|
||||||
int ascent;
|
float leading;
|
||||||
int descent;
|
stbtt_fontinfo font;
|
||||||
};
|
};
|
||||||
|
|
||||||
Rasterizer* lovrRasterizerCreate(Blob* blob, float size) {
|
Rasterizer* lovrRasterizerCreate(Blob* blob, float size) {
|
||||||
|
@ -37,17 +33,13 @@ Rasterizer* lovrRasterizerCreate(Blob* blob, float size) {
|
||||||
rasterizer->blob = blob;
|
rasterizer->blob = blob;
|
||||||
rasterizer->size = size;
|
rasterizer->size = size;
|
||||||
rasterizer->scale = stbtt_ScaleForMappingEmToPixels(font, size);
|
rasterizer->scale = stbtt_ScaleForMappingEmToPixels(font, size);
|
||||||
rasterizer->glyphCount = font->numGlyphs;
|
|
||||||
|
|
||||||
int ascent, descent, linegap;
|
int ascent, descent, lineGap;
|
||||||
stbtt_GetFontVMetrics(font, &ascent, &descent, &linegap);
|
stbtt_GetFontVMetrics(font, &ascent, &descent, &lineGap);
|
||||||
rasterizer->ascent = roundf(ascent * rasterizer->scale);
|
rasterizer->ascent = ascent * rasterizer->scale;
|
||||||
rasterizer->descent = roundf(descent * rasterizer->scale);
|
rasterizer->descent = descent * rasterizer->scale;
|
||||||
rasterizer->height = roundf((ascent - descent + linegap) * rasterizer->scale);
|
rasterizer->lineGap = lineGap * rasterizer->scale;
|
||||||
|
rasterizer->leading = (ascent - descent + lineGap) * rasterizer->scale;
|
||||||
int x0, y0, x1, y1;
|
|
||||||
stbtt_GetFontBoundingBox(font, &x0, &y0, &x1, &y1);
|
|
||||||
rasterizer->advance = roundf(x1 * rasterizer->scale);
|
|
||||||
|
|
||||||
return rasterizer;
|
return rasterizer;
|
||||||
}
|
}
|
||||||
|
@ -58,96 +50,108 @@ void lovrRasterizerDestroy(void* ref) {
|
||||||
free(rasterizer);
|
free(rasterizer);
|
||||||
}
|
}
|
||||||
|
|
||||||
float lovrRasterizerGetSize(Rasterizer* rasterizer) {
|
float lovrRasterizerGetFontSize(Rasterizer* rasterizer) {
|
||||||
return rasterizer->size;
|
return rasterizer->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lovrRasterizerGetGlyphCount(Rasterizer* rasterizer) {
|
uint32_t lovrRasterizerGetGlyphCount(Rasterizer* rasterizer) {
|
||||||
return rasterizer->glyphCount;
|
return rasterizer->font.numGlyphs;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lovrRasterizerGetHeight(Rasterizer* rasterizer) {
|
bool lovrRasterizerHasGlyph(Rasterizer* rasterizer, uint32_t codepoint) {
|
||||||
return rasterizer->height;
|
return stbtt_FindGlyphIndex(&rasterizer->font, codepoint) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lovrRasterizerGetAdvance(Rasterizer* rasterizer) {
|
bool lovrRasterizerHasGlyphs(Rasterizer* rasterizer, const char* str, size_t length) {
|
||||||
return rasterizer->advance;
|
size_t bytes;
|
||||||
|
uint32_t codepoint;
|
||||||
|
const char* end = str + length;
|
||||||
|
while ((bytes = utf8_decode(str, end, &codepoint)) > 0) {
|
||||||
|
if (!lovrRasterizerHasGlyph(rasterizer, codepoint)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
str += bytes;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lovrRasterizerGetAscent(Rasterizer* rasterizer) {
|
float lovrRasterizerGetAscent(Rasterizer* rasterizer) {
|
||||||
return rasterizer->ascent;
|
return rasterizer->ascent;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lovrRasterizerGetDescent(Rasterizer* rasterizer) {
|
float lovrRasterizerGetDescent(Rasterizer* rasterizer) {
|
||||||
return rasterizer->descent;
|
return rasterizer->descent;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lovrRasterizerHasGlyph(Rasterizer* rasterizer, uint32_t character) {
|
float lovrRasterizerGetLineGap(Rasterizer* rasterizer) {
|
||||||
return stbtt_FindGlyphIndex(&rasterizer->font, character) != 0;
|
return rasterizer->lineGap;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool lovrRasterizerHasGlyphs(Rasterizer* rasterizer, const char* str) {
|
float lovrRasterizerGetLeading(Rasterizer* rasterizer) {
|
||||||
const char* end = str + strlen(str);
|
return rasterizer->leading;
|
||||||
unsigned int codepoint;
|
|
||||||
size_t bytes;
|
|
||||||
|
|
||||||
bool hasGlyphs = true;
|
|
||||||
while ((bytes = utf8_decode(str, end, &codepoint)) > 0) {
|
|
||||||
hasGlyphs &= lovrRasterizerHasGlyph(rasterizer, codepoint);
|
|
||||||
str += bytes;
|
|
||||||
}
|
|
||||||
return hasGlyphs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrRasterizerLoadGlyph(Rasterizer* rasterizer, uint32_t character, uint32_t padding, double spread, Glyph* glyph) {
|
float lovrRasterizerGetKerning(Rasterizer* rasterizer, uint32_t prev, uint32_t next) {
|
||||||
int glyphIndex = stbtt_FindGlyphIndex(&rasterizer->font, character);
|
return stbtt_GetCodepointKernAdvance(&rasterizer->font, prev, next) * rasterizer->scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
float lovrRasterizerGetGlyphAdvance(Rasterizer* rasterizer, uint32_t codepoint) {
|
||||||
int advance, bearing;
|
int advance, bearing;
|
||||||
stbtt_GetGlyphHMetrics(&rasterizer->font, glyphIndex, &advance, &bearing);
|
stbtt_GetCodepointHMetrics(&rasterizer->font, codepoint, &advance, &bearing);
|
||||||
|
return advance * rasterizer->scale;
|
||||||
|
}
|
||||||
|
|
||||||
if (stbtt_IsGlyphEmpty(&rasterizer->font, glyphIndex)) {
|
float lovrRasterizerGetGlyphBearing(Rasterizer* rasterizer, uint32_t codepoint) {
|
||||||
memset(glyph, 0, sizeof(Glyph));
|
int advance, bearing;
|
||||||
glyph->advance = roundf(advance * rasterizer->scale);
|
stbtt_GetCodepointHMetrics(&rasterizer->font, codepoint, &advance, &bearing);
|
||||||
|
return bearing * rasterizer->scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lovrRasterizerGetGlyphBoundingBox(Rasterizer* rasterizer, uint32_t codepoint, float box[4]) {
|
||||||
|
int x0, y0, x1, y1;
|
||||||
|
stbtt_GetCodepointBox(&rasterizer->font, codepoint, &x0, &y0, &x1, &y1);
|
||||||
|
box[0] = x0 * rasterizer->scale;
|
||||||
|
box[1] = y0 * rasterizer->scale;
|
||||||
|
box[2] = x1 * rasterizer->scale;
|
||||||
|
box[3] = y1 * rasterizer->scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lovrRasterizerIsGlyphEmpty(Rasterizer* rasterizer, uint32_t codepoint) {
|
||||||
|
return stbtt_IsGlyphEmpty(&rasterizer->font, stbtt_FindGlyphIndex(&rasterizer->font, codepoint));
|
||||||
|
}
|
||||||
|
|
||||||
|
void lovrRasterizerGetGlyphCurves(Rasterizer* rasterizer, uint32_t codepoint, void (*fn)(void* context, uint32_t degree, float* points), void* context) {
|
||||||
|
uint32_t id = stbtt_FindGlyphIndex(&rasterizer->font, codepoint);
|
||||||
|
|
||||||
|
if (stbtt_IsGlyphEmpty(&rasterizer->font, id)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trace glyph outline
|
|
||||||
stbtt_vertex* vertices;
|
stbtt_vertex* vertices;
|
||||||
int vertexCount = stbtt_GetGlyphShape(&rasterizer->font, glyphIndex, &vertices);
|
uint32_t count = stbtt_GetGlyphShape(&rasterizer->font, id, &vertices);
|
||||||
msShape* shape = msShapeCreate();
|
|
||||||
msContour* contour = NULL;
|
|
||||||
float x = 0.f;
|
float x = 0.f;
|
||||||
float y = 0.f;
|
float y = 0.f;
|
||||||
|
for (uint32_t i = 0; i < count; i++) {
|
||||||
for (int i = 0; i < vertexCount; i++) {
|
|
||||||
stbtt_vertex vertex = vertices[i];
|
stbtt_vertex vertex = vertices[i];
|
||||||
float x2 = vertex.x * rasterizer->scale;
|
float x2 = vertex.x * rasterizer->scale;
|
||||||
float y2 = vertex.y * rasterizer->scale;
|
float y2 = vertex.y * rasterizer->scale;
|
||||||
|
|
||||||
switch (vertex.type) {
|
if (vertex.type == STBTT_vline) {
|
||||||
case STBTT_vmove:
|
float points[4] = { x, y, x2, y2 };
|
||||||
contour = msShapeAddContour(shape);
|
fn(context, 1, points);
|
||||||
break;
|
} else if (vertex.type == STBTT_vcurve) {
|
||||||
|
float cx = vertex.cx * rasterizer->scale;
|
||||||
case STBTT_vline:
|
float cy = vertex.cy * rasterizer->scale;
|
||||||
msContourAddLinearEdge(contour, x, y, x2, y2);
|
float points[6] = { x, y, cx, cy, x2, y2 };
|
||||||
break;
|
fn(context, 2, points);
|
||||||
|
} else if (vertex.type == STBTT_vcubic) {
|
||||||
case STBTT_vcurve: {
|
float cx1 = vertex.cx * rasterizer->scale;
|
||||||
float cx = vertex.cx * rasterizer->scale;
|
float cy1 = vertex.cy * rasterizer->scale;
|
||||||
float cy = vertex.cy * rasterizer->scale;
|
float cx2 = vertex.cx1 * rasterizer->scale;
|
||||||
msContourAddQuadraticEdge(contour, x, y, cx, cy, x2, y2);
|
float cy2 = vertex.cy1 * rasterizer->scale;
|
||||||
break;
|
float points[8] = { x, y, cx1, cy1, cx2, cy2, x2, y2 };
|
||||||
}
|
fn(context, 3, points);
|
||||||
|
|
||||||
case STBTT_vcubic: {
|
|
||||||
float cx1 = vertex.cx * rasterizer->scale;
|
|
||||||
float cy1 = vertex.cy * rasterizer->scale;
|
|
||||||
float cx2 = vertex.cx1 * rasterizer->scale;
|
|
||||||
float cy2 = vertex.cy1 * rasterizer->scale;
|
|
||||||
msContourAddCubicEdge(contour, x, y, cx1, cy1, cx2, cy2, x2, y2);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
x = x2;
|
x = x2;
|
||||||
|
@ -155,86 +159,4 @@ void lovrRasterizerLoadGlyph(Rasterizer* rasterizer, uint32_t character, uint32_
|
||||||
}
|
}
|
||||||
|
|
||||||
stbtt_FreeShape(&rasterizer->font, vertices);
|
stbtt_FreeShape(&rasterizer->font, vertices);
|
||||||
|
|
||||||
int x0, y0, x1, y1;
|
|
||||||
stbtt_GetGlyphBox(&rasterizer->font, glyphIndex, &x0, &y0, &x1, &y1);
|
|
||||||
|
|
||||||
// Initialize glyph data
|
|
||||||
glyph->x = 0;
|
|
||||||
glyph->y = 0;
|
|
||||||
glyph->w = ceilf((x1 - x0) * rasterizer->scale);
|
|
||||||
glyph->h = ceilf((y1 - y0) * rasterizer->scale);
|
|
||||||
glyph->tw = glyph->w + 2 * padding;
|
|
||||||
glyph->th = glyph->h + 2 * padding;
|
|
||||||
glyph->dx = roundf(bearing * rasterizer->scale);
|
|
||||||
glyph->dy = roundf(y1 * rasterizer->scale);
|
|
||||||
glyph->advance = roundf(advance * rasterizer->scale);
|
|
||||||
glyph->data = lovrImageCreateRaw(glyph->tw, glyph->th, FORMAT_RGBA32F);
|
|
||||||
|
|
||||||
// Render SDF
|
|
||||||
float tx = (float) padding + -glyph->dx;
|
|
||||||
float ty = (float) padding + (float) glyph->h - glyph->dy;
|
|
||||||
msShapeNormalize(shape);
|
|
||||||
msEdgeColoringSimple(shape, 3., 0);
|
|
||||||
msGenerateMTSDF(lovrImageGetBlob(glyph->data)->data, glyph->tw, glyph->th, shape, spread, 1.f, 1.f, tx, ty);
|
|
||||||
msShapeDestroy(shape);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t lovrRasterizerGetKerning(Rasterizer* rasterizer, uint32_t left, uint32_t right) {
|
|
||||||
return stbtt_GetCodepointKernAdvance(&rasterizer->font, left, right) * rasterizer->scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
void lovrRasterizerMeasure(Rasterizer* rasterizer, const char* str, size_t length, float wrap, float* width, float* lastLineWidth, float* height, uint32_t* lineCount, uint32_t* glyphCount) {
|
|
||||||
float x = 0.f;
|
|
||||||
const char* end = str + length;
|
|
||||||
size_t bytes;
|
|
||||||
unsigned int previous = '\0';
|
|
||||||
unsigned int codepoint;
|
|
||||||
*width = 0.f;
|
|
||||||
*lastLineWidth = 0.f;
|
|
||||||
*lineCount = 0;
|
|
||||||
*glyphCount = 0;
|
|
||||||
|
|
||||||
while ((bytes = utf8_decode(str, end, &codepoint)) > 0) {
|
|
||||||
if (codepoint == '\n' || (wrap && x > wrap && (codepoint == ' ' || previous == ' '))) {
|
|
||||||
*width = MAX(*width, x);
|
|
||||||
(*lineCount)++;
|
|
||||||
x = 0.f;
|
|
||||||
previous = '\0';
|
|
||||||
if (codepoint == ' ' || codepoint == '\n') {
|
|
||||||
str += bytes;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tabs
|
|
||||||
if (codepoint == '\t') {
|
|
||||||
int glyphIndex = stbtt_FindGlyphIndex(&rasterizer->font, ' ');
|
|
||||||
int advance, bearing;
|
|
||||||
stbtt_GetGlyphHMetrics(&rasterizer->font, glyphIndex, &advance, &bearing);
|
|
||||||
x += advance * 4.f;
|
|
||||||
str += bytes;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
int glyphIndex = stbtt_FindGlyphIndex(&rasterizer->font, codepoint);
|
|
||||||
int advance, bearing;
|
|
||||||
stbtt_GetGlyphHMetrics(&rasterizer->font, glyphIndex, &advance, &bearing);
|
|
||||||
int x0, y0, x1, y1;
|
|
||||||
if (stbtt_GetGlyphBox(&rasterizer->font, glyphIndex, &x0, &y0, &x1, &y1)) {
|
|
||||||
float w = ceilf((x1 - x0) * rasterizer->scale);
|
|
||||||
float h = ceilf((y1 - y0) * rasterizer->scale);
|
|
||||||
if (w > 0 && h > 0) {
|
|
||||||
(*glyphCount)++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
x += roundf(advance * rasterizer->scale) + lovrRasterizerGetKerning(rasterizer, previous, codepoint);
|
|
||||||
previous = codepoint;
|
|
||||||
str += bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
*width = MAX(*width, x);
|
|
||||||
*lastLineWidth = x;
|
|
||||||
*height = ((*lineCount + 1) * lovrRasterizerGetHeight(rasterizer));
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,30 +7,20 @@
|
||||||
struct Blob;
|
struct Blob;
|
||||||
struct Image;
|
struct Image;
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t x;
|
|
||||||
uint32_t y;
|
|
||||||
uint32_t w;
|
|
||||||
uint32_t h;
|
|
||||||
uint32_t tw;
|
|
||||||
uint32_t th;
|
|
||||||
int32_t dx;
|
|
||||||
int32_t dy;
|
|
||||||
int32_t advance;
|
|
||||||
struct Image* data;
|
|
||||||
} Glyph;
|
|
||||||
|
|
||||||
typedef struct Rasterizer Rasterizer;
|
typedef struct Rasterizer Rasterizer;
|
||||||
Rasterizer* lovrRasterizerCreate(struct Blob* blob, float size);
|
Rasterizer* lovrRasterizerCreate(struct Blob* blob, float size);
|
||||||
void lovrRasterizerDestroy(void* ref);
|
void lovrRasterizerDestroy(void* ref);
|
||||||
float lovrRasterizerGetSize(Rasterizer* rasterizer);
|
float lovrRasterizerGetFontSize(Rasterizer* rasterizer);
|
||||||
int lovrRasterizerGetGlyphCount(Rasterizer* rasterizer);
|
uint32_t lovrRasterizerGetGlyphCount(Rasterizer* rasterizer);
|
||||||
int lovrRasterizerGetHeight(Rasterizer* rasterizer);
|
bool lovrRasterizerHasGlyph(Rasterizer* rasterizer, uint32_t codepoint);
|
||||||
int lovrRasterizerGetAdvance(Rasterizer* rasterizer);
|
bool lovrRasterizerHasGlyphs(Rasterizer* rasterizer, const char* str, size_t length);
|
||||||
int lovrRasterizerGetAscent(Rasterizer* rasterizer);
|
float lovrRasterizerGetAscent(Rasterizer* rasterizer);
|
||||||
int lovrRasterizerGetDescent(Rasterizer* rasterizer);
|
float lovrRasterizerGetDescent(Rasterizer* rasterizer);
|
||||||
bool lovrRasterizerHasGlyph(Rasterizer* fontData, uint32_t character);
|
float lovrRasterizerGetLineGap(Rasterizer* rasterizer);
|
||||||
bool lovrRasterizerHasGlyphs(Rasterizer* fontData, const char* str);
|
float lovrRasterizerGetLeading(Rasterizer* rasterizer);
|
||||||
void lovrRasterizerLoadGlyph(Rasterizer* fontData, uint32_t character, uint32_t padding, double spread, Glyph* glyph);
|
float lovrRasterizerGetKerning(Rasterizer* rasterizer, uint32_t prev, uint32_t next);
|
||||||
int32_t lovrRasterizerGetKerning(Rasterizer* fontData, uint32_t left, uint32_t right);
|
float lovrRasterizerGetGlyphAdvance(Rasterizer* rasterizer, uint32_t codepoint);
|
||||||
void lovrRasterizerMeasure(Rasterizer* rasterizer, const char* str, size_t length, float wrap, float* width, float* lastLineWidth, float* height, uint32_t* lineCount, uint32_t* glyphCount);
|
float lovrRasterizerGetGlyphBearing(Rasterizer* rasterizer, uint32_t codepoint);
|
||||||
|
void lovrRasterizerGetGlyphBoundingBox(Rasterizer* rasterizer, uint32_t codepoint, float box[4]);
|
||||||
|
bool lovrRasterizerIsGlyphEmpty(Rasterizer* rasterizer, uint32_t codepoint);
|
||||||
|
void lovrRasterizerGetGlyphCurves(Rasterizer* rasterizer, uint32_t codepoint, void (*fn)(void* context, uint32_t degree, float* points), void* context);
|
||||||
|
|
Loading…
Reference in New Issue