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;
|
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.
|
/// A structure to model a given axis of a variable font.
|
||||||
struct FontVariationAxisParameters {
|
struct FontVariationAxisParameters {
|
||||||
|
@ -879,11 +886,60 @@ class Font {
|
||||||
BufferGlyph bufferGlyph;
|
BufferGlyph bufferGlyph;
|
||||||
bufferGlyph.start = static_cast <int32_t>(bufferCurves.size());
|
bufferGlyph.start = static_cast <int32_t>(bufferCurves.size());
|
||||||
|
|
||||||
short start = 0;
|
bool autoFixOutline = true;
|
||||||
for(int i = 0; i < face->glyph->outline.n_contours; i++){
|
if(autoFixOutline){
|
||||||
// Note: The end indices in face->glyph->outline.contours are inclusive.
|
short start = 0;
|
||||||
convertContour(bufferCurves, &face->glyph->outline, start, face->glyph->outline.contours[i], emSize);
|
int n_contours = face->glyph->outline.n_contours;
|
||||||
start = face->glyph->outline.contours[i] + 1;
|
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;
|
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
|
// This function takes a single contour (defined by firstIndex and
|
||||||
// lastIndex, both inclusive) from outline and converts it into individual
|
// lastIndex, both inclusive) from outline and converts it into individual
|
||||||
// quadratic bezier curves, which are added to the curves vector.
|
// 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){
|
void convertContour(std::vector <BufferCurve> & curves, float & direction, BBox & bb, 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;
|
|
||||||
|
|
||||||
// See https://freetype.org/freetype2/docs/glyphs/glyphs-6.html
|
// See https://freetype.org/freetype2/docs/glyphs/glyphs-6.html
|
||||||
// for a detailed description of the outline format.
|
// for a detailed description of the outline format.
|
||||||
|
@ -1000,14 +1053,11 @@ class Font {
|
||||||
return (p1.x - p0.x) * (p1.y + p0.y);
|
return (p1.x - p0.x) * (p1.y + p0.y);
|
||||||
};
|
};
|
||||||
|
|
||||||
// keep track of collected direction
|
|
||||||
float direction = 0;
|
|
||||||
|
|
||||||
// We will inject getDirection in makeCurve,
|
// We will inject getDirection in makeCurve,
|
||||||
// so anytime the curve is made it updates the direction.
|
// so anytime the curve is made it updates the direction.
|
||||||
// This is less error prone than calling it separately.
|
// This is less error prone than calling it separately.
|
||||||
// wisdom: Any error you cannot make, you will not make. :)
|
// 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;
|
BufferCurve result;
|
||||||
result.x0 = p0.x;
|
result.x0 = p0.x;
|
||||||
result.y0 = p0.y;
|
result.y0 = p0.y;
|
||||||
|
@ -1016,6 +1066,10 @@ class Font {
|
||||||
result.x2 = p2.x;
|
result.x2 = p2.x;
|
||||||
result.y2 = p2.y;
|
result.y2 = p2.y;
|
||||||
direction += getDirection(p0, p2);
|
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;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1105,18 +1159,6 @@ class Font {
|
||||||
}else{
|
}else{
|
||||||
curves.push_back(makeCurve(start, previous, first));
|
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