don't flip contour for inside shapes
This commit is contained in:
parent
a3fd4a6e9b
commit
f9629b44f8
1 changed files with 67 additions and 25 deletions
|
@ -255,6 +255,13 @@ class Font {
|
|||
p3 = mat * p3;
|
||||
}
|
||||
};
|
||||
// and here a mini variant
|
||||
struct BBox {
|
||||
float xMin;
|
||||
float xMax;
|
||||
float yMin;
|
||||
float yMax;
|
||||
};
|
||||
|
||||
/// A structure to model a given axis of a variable font.
|
||||
struct FontVariationAxisParameters {
|
||||
|
@ -879,11 +886,60 @@ class Font {
|
|||
BufferGlyph bufferGlyph;
|
||||
bufferGlyph.start = static_cast <int32_t>(bufferCurves.size());
|
||||
|
||||
short start = 0;
|
||||
for(int i = 0; i < face->glyph->outline.n_contours; i++){
|
||||
// Note: The end indices in face->glyph->outline.contours are inclusive.
|
||||
convertContour(bufferCurves, &face->glyph->outline, start, face->glyph->outline.contours[i], emSize);
|
||||
start = face->glyph->outline.contours[i] + 1;
|
||||
bool autoFixOutline = true;
|
||||
if(autoFixOutline){
|
||||
short start = 0;
|
||||
int n_contours = face->glyph->outline.n_contours;
|
||||
std::vector <float> directions(n_contours, 0);
|
||||
std::vector <std::vector <BufferCurve> > curves(n_contours);
|
||||
std::vector <BBox> bbs(n_contours);
|
||||
for(int i = 0; i < n_contours; i++){
|
||||
// Note: The end indices in face->glyph->outline.contours are inclusive.
|
||||
bbs[i].xMin = FLT_MAX;
|
||||
bbs[i].xMax = -FLT_MAX;
|
||||
bbs[i].yMin = FLT_MAX;
|
||||
bbs[i].yMax = -FLT_MAX;
|
||||
convertContour(curves[i], directions[i], bbs[i], &face->glyph->outline, start, face->glyph->outline.contours[i], emSize);
|
||||
start = face->glyph->outline.contours[i] + 1;
|
||||
}
|
||||
for(int i = 0; i < n_contours; i++){
|
||||
if(directions[i] < 0){
|
||||
bool flip = true;
|
||||
for(int j = 0; j < n_contours; j++){
|
||||
if(i != j){
|
||||
bool inside = bbs[j].xMin <= bbs[i].xMin
|
||||
&& bbs[j].xMax >= bbs[i].xMax
|
||||
&& bbs[j].yMin <= bbs[i].yMin
|
||||
&& bbs[j].yMax >= bbs[i].yMax;
|
||||
if(inside){
|
||||
flip = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(flip){
|
||||
for(BufferCurve & curve : curves[i]){
|
||||
float tmp_x = curve.x0;
|
||||
float tmp_y = curve.y0;
|
||||
curve.x0 = curve.x2;
|
||||
curve.y0 = curve.y2;
|
||||
curve.x2 = tmp_x;
|
||||
curve.y2 = tmp_y;
|
||||
}
|
||||
std::reverse(curves[i].begin(), curves[i].end());
|
||||
}
|
||||
}
|
||||
bufferCurves.insert(bufferCurves.end(), curves[i].begin(), curves[i].end());
|
||||
}
|
||||
}else{
|
||||
short start = 0;
|
||||
for(int i = 0; i < face->glyph->outline.n_contours; i++){
|
||||
// Note: The end indices in face->glyph->outline.contours are inclusive.
|
||||
float direction = 0; // ignored
|
||||
BBox bb; // ignored
|
||||
convertContour(bufferCurves, direction, bb, &face->glyph->outline, start, face->glyph->outline.contours[i], emSize);
|
||||
start = face->glyph->outline.contours[i] + 1;
|
||||
}
|
||||
}
|
||||
|
||||
bufferGlyph.count = static_cast <int32_t>(bufferCurves.size()) - bufferGlyph.start;
|
||||
|
@ -906,10 +962,7 @@ class Font {
|
|||
// This function takes a single contour (defined by firstIndex and
|
||||
// lastIndex, both inclusive) from outline and converts it into individual
|
||||
// quadratic bezier curves, which are added to the curves vector.
|
||||
void convertContour(std::vector <BufferCurve> & all_curves, const FT_Outline * outline, short firstIndex, short lastIndex, float emSize){
|
||||
// we might have to flip the direction
|
||||
// so let's buffer our buffercurves in a buffer curves of buffercurves
|
||||
std::vector <BufferCurve> curves;
|
||||
void convertContour(std::vector <BufferCurve> & curves, float & direction, BBox & bb, const FT_Outline * outline, short firstIndex, short lastIndex, float emSize){
|
||||
|
||||
// See https://freetype.org/freetype2/docs/glyphs/glyphs-6.html
|
||||
// for a detailed description of the outline format.
|
||||
|
@ -1000,14 +1053,11 @@ class Font {
|
|||
return (p1.x - p0.x) * (p1.y + p0.y);
|
||||
};
|
||||
|
||||
// keep track of collected direction
|
||||
float direction = 0;
|
||||
|
||||
// We will inject getDirection in makeCurve,
|
||||
// so anytime the curve is made it updates the direction.
|
||||
// This is less error prone than calling it separately.
|
||||
// wisdom: Any error you cannot make, you will not make. :)
|
||||
auto makeCurve = [&direction, getDirection](const glm::vec2 & p0, const glm::vec2 & p1, const glm::vec2 & p2){
|
||||
auto makeCurve = [&direction, getDirection, &bb](const glm::vec2 & p0, const glm::vec2 & p1, const glm::vec2 & p2){
|
||||
BufferCurve result;
|
||||
result.x0 = p0.x;
|
||||
result.y0 = p0.y;
|
||||
|
@ -1016,6 +1066,10 @@ class Font {
|
|||
result.x2 = p2.x;
|
||||
result.y2 = p2.y;
|
||||
direction += getDirection(p0, p2);
|
||||
bb.xMin = min(bb.xMin, min(p0.x, min(p1.x, p2.x)));
|
||||
bb.xMax = max(bb.xMax, max(p0.x, max(p1.x, p2.x)));
|
||||
bb.yMin = min(bb.yMin, min(p0.y, min(p1.y, p2.y)));
|
||||
bb.yMax = max(bb.yMax, max(p0.y, max(p1.y, p2.y)));
|
||||
return result;
|
||||
};
|
||||
|
||||
|
@ -1105,18 +1159,6 @@ class Font {
|
|||
}else{
|
||||
curves.push_back(makeCurve(start, previous, first));
|
||||
}
|
||||
if(direction < 0){
|
||||
for(BufferCurve & curve : curves){
|
||||
float tmp_x = curve.x0;
|
||||
float tmp_y = curve.y0;
|
||||
curve.x0 = curve.x2;
|
||||
curve.y0 = curve.y2;
|
||||
curve.x2 = tmp_x;
|
||||
curve.y2 = tmp_y;
|
||||
}
|
||||
std::reverse(curves.begin(), curves.end());
|
||||
}
|
||||
all_curves.insert(all_curves.end(), curves.begin(), curves.end());
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue