msdf-atlas-gen/msdf-atlas-gen/GlyphGeometry.cpp

236 lines
7.2 KiB
C++

#include "GlyphGeometry.h"
#include <cmath>
#include <core/ShapeDistanceFinder.h>
namespace msdf_atlas {
GlyphGeometry::GlyphGeometry() : index(), codepoint(), geometryScale(), bounds(), advance(), box() { }
bool GlyphGeometry::load(msdfgen::FontHandle *font, double geometryScale, msdfgen::GlyphIndex index, bool preprocessGeometry) {
if (font && msdfgen::loadGlyph(shape, font, index, &advance) && shape.validate()) {
this->index = index.getIndex();
this->geometryScale = geometryScale;
codepoint = 0;
advance *= geometryScale;
#ifdef MSDFGEN_USE_SKIA
if (preprocessGeometry)
msdfgen::resolveShapeGeometry(shape);
#endif
shape.normalize();
bounds = shape.getBounds();
#ifdef MSDFGEN_USE_SKIA
if (!preprocessGeometry)
#endif
{
// Determine if shape is winded incorrectly and reverse it in that case
msdfgen::Point2 outerPoint(bounds.l-(bounds.r-bounds.l)-1, bounds.b-(bounds.t-bounds.b)-1);
if (msdfgen::SimpleTrueShapeDistanceFinder::oneShotDistance(shape, outerPoint) > 0) {
for (msdfgen::Contour &contour : shape.contours)
contour.reverse();
}
}
return true;
}
return false;
}
bool GlyphGeometry::load(msdfgen::FontHandle *font, double geometryScale, unicode_t codepoint, bool preprocessGeometry) {
msdfgen::GlyphIndex index;
if (msdfgen::getGlyphIndex(index, font, codepoint)) {
if (load(font, geometryScale, index, preprocessGeometry)) {
this->codepoint = codepoint;
return true;
}
}
return false;
}
void GlyphGeometry::edgeColoring(void (*fn)(msdfgen::Shape &, double, unsigned long long), double angleThreshold, unsigned long long seed) {
fn(shape, angleThreshold, seed);
}
void GlyphGeometry::wrapBox(double scale, double range, double miterLimit, bool alignOrigin) {
wrapBox(scale, range, miterLimit, alignOrigin, alignOrigin);
}
void GlyphGeometry::wrapBox(double scale, double range, double miterLimit, bool alignOriginX, bool alignOriginY) {
scale *= geometryScale;
range /= geometryScale;
box.range = range;
box.scale = scale;
if (bounds.l < bounds.r && bounds.b < bounds.t) {
double l = bounds.l, b = bounds.b, r = bounds.r, t = bounds.t;
l -= .5*range, b -= .5*range;
r += .5*range, t += .5*range;
if (miterLimit > 0)
shape.boundMiters(l, b, r, t, .5*range, miterLimit, 1);
if (alignOriginX) {
int sl = (int) floor(scale*l-.5);
int sr = (int) ceil(scale*r+.5);
box.rect.w = sr-sl;
box.translate.x = -sl/scale;
} else {
double w = scale*(r-l);
box.rect.w = (int) ceil(w)+1;
box.translate.x = -l+.5*(box.rect.w-w)/scale;
}
if (alignOriginY) {
int sb = (int) floor(scale*b-.5);
int st = (int) ceil(scale*t+.5);
box.rect.h = st-sb;
box.translate.y = -sb/scale;
} else {
double h = scale*(t-b);
box.rect.h = (int) ceil(h)+1;
box.translate.y = -b+.5*(box.rect.h-h)/scale;
}
} else {
box.rect.w = 0, box.rect.h = 0;
box.translate = msdfgen::Vector2();
}
}
void GlyphGeometry::frameBox(double scale, double range, double miterLimit, int width, int height, const double *fixedX, const double *fixedY) {
scale *= geometryScale;
range /= geometryScale;
box.range = range;
box.scale = scale;
box.rect.w = width;
box.rect.h = height;
if (fixedX && fixedY) {
box.translate.x = *fixedX/geometryScale;
box.translate.y = *fixedY/geometryScale;
} else {
double l = bounds.l, b = bounds.b, r = bounds.r, t = bounds.t;
l -= .5*range, b -= .5*range;
r += .5*range, t += .5*range;
if (miterLimit > 0)
shape.boundMiters(l, b, r, t, .5*range, miterLimit, 1);
if (fixedX)
box.translate.x = *fixedX/geometryScale;
else {
double w = scale*(r-l);
box.translate.x = -l+.5*(box.rect.w-w)/scale;
}
if (fixedY)
box.translate.y = *fixedY/geometryScale;
else {
double h = scale*(t-b);
box.translate.y = -b+.5*(box.rect.h-h)/scale;
}
}
}
void GlyphGeometry::placeBox(int x, int y) {
box.rect.x = x, box.rect.y = y;
}
void GlyphGeometry::setBoxRect(const Rectangle &rect) {
box.rect = rect;
}
int GlyphGeometry::getIndex() const {
return index;
}
msdfgen::GlyphIndex GlyphGeometry::getGlyphIndex() const {
return msdfgen::GlyphIndex(index);
}
unicode_t GlyphGeometry::getCodepoint() const {
return codepoint;
}
int GlyphGeometry::getIdentifier(GlyphIdentifierType type) const {
switch (type) {
case GlyphIdentifierType::GLYPH_INDEX:
return index;
case GlyphIdentifierType::UNICODE_CODEPOINT:
return (int) codepoint;
}
return 0;
}
double GlyphGeometry::getGeometryScale() const {
return geometryScale;
}
const msdfgen::Shape & GlyphGeometry::getShape() const {
return shape;
}
const msdfgen::Shape::Bounds & GlyphGeometry::getShapeBounds() const {
return bounds;
}
double GlyphGeometry::getAdvance() const {
return advance;
}
Rectangle GlyphGeometry::getBoxRect() const {
return box.rect;
}
void GlyphGeometry::getBoxRect(int &x, int &y, int &w, int &h) const {
x = box.rect.x, y = box.rect.y;
w = box.rect.w, h = box.rect.h;
}
void GlyphGeometry::getBoxSize(int &w, int &h) const {
w = box.rect.w, h = box.rect.h;
}
double GlyphGeometry::getBoxRange() const {
return box.range;
}
msdfgen::Projection GlyphGeometry::getBoxProjection() const {
return msdfgen::Projection(msdfgen::Vector2(box.scale), box.translate);
}
double GlyphGeometry::getBoxScale() const {
return box.scale;
}
msdfgen::Vector2 GlyphGeometry::getBoxTranslate() const {
return box.translate;
}
void GlyphGeometry::getQuadPlaneBounds(double &l, double &b, double &r, double &t) const {
if (box.rect.w > 0 && box.rect.h > 0) {
double invBoxScale = 1/box.scale;
l = geometryScale*(-box.translate.x+.5*invBoxScale);
b = geometryScale*(-box.translate.y+.5*invBoxScale);
r = geometryScale*(-box.translate.x+(box.rect.w-.5)*invBoxScale);
t = geometryScale*(-box.translate.y+(box.rect.h-.5)*invBoxScale);
} else
l = 0, b = 0, r = 0, t = 0;
}
void GlyphGeometry::getQuadAtlasBounds(double &l, double &b, double &r, double &t) const {
if (box.rect.w > 0 && box.rect.h > 0) {
l = box.rect.x+.5;
b = box.rect.y+.5;
r = box.rect.x+box.rect.w-.5;
t = box.rect.y+box.rect.h-.5;
} else
l = 0, b = 0, r = 0, t = 0;
}
bool GlyphGeometry::isWhitespace() const {
return shape.contours.empty();
}
GlyphGeometry::operator GlyphBox() const {
GlyphBox box;
box.index = index;
box.advance = advance;
getQuadPlaneBounds(box.bounds.l, box.bounds.b, box.bounds.r, box.bounds.t);
box.rect.x = this->box.rect.x, box.rect.y = this->box.rect.y, box.rect.w = this->box.rect.w, box.rect.h = this->box.rect.h;
return box;
}
}