Use msdfgen;

This commit is contained in:
bjorn 2017-07-15 00:18:25 +09:00
parent c518cadcf7
commit 800d07a0de
3 changed files with 74 additions and 27 deletions

View File

@ -48,7 +48,7 @@ Font* lovrFontCreate(FontData* fontData) {
} }
// Texture // Texture
TextureData* textureData = lovrTextureDataGetBlank(font->atlas.width, font->atlas.height, 0x0, FORMAT_LUMINANCE_ALPHA); TextureData* textureData = lovrTextureDataGetBlank(font->atlas.width, font->atlas.height, 0x0, FORMAT_RGB);
font->texture = lovrTextureCreate(textureData); font->texture = lovrTextureCreate(textureData);
lovrTextureSetWrap(font->texture, WRAP_CLAMP, WRAP_CLAMP); lovrTextureSetWrap(font->texture, WRAP_CLAMP, WRAP_CLAMP);
@ -120,9 +120,9 @@ void lovrFontPrint(Font* font, const char* str, mat4 transform, float wrap, Hori
float x2 = x1 + glyph->w; float x2 = x1 + glyph->w;
float y2 = y1 - glyph->h; float y2 = y1 - glyph->h;
float s1 = glyph->x / u; float s1 = glyph->x / u;
float t1 = glyph->y / v; float t1 = (glyph->y + glyph->h) / v;
float s2 = (glyph->x + glyph->w) / u; float s2 = (glyph->x + glyph->w) / u;
float t2 = (glyph->y + glyph->h) / v; float t2 = glyph->y / v;
float vertices[30] = { float vertices[30] = {
x1, y1, 0, s1, t1, x1, y1, 0, s1, t1,
@ -287,7 +287,7 @@ void lovrFontAddGlyph(Font* font, Glyph* glyph) {
// Paste glyph into texture // Paste glyph into texture
lovrGraphicsBindTexture(font->texture); lovrGraphicsBindTexture(font->texture);
glTexSubImage2D(GL_TEXTURE_2D, 0, atlas->x, atlas->y, glyph->w, glyph->h, lovrTextureFormats[FORMAT_LUMINANCE_ALPHA].format, GL_UNSIGNED_BYTE, glyph->data); glTexSubImage2D(GL_TEXTURE_2D, 0, atlas->x, atlas->y, glyph->w, glyph->h, lovrTextureFormats[FORMAT_RGB].format, GL_UNSIGNED_BYTE, glyph->data);
// Advance atlas cursor // Advance atlas cursor
atlas->x += glyph->w + atlas->padding; atlas->x += glyph->w + atlas->padding;

View File

@ -55,7 +55,7 @@ void lovrGraphicsInit() {
glfwSetTime(0); glfwSetTime(0);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glPixelStorei(GL_UNPACK_ALIGNMENT, 2); glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
#ifndef LOVR_WEB #ifndef LOVR_WEB
glfwSwapInterval(0); glfwSwapInterval(0);
glEnable(GL_LINE_SMOOTH); glEnable(GL_LINE_SMOOTH);

View File

@ -1,12 +1,65 @@
#include "loaders/font.h" #include "loaders/font.h"
#include "data/Cabin.ttf.h" #include "data/Cabin.ttf.h"
#include "util.h" #include "util.h"
#include "msdfgen-c.h"
#include <ft2build.h> #include <ft2build.h>
#include FT_FREETYPE_H #include FT_FREETYPE_H
#include FT_GLYPH_H #include FT_GLYPH_H
#include FT_OUTLINE_H
static FT_Library ft = NULL; static FT_Library ft = NULL;
typedef struct {
float x;
float y;
msShape* shape;
msContour* contour;
} ftContext;
static int ftMoveTo(const FT_Vector* to, void* userdata) {
ftContext* context = userdata;
context->contour = msShapeAddContour(context->shape);
context->x = to->x / 64.;
context->y = to->y / 64.;
return 0;
}
static int ftLineTo(const FT_Vector* to, void* userdata) {
ftContext* context = userdata;
float x = to->x / 64.;
float y = to->y / 64.;
msContourAddLinearEdge(context->contour, context->x, context->y, x, y);
context->x = x;
context->y = y;
return 0;
}
static int ftConicTo(const FT_Vector* control, const FT_Vector* to, void* userdata) {
ftContext* context = userdata;
float cx = control->x / 64.;
float cy = control->y / 64.;
float x = to->x / 64.;
float y = to->y / 64.;
msContourAddQuadraticEdge(context->contour, context->x, context->y, cx, cy, x, y);
context->x = x;
context->y = y;
return 0;
}
static int ftCubicTo(const FT_Vector* control1, const FT_Vector* control2, const FT_Vector* to, void* userdata) {
ftContext* context = userdata;
float c1x = control1->x / 64.;
float c1y = control1->y / 64.;
float c2x = control2->x / 64.;
float c2y = control2->y / 64.;
float x = to->x / 64.;
float y = to->y / 64.;
msContourAddCubicEdge(context->contour, context->x, context->y, c1x, c1y, c2x, c2y, x, y);
context->x = x;
context->y = y;
return 0;
}
FontData* lovrFontDataCreate(Blob* blob, int size) { FontData* lovrFontDataCreate(Blob* blob, int size) {
if (!ft && FT_Init_FreeType(&ft)) { if (!ft && FT_Init_FreeType(&ft)) {
error("Error initializing FreeType"); error("Error initializing FreeType");
@ -51,22 +104,23 @@ void lovrFontDataDestroy(FontData* fontData) {
void lovrFontDataLoadGlyph(FontData* fontData, uint32_t character, Glyph* glyph) { void lovrFontDataLoadGlyph(FontData* fontData, uint32_t character, Glyph* glyph) {
FT_Face face = fontData->rasterizer; FT_Face face = fontData->rasterizer;
FT_Error err = FT_Err_Ok; FT_Error err = FT_Err_Ok;
FT_Glyph slot;
FT_Bitmap bitmap;
FT_BitmapGlyph bmglyph;
FT_Glyph_Metrics* metrics; FT_Glyph_Metrics* metrics;
FT_Outline_Funcs callbacks = {
.move_to = ftMoveTo,
.line_to = ftLineTo,
.conic_to = ftConicTo,
.cubic_to = ftCubicTo
};
msShape* shape = msShapeCreate();
ftContext context = { .x = 0, .y = 0, .shape = shape, .contour = NULL };
// FreeType
err = err || FT_Load_Glyph(face, FT_Get_Char_Index(face, character), FT_LOAD_DEFAULT); err = err || FT_Load_Glyph(face, FT_Get_Char_Index(face, character), FT_LOAD_DEFAULT);
err = err || FT_Get_Glyph(face->glyph, &slot); err = err || FT_Outline_Decompose(&face->glyph->outline, &callbacks, &context);
err = err || FT_Glyph_To_Bitmap(&slot, FT_RENDER_MODE_NORMAL, 0, 1);
if (err) { if (err) {
error("Error loading glyph\n"); error("Error loading glyph\n");
} }
bmglyph = (FT_BitmapGlyph) slot;
bitmap = bmglyph->bitmap;
metrics = &face->glyph->metrics; metrics = &face->glyph->metrics;
// Initialize glyph // Initialize glyph
@ -77,20 +131,13 @@ void lovrFontDataLoadGlyph(FontData* fontData, uint32_t character, Glyph* glyph)
glyph->dx = metrics->horiBearingX >> 6; glyph->dx = metrics->horiBearingX >> 6;
glyph->dy = metrics->horiBearingY >> 6; glyph->dy = metrics->horiBearingY >> 6;
glyph->advance = metrics->horiAdvance >> 6; glyph->advance = metrics->horiAdvance >> 6;
glyph->data = malloc(glyph->w * glyph->h * 2 * sizeof(uint8_t)); glyph->data = malloc(glyph->w * glyph->h * 3 * sizeof(uint8_t));
// Transform data into an OpenGL-friendly format // Render SDF
int i = 0; msShapeNormalize(shape);
uint8_t* row = bitmap.buffer; msEdgeColoringSimple(shape, 3.0, 0);
for (int y = 0; y < glyph->h; y++) { msGenerateMSDF(glyph->data, glyph->w, glyph->h, shape, fontData->size / 8., 1, 1, -glyph->dx, glyph->h - glyph->dy);
for (int x = 0; x < glyph->w; x++) { msShapeDestroy(shape);
glyph->data[i++] = 0xff;
glyph->data[i++] = row[x];
}
row += bitmap.pitch;
}
FT_Done_Glyph(slot);
} }
int lovrFontDataGetKerning(FontData* fontData, uint32_t left, uint32_t right) { int lovrFontDataGetKerning(FontData* fontData, uint32_t left, uint32_t right) {