Font improvements
?border and ?outline blend nicer when applied to font glyphs
This commit is contained in:
parent
d08b3c3b22
commit
f2e64e1752
@ -141,10 +141,9 @@ public:
|
|||||||
Color& operator+=(Color const& c);
|
Color& operator+=(Color const& c);
|
||||||
Color& operator*=(Color const& c);
|
Color& operator*=(Color const& c);
|
||||||
|
|
||||||
private:
|
|
||||||
static float toLinear(float in);
|
static float toLinear(float in);
|
||||||
static float fromLinear(float in);
|
static float fromLinear(float in);
|
||||||
|
private:
|
||||||
Vec4F m_data;
|
Vec4F m_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -87,10 +87,10 @@ unsigned Font::width(String::Char c) {
|
|||||||
|
|
||||||
Image Font::render(String::Char c) {
|
Image Font::render(String::Char c) {
|
||||||
if (!m_fontImpl)
|
if (!m_fontImpl)
|
||||||
throw FontException("Font::render called on uninitialzed font.");
|
throw FontException("Font::render called on uninitialized font.");
|
||||||
|
|
||||||
FT_UInt glyph_index = FT_Get_Char_Index(m_fontImpl->face, c);
|
FT_UInt glyph_index = FT_Get_Char_Index(m_fontImpl->face, c);
|
||||||
if (FT_Load_Glyph(m_fontImpl->face, glyph_index, FT_LOAD_DEFAULT) != 0)
|
if (FT_Load_Glyph(m_fontImpl->face, glyph_index, FT_LOAD_FORCE_AUTOHINT) != 0)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
/* convert to an anti-aliased bitmap */
|
/* convert to an anti-aliased bitmap */
|
||||||
|
@ -224,6 +224,7 @@ ImageOperation imageOperationFromString(String const& string) {
|
|||||||
else
|
else
|
||||||
operation.endColor = operation.startColor;
|
operation.endColor = operation.startColor;
|
||||||
operation.outlineOnly = type == "outline";
|
operation.outlineOnly = type == "outline";
|
||||||
|
operation.includeTransparent = false; // Currently just here for anti-aliased fonts
|
||||||
|
|
||||||
return operation;
|
return operation;
|
||||||
|
|
||||||
@ -476,7 +477,8 @@ Image processImageOperations(List<ImageOperation> const& operations, Image image
|
|||||||
|
|
||||||
borderImage.forEachPixel([&op, &image, &borderImageSize](int x, int y, Vec4B& pixel) {
|
borderImage.forEachPixel([&op, &image, &borderImageSize](int x, int y, Vec4B& pixel) {
|
||||||
int pixels = op->pixels;
|
int pixels = op->pixels;
|
||||||
if (pixel[3] == 0) {
|
bool includeTransparent = op->includeTransparent;
|
||||||
|
if (pixel[3] == 0 || (includeTransparent && pixel[3] != 255)) {
|
||||||
int dist = std::numeric_limits<int>::max();
|
int dist = std::numeric_limits<int>::max();
|
||||||
for (int j = -pixels; j < pixels + 1; j++) {
|
for (int j = -pixels; j < pixels + 1; j++) {
|
||||||
for (int i = -pixels; i < pixels + 1; i++) {
|
for (int i = -pixels; i < pixels + 1; i++) {
|
||||||
@ -493,7 +495,21 @@ Image processImageOperations(List<ImageOperation> const& operations, Image image
|
|||||||
|
|
||||||
if (dist < std::numeric_limits<int>::max()) {
|
if (dist < std::numeric_limits<int>::max()) {
|
||||||
float percent = (dist - 1) / (2.0f * pixels - 1);
|
float percent = (dist - 1) / (2.0f * pixels - 1);
|
||||||
pixel = Vec4B(Vec4F(op->startColor) * (1 - percent) + Vec4F(op->endColor) * percent);
|
Vec4F color = (Vec4F(op->startColor) * ((1.0f - percent) / 255.0f)) + (Vec4F(op->endColor) * (percent / 255.0f));
|
||||||
|
color.clamp(0.0f, 1.0f);
|
||||||
|
if (pixel[3] != 0) {
|
||||||
|
float pixelA = byteToFloat(pixel[3]);
|
||||||
|
if (op->outlineOnly)
|
||||||
|
color[3] *= (1.0f - pixelA);
|
||||||
|
else {
|
||||||
|
float colorA = pixelA * (1.0f - color[3]);
|
||||||
|
color[0] = Color::fromLinear((Color::toLinear(color[0]) * colorA) + (Color::toLinear(byteToFloat(pixel[0])) * pixelA));
|
||||||
|
color[1] = Color::fromLinear((Color::toLinear(color[1]) * colorA) + (Color::toLinear(byteToFloat(pixel[1])) * pixelA));
|
||||||
|
color[2] = Color::fromLinear((Color::toLinear(color[2]) * colorA) + (Color::toLinear(byteToFloat(pixel[2])) * pixelA));
|
||||||
|
color[3] += colorA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pixel = Vec4B(color.piecewiseMultiply(Vec4F::filled(255.0f)));
|
||||||
}
|
}
|
||||||
} else if (op->outlineOnly) {
|
} else if (op->outlineOnly) {
|
||||||
pixel = Vec4B(0, 0, 0, 0);
|
pixel = Vec4B(0, 0, 0, 0);
|
||||||
|
@ -102,6 +102,7 @@ struct BorderImageOperation {
|
|||||||
Vec4B startColor;
|
Vec4B startColor;
|
||||||
Vec4B endColor;
|
Vec4B endColor;
|
||||||
bool outlineOnly;
|
bool outlineOnly;
|
||||||
|
bool includeTransparent;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ScaleImageOperation {
|
struct ScaleImageOperation {
|
||||||
|
@ -21,7 +21,12 @@ const FontTextureGroup::GlyphTexture& FontTextureGroup::glyphTexture(String::Cha
|
|||||||
Image image = m_font->render(c);
|
Image image = m_font->render(c);
|
||||||
if (!processingDirectives.empty()) {
|
if (!processingDirectives.empty()) {
|
||||||
Vec2F preSize = Vec2F(image.size());
|
Vec2F preSize = Vec2F(image.size());
|
||||||
image = processImageOperations(parseImageOperations(processingDirectives), image);
|
auto imageOperations = parseImageOperations(processingDirectives);
|
||||||
|
for (auto& imageOp : imageOperations) {
|
||||||
|
if (auto border = imageOp.ptr<BorderImageOperation>())
|
||||||
|
border->includeTransparent = true;
|
||||||
|
}
|
||||||
|
image = processImageOperations(imageOperations, image);
|
||||||
res.first->second.processingOffset = preSize - Vec2F(image.size());
|
res.first->second.processingOffset = preSize - Vec2F(image.size());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
Loading…
Reference in New Issue
Block a user