Skip to content

Commit 9d22335

Browse files
committed
Skia integration - preprocessing of shape geometry
1 parent fe910c8 commit 9d22335

File tree

294 files changed

+51516
-57
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

294 files changed

+51516
-57
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
include/** linguist-vendored
33
lib/** linguist-vendored
44
freetype/** linguist-vendored
5+
skia/** linguist-vendored

.gitignore

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
Debug/
2-
Release/
3-
Release OpenMP/
4-
Debug Library/
5-
Release Library/
6-
Release Library OpenMP/
7-
x86/
8-
x64/
1+
/Debug/
2+
/Release/
3+
/Release OpenMP/
4+
/Debug Library/
5+
/Release Library/
6+
/Release Library OpenMP/
7+
/x86/
8+
/x64/
99
.vs/
1010
*.exe
1111
*.zip
@@ -17,9 +17,11 @@ x64/
1717
*.suo
1818
*.VC.opendb
1919
*.VC.db
20-
bin/*.lib
20+
/bin/*.lib
2121
output.png
2222
render.png
2323
out/
2424
build/
2525
build_xcode/
26+
skia/win32/
27+
skia/win64/

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,23 @@
11

2+
## Version 1.8 (2020-10-17)
3+
4+
- Integrated the Skia library into the project, which is used to preprocess the shape geometry and eliminate any self-intersections and other irregularities previously unsupported by the software
5+
- The scanline pass and overlapping contour mode is made obsolete by this step and has been disabled by default. The preprocess step can be disabled by the new `-nopreprocess` switch and the former enabled by `-scanline` and `-overlap` respectively.
6+
- The project can be built without the Skia library, forgoing the geometry preprocessing feature. This is controlled by the macro definition `MSDFGEN_USE_SKIA`
7+
- Significantly improved performance of the core algorithm by reusing results from previously computed pixels
8+
- Introduced an additional error correction routine which eliminates MSDF artifacts by analytically predicting results of bilinear interpolation
9+
- Added the possibility to load font glyphs by their index rather than a Unicode value (use the prefix `g` before the character code in `-font` argument)
10+
- Added `-distanceshift` argument that can be used to adjust the center of the distance range in the output distance field
11+
- Fixed several errors in the evaluation of curve distances
12+
- Fixed an issue with paths containing convergent corners (those whose inner angle is zero)
13+
- The algorithm for pseudo-distance computation slightly changed, fixing certain rare edge cases and improving consistency
14+
- Added the ability to supply own `FT_Face` handle to the msdfgen library
15+
- Minor refactor of the core algorithm
16+
17+
### Version 1.7.1 (2020-03-09)
18+
19+
- Fixed an edge case bug in scanline rasterization
20+
221
## Version 1.7 (2020-03-07)
322

423
- Added `mtsdf` mode - a combination of `msdf` with `sdf` in the alpha channel

CMakeLists.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
cmake_minimum_required(VERSION 3.10)
22

3-
project(msdfgen VERSION 1.7.1 LANGUAGES CXX)
3+
project(msdfgen VERSION 1.8 LANGUAGES CXX)
44
option(MSDFGEN_BUILD_MSDFGEN_STANDALONE "Build the msdfgen standalone executable" ON)
55
option(MSDFGEN_USE_OPENMP "Build with OpenMP support for multithreaded code" OFF)
66
option(MSDFGEN_USE_CPP11 "Build with C++11 enabled" ON)
7+
option(MSDFGEN_USE_SKIA "Build with the Skia library" OFF)
78
option(FREETYPE_WITH_PNG "Link libpng and zlib because FreeType is configured to require it" OFF)
89
option(FREETYPE_WITH_HARFBUZZ "Link HarfBuzz because FreeType is configured to require it" OFF)
910

@@ -71,6 +72,12 @@ if(MSDFGEN_USE_OPENMP)
7172
target_compile_definitions(msdfgen PRIVATE MSDFGEN_USE_OPENMP)
7273
endif()
7374

75+
if(MSDFGEN_USE_SKIA)
76+
find_package(Skia REQUIRED)
77+
target_link_libraries(msdfgen-ext PRIVATE Skia::Skia)
78+
target_compile_definitions(msdfgen-ext PUBLIC MSDFGEN_USE_SKIA)
79+
endif()
80+
7481
add_library(msdfgen-ext ${msdfgen-ext_SOURCES} ${msdfgen-ext_PUBLIC_HEADERS} ${msdfgen-ext_PRIVATE_HEADERS} "./msdfgen-ext.h")
7582
add_library(msdfgen::msdfgen-ext ALIAS msdfgen-ext)
7683
set_target_properties(msdfgen-ext PROPERTIES

Msdfgen.aps

34.3 KB
Binary file not shown.

Msdfgen.rc

1.92 KB
Binary file not shown.

Msdfgen.vcxproj

Lines changed: 38 additions & 36 deletions
Large diffs are not rendered by default.

Msdfgen.vcxproj.filters

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@
120120
<ClInclude Include="core\msdf-edge-artifact-patcher.h">
121121
<Filter>Core</Filter>
122122
</ClInclude>
123+
<ClInclude Include="ext\resolve-shape-geometry.h">
124+
<Filter>Extensions</Filter>
125+
</ClInclude>
123126
</ItemGroup>
124127
<ItemGroup>
125128
<ClCompile Include="main.cpp">
@@ -200,6 +203,9 @@
200203
<ClCompile Include="core\msdf-edge-artifact-patcher.cpp">
201204
<Filter>Core</Filter>
202205
</ClCompile>
206+
<ClCompile Include="ext\resolve-shape-geometry.cpp">
207+
<Filter>Extensions</Filter>
208+
</ClCompile>
203209
</ItemGroup>
204210
<ItemGroup>
205211
<ResourceCompile Include="Msdfgen.rc">

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ Extensions contain utilities for loading fonts and SVG files, as well as saving
2626
Those are exposed by the [msdfgen-ext.h](msdfgen-ext.h) header. This module uses
2727
[FreeType](http://www.freetype.org/),
2828
[TinyXML2](http://www.grinninglizard.com/tinyxml2/),
29-
and [LodePNG](http://lodev.org/lodepng/).
29+
[LodePNG](http://lodev.org/lodepng/),
30+
and (optionally) [Skia](https://skia.org/).
3031

3132
Additionally, there is the [main.cpp](main.cpp), which wraps the functionality into
3233
a comprehensive standalone console program. To start using the program immediately,

ext/resolve-shape-geometry.cpp

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
2+
#include "resolve-shape-geometry.h"
3+
4+
#ifdef MSDFGEN_USE_SKIA
5+
6+
#include <core/SkPath.h>
7+
#include <pathops/SkPathOps.h>
8+
#include "../core/Vector2.h"
9+
#include "../core/edge-segments.h"
10+
#include "../core/Contour.h"
11+
12+
#ifdef _WIN32
13+
#pragma comment(lib, "skia.lib")
14+
#endif
15+
16+
namespace msdfgen {
17+
18+
SkPoint pointToSkiaPoint(Point2 p) {
19+
return SkPoint::Make((SkScalar) p.x, (SkScalar) p.y);
20+
}
21+
22+
Point2 pointFromSkiaPoint(const SkPoint p) {
23+
return Point2((double) p.x(), (double) p.y());
24+
}
25+
26+
void shapeToSkiaPath(SkPath &skPath, const Shape &shape) {
27+
for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
28+
if (!contour->edges.empty()) {
29+
skPath.moveTo(pointToSkiaPoint(contour->edges.front()->point(0)));
30+
for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
31+
{
32+
const LinearSegment *linearSegment = dynamic_cast<const LinearSegment *>(&**edge);
33+
if (linearSegment)
34+
skPath.lineTo(pointToSkiaPoint(linearSegment->p[1]));
35+
} {
36+
const QuadraticSegment *quadraticSegment = dynamic_cast<const QuadraticSegment *>(&**edge);
37+
if (quadraticSegment)
38+
skPath.quadTo(pointToSkiaPoint(quadraticSegment->p[1]), pointToSkiaPoint(quadraticSegment->p[2]));
39+
} {
40+
const CubicSegment *cubicSegment = dynamic_cast<const CubicSegment *>(&**edge);
41+
if (cubicSegment)
42+
skPath.cubicTo(pointToSkiaPoint(cubicSegment->p[1]), pointToSkiaPoint(cubicSegment->p[2]), pointToSkiaPoint(cubicSegment->p[3]));
43+
}
44+
}
45+
}
46+
}
47+
}
48+
49+
void shapeFromSkiaPath(Shape &shape, const SkPath &skPath) {
50+
shape.contours.clear();
51+
Contour *contour = &shape.addContour();
52+
SkPath::Iter pathIterator(skPath, true);
53+
SkPoint edgePoints[4];
54+
for (SkPath::Verb op; (op = pathIterator.next(edgePoints)) != SkPath::kDone_Verb;) {
55+
switch (op) {
56+
case SkPath::kMove_Verb:
57+
if (!contour->edges.empty())
58+
contour = &shape.addContour();
59+
break;
60+
case SkPath::kLine_Verb:
61+
contour->addEdge(new LinearSegment(pointFromSkiaPoint(edgePoints[0]), pointFromSkiaPoint(edgePoints[1])));
62+
break;
63+
case SkPath::kQuad_Verb:
64+
contour->addEdge(new QuadraticSegment(pointFromSkiaPoint(edgePoints[0]), pointFromSkiaPoint(edgePoints[1]), pointFromSkiaPoint(edgePoints[2])));
65+
break;
66+
case SkPath::kCubic_Verb:
67+
contour->addEdge(new CubicSegment(pointFromSkiaPoint(edgePoints[0]), pointFromSkiaPoint(edgePoints[1]), pointFromSkiaPoint(edgePoints[2]), pointFromSkiaPoint(edgePoints[3])));
68+
break;
69+
default:;
70+
}
71+
}
72+
if (contour->edges.empty())
73+
shape.contours.pop_back();
74+
}
75+
76+
bool resolveShapeGeometry(Shape &shape) {
77+
SkPath skPath;
78+
shapeToSkiaPath(skPath, shape);
79+
if (!Simplify(skPath, &skPath))
80+
return false;
81+
// Skia's AsWinding doesn't seem to work for unknown reasons
82+
shapeFromSkiaPath(shape, skPath);
83+
shape.orientContours();
84+
return true;
85+
}
86+
87+
}
88+
89+
#endif

0 commit comments

Comments
 (0)