diff --git a/src/graphics/font.c b/src/graphics/font.c index a0b4152e..c991ecce 100644 --- a/src/graphics/font.c +++ b/src/graphics/font.c @@ -48,7 +48,7 @@ Font* lovrFontCreate(FontData* fontData) { } // 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); 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 y2 = y1 - glyph->h; 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 t2 = (glyph->y + glyph->h) / v; + float t2 = glyph->y / v; float vertices[30] = { x1, y1, 0, s1, t1, @@ -287,7 +287,7 @@ void lovrFontAddGlyph(Font* font, Glyph* glyph) { // Paste glyph into 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 atlas->x += glyph->w + atlas->padding; diff --git a/src/graphics/graphics.c b/src/graphics/graphics.c index 922ebd38..e4330aa2 100644 --- a/src/graphics/graphics.c +++ b/src/graphics/graphics.c @@ -55,7 +55,7 @@ void lovrGraphicsInit() { glfwSetTime(0); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glPixelStorei(GL_UNPACK_ALIGNMENT, 2); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); #ifndef LOVR_WEB glfwSwapInterval(0); glEnable(GL_LINE_SMOOTH); diff --git a/src/loaders/font.c b/src/loaders/font.c index a02d0421..5768f2c7 100644 --- a/src/loaders/font.c +++ b/src/loaders/font.c @@ -1,12 +1,65 @@ #include "loaders/font.h" #include "data/Cabin.ttf.h" #include "util.h" +#include "msdfgen-c.h" #include #include FT_FREETYPE_H #include FT_GLYPH_H +#include FT_OUTLINE_H 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) { if (!ft && FT_Init_FreeType(&ft)) { error("Error initializing FreeType"); @@ -51,22 +104,23 @@ void lovrFontDataDestroy(FontData* fontData) { void lovrFontDataLoadGlyph(FontData* fontData, uint32_t character, Glyph* glyph) { FT_Face face = fontData->rasterizer; FT_Error err = FT_Err_Ok; - FT_Glyph slot; - FT_Bitmap bitmap; - FT_BitmapGlyph bmglyph; 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_Get_Glyph(face->glyph, &slot); - err = err || FT_Glyph_To_Bitmap(&slot, FT_RENDER_MODE_NORMAL, 0, 1); - + err = err || FT_Outline_Decompose(&face->glyph->outline, &callbacks, &context); if (err) { error("Error loading glyph\n"); } - bmglyph = (FT_BitmapGlyph) slot; - bitmap = bmglyph->bitmap; metrics = &face->glyph->metrics; // Initialize glyph @@ -77,20 +131,13 @@ void lovrFontDataLoadGlyph(FontData* fontData, uint32_t character, Glyph* glyph) glyph->dx = metrics->horiBearingX >> 6; glyph->dy = metrics->horiBearingY >> 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 - int i = 0; - uint8_t* row = bitmap.buffer; - for (int y = 0; y < glyph->h; y++) { - for (int x = 0; x < glyph->w; x++) { - glyph->data[i++] = 0xff; - glyph->data[i++] = row[x]; - } - row += bitmap.pitch; - } - - FT_Done_Glyph(slot); + // Render SDF + msShapeNormalize(shape); + msEdgeColoringSimple(shape, 3.0, 0); + msGenerateMSDF(glyph->data, glyph->w, glyph->h, shape, fontData->size / 8., 1, 1, -glyph->dx, glyph->h - glyph->dy); + msShapeDestroy(shape); } int lovrFontDataGetKerning(FontData* fontData, uint32_t left, uint32_t right) {