mirror of https://github.com/mgba-emu/mgba.git
Util: Add somewhat hacky SDF masking for outlined text rendering
This commit is contained in:
parent
41d25de69f
commit
c4d3cf7de5
|
@ -159,6 +159,7 @@ void mPainterDrawRectangle(struct mPainter*, int x, int y, int width, int height
|
|||
void mPainterDrawLine(struct mPainter*, int x1, int y1, int x2, int y2);
|
||||
void mPainterDrawCircle(struct mPainter*, int x, int y, int diameter);
|
||||
void mPainterDrawMask(struct mPainter*, const struct mImage* mask, int x, int y);
|
||||
void mPainterDrawSDFMask(struct mPainter*, const struct mImage* mask, int x, int y, uint8_t upper);
|
||||
|
||||
uint32_t mColorConvert(uint32_t color, enum mColorFormat from, enum mColorFormat to);
|
||||
uint32_t mImageColorConvert(uint32_t color, const struct mImage* from, enum mColorFormat to);
|
||||
|
|
|
@ -6,6 +6,8 @@ state.painter = image.newPainter(state.overlay.image)
|
|||
state.painter:loadFont(script.dir .. "/SourceSans3-Regular.otf")
|
||||
state.painter:setFontSize(9)
|
||||
state.painter:setFill(true)
|
||||
state.painter:setStrokeWidth(1)
|
||||
state.painter:setStrokeColor(0xFF000000)
|
||||
state.painter:setBlend(true)
|
||||
|
||||
state.painter:setFillColor(0xFFFFFFFF)
|
||||
|
@ -24,8 +26,9 @@ state.painter:drawText("Center right", state.width, state.height / 2, C.ALIGN.VC
|
|||
|
||||
state.painter:setFillColor(0xFF0000FF)
|
||||
state.painter:drawText("Bottom left", 0, state.height, C.ALIGN.BOTTOM | C.ALIGN.LEFT)
|
||||
state.painter:setFillColor(0xFF000000)
|
||||
state.painter:drawText("Bottom center", state.width / 2, state.height, C.ALIGN.BOTTOM | C.ALIGN.HCENTER)
|
||||
state.painter:setFillColor(0xFF808080)
|
||||
state.painter:drawText("Bottom center", state.width / 2, state.height, C.ALIGN.BOTTOM | C.ALIGN.HCENTER)
|
||||
state.painter:setStrokeColor(0xFFFFFFFF)
|
||||
state.painter:setFillColor(0xFF000000)
|
||||
state.painter:drawText("Bottom right", state.width, state.height, C.ALIGN.BOTTOM | C.ALIGN.RIGHT)
|
||||
state.overlay:update()
|
||||
|
|
|
@ -904,6 +904,40 @@ void mPainterDrawMask(struct mPainter* painter, const struct mImage* mask, int x
|
|||
}
|
||||
}
|
||||
|
||||
void mPainterDrawSDFMask(struct mPainter* painter, const struct mImage* mask, int x, int y, uint8_t upper) {
|
||||
if (mask->format != mCOLOR_L8) {
|
||||
return;
|
||||
}
|
||||
|
||||
COMPOSITE_BOUNDS_INIT(mask, painter->backing);
|
||||
|
||||
for (y = 0; y < srcRect.height; ++y) {
|
||||
uintptr_t dstPixel = (uintptr_t) PIXEL(painter->backing, dstStartX, dstStartY + y);
|
||||
uintptr_t maskPixel = (uintptr_t) PIXEL(mask, srcStartX, srcStartY + y);
|
||||
for (x = 0; x < srcRect.width; ++x, dstPixel += painter->backing->depth, maskPixel += mask->depth) {
|
||||
uint32_t color;
|
||||
GET_PIXEL(color, maskPixel, mask->depth);
|
||||
if (color >= upper) {
|
||||
color = painter->fillColor;
|
||||
} else if (color + 0x10 > upper) {
|
||||
// TODO: Make this spread customizable without too much perf hit
|
||||
color = ((color + 0x10 - upper) * 0x10) << 24;
|
||||
color |= painter->fillColor & 0x00FFFFFF;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if (painter->blend || painter->fillColor < 0xFF000000) {
|
||||
uint32_t current;
|
||||
GET_PIXEL(current, dstPixel, painter->backing->depth);
|
||||
current = mColorConvert(current, painter->backing->format, mCOLOR_ARGB8);
|
||||
color = mColorMixARGB8(color, current);
|
||||
}
|
||||
color = mColorConvert(color, mCOLOR_ARGB8, painter->backing->format);
|
||||
PUT_PIXEL(color, dstPixel, painter->backing->depth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t mColorConvert(uint32_t color, enum mColorFormat from, enum mColorFormat to) {
|
||||
if (from == to) {
|
||||
return color;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
#include FT_MODULE_H
|
||||
|
||||
#define DPI 100
|
||||
|
||||
|
@ -42,6 +43,9 @@ struct mFont* mFontOpen(const char* path) {
|
|||
if (FT_Init_FreeType(&library)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FT_Int spread = 5;
|
||||
FT_Property_Set(library, "sdf", "spread", &spread);
|
||||
}
|
||||
|
||||
FT_Face face;
|
||||
|
@ -131,6 +135,42 @@ void mPainterDrawText(struct mPainter* painter, const char* text, int x, int y,
|
|||
break;
|
||||
}
|
||||
|
||||
if (painter->strokeWidth) {
|
||||
int xx = x;
|
||||
int yy = y;
|
||||
const char* ltext = text;
|
||||
uint32_t fillColor = painter->fillColor;
|
||||
painter->fillColor = painter->strokeColor;
|
||||
while (*ltext) {
|
||||
uint32_t glyph = utf8Char((const char**) <ext, NULL);
|
||||
|
||||
if (FT_Load_Char(face, glyph, FT_LOAD_DEFAULT)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FT_Render_Glyph(face->glyph, FT_RENDER_MODE_SDF)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
struct mImage image;
|
||||
_makeTemporaryImage(&image, &face->glyph->bitmap);
|
||||
|
||||
FT_Vector kerning = {0};
|
||||
FT_Get_Kerning(face, lastGlyph, glyph, FT_KERNING_DEFAULT, &kerning);
|
||||
xx += kerning.x;
|
||||
yy += kerning.y;
|
||||
|
||||
mPainterDrawSDFMask(painter, &image, (xx >> 6) + face->glyph->bitmap_left, (yy >> 6) - face->glyph->bitmap_top, 0x70);
|
||||
xx += face->glyph->advance.x;
|
||||
yy += face->glyph->advance.y;
|
||||
|
||||
lastGlyph = glyph;
|
||||
}
|
||||
|
||||
painter->fillColor = fillColor;
|
||||
lastGlyph = 0;
|
||||
}
|
||||
|
||||
while (*text) {
|
||||
uint32_t glyph = utf8Char((const char**) &text, NULL);
|
||||
|
||||
|
|
Loading…
Reference in New Issue