1
2#include "../msdfgen.h"
3
4#include <vector>
5#include "edge-selectors.h"
6#include "contour-combiners.h"
7#include "ShapeDistanceFinder.h"
8
9namespace msdfgen {
10
11template <typename DistanceType>
12class DistancePixelConversion;
13
14template <>
15class DistancePixelConversion<double> {
16 double invRange;
17public:
18 typedef BitmapRef<float, 1> BitmapRefType;
19 inline explicit DistancePixelConversion(double range) : invRange(1/range) { }
20 inline void operator()(float *pixels, double distance) const {
21 *pixels = float(invRange*distance+.5);
22 }
23};
24
25template <>
26class DistancePixelConversion<MultiDistance> {
27 double invRange;
28public:
29 typedef BitmapRef<float, 3> BitmapRefType;
30 inline explicit DistancePixelConversion(double range) : invRange(1/range) { }
31 inline void operator()(float *pixels, const MultiDistance &distance) const {
32 pixels[0] = float(invRange*distance.r+.5);
33 pixels[1] = float(invRange*distance.g+.5);
34 pixels[2] = float(invRange*distance.b+.5);
35 }
36};
37
38template <>
39class DistancePixelConversion<MultiAndTrueDistance> {
40 double invRange;
41public:
42 typedef BitmapRef<float, 4> BitmapRefType;
43 inline explicit DistancePixelConversion(double range) : invRange(1/range) { }
44 inline void operator()(float *pixels, const MultiAndTrueDistance &distance) const {
45 pixels[0] = float(invRange*distance.r+.5);
46 pixels[1] = float(invRange*distance.g+.5);
47 pixels[2] = float(invRange*distance.b+.5);
48 pixels[3] = float(invRange*distance.a+.5);
49 }
50};
51
52template <class ContourCombiner>
53void generateDistanceField(const typename DistancePixelConversion<typename ContourCombiner::DistanceType>::BitmapRefType &output, const Shape &shape, const Projection &projection, double range) {
54 DistancePixelConversion<typename ContourCombiner::DistanceType> distancePixelConversion(range);
55#ifdef MSDFGEN_USE_OPENMP
56 #pragma omp parallel
57#endif
58 {
59 ShapeDistanceFinder<ContourCombiner> distanceFinder(shape);
60 bool rightToLeft = false;
61#ifdef MSDFGEN_USE_OPENMP
62 #pragma omp for
63#endif
64 for (int y = 0; y < output.height; ++y) {
65 int row = shape.inverseYAxis ? output.height-y-1 : y;
66 for (int col = 0; col < output.width; ++col) {
67 int x = rightToLeft ? output.width-col-1 : col;
68 Point2 p = projection.unproject(Point2(x+.5, y+.5));
69 typename ContourCombiner::DistanceType distance = distanceFinder.distance(p);
70 distancePixelConversion(output(x, row), distance);
71 }
72 rightToLeft = !rightToLeft;
73 }
74 }
75}
76
77void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, double range, const GeneratorConfig &config) {
78 if (config.overlapSupport)
79 generateDistanceField<OverlappingContourCombiner<TrueDistanceSelector> >(output, shape, projection, range);
80 else
81 generateDistanceField<SimpleContourCombiner<TrueDistanceSelector> >(output, shape, projection, range);
82}
83
84void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, double range, const GeneratorConfig &config) {
85 if (config.overlapSupport)
86 generateDistanceField<OverlappingContourCombiner<PseudoDistanceSelector> >(output, shape, projection, range);
87 else
88 generateDistanceField<SimpleContourCombiner<PseudoDistanceSelector> >(output, shape, projection, range);
89}
90
91void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config) {
92 if (config.overlapSupport)
93 generateDistanceField<OverlappingContourCombiner<MultiDistanceSelector> >(output, shape, projection, range);
94 else
95 generateDistanceField<SimpleContourCombiner<MultiDistanceSelector> >(output, shape, projection, range);
96 msdfErrorCorrection(output, shape, projection, range, config);
97}
98
99void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config) {
100 if (config.overlapSupport)
101 generateDistanceField<OverlappingContourCombiner<MultiAndTrueDistanceSelector> >(output, shape, projection, range);
102 else
103 generateDistanceField<SimpleContourCombiner<MultiAndTrueDistanceSelector> >(output, shape, projection, range);
104 msdfErrorCorrection(output, shape, projection, range, config);
105}
106
107// Legacy API
108
109void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
110 generateSDF(output, shape, Projection(scale, translate), range, GeneratorConfig(overlapSupport));
111}
112
113void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
114 generatePseudoSDF(output, shape, Projection(scale, translate), range, GeneratorConfig(overlapSupport));
115}
116
117void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig, bool overlapSupport) {
118 generateMSDF(output, shape, Projection(scale, translate), range, MSDFGeneratorConfig(overlapSupport, errorCorrectionConfig));
119}
120
121void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig, bool overlapSupport) {
122 generateMTSDF(output, shape, Projection(scale, translate), range, MSDFGeneratorConfig(overlapSupport, errorCorrectionConfig));
123}
124
125// Legacy version
126
127void generateSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate) {
128#ifdef MSDFGEN_USE_OPENMP
129 #pragma omp parallel for
130#endif
131 for (int y = 0; y < output.height; ++y) {
132 int row = shape.inverseYAxis ? output.height-y-1 : y;
133 for (int x = 0; x < output.width; ++x) {
134 double dummy;
135 Point2 p = Vector2(x+.5, y+.5)/scale-translate;
136 SignedDistance minDistance;
137 for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour)
138 for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
139 SignedDistance distance = (*edge)->signedDistance(p, dummy);
140 if (distance < minDistance)
141 minDistance = distance;
142 }
143 *output(x, row) = float(minDistance.distance/range+.5);
144 }
145 }
146}
147
148void generatePseudoSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate) {
149#ifdef MSDFGEN_USE_OPENMP
150 #pragma omp parallel for
151#endif
152 for (int y = 0; y < output.height; ++y) {
153 int row = shape.inverseYAxis ? output.height-y-1 : y;
154 for (int x = 0; x < output.width; ++x) {
155 Point2 p = Vector2(x+.5, y+.5)/scale-translate;
156 SignedDistance minDistance;
157 const EdgeHolder *nearEdge = NULL;
158 double nearParam = 0;
159 for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour)
160 for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
161 double param;
162 SignedDistance distance = (*edge)->signedDistance(p, param);
163 if (distance < minDistance) {
164 minDistance = distance;
165 nearEdge = &*edge;
166 nearParam = param;
167 }
168 }
169 if (nearEdge)
170 (*nearEdge)->distanceToPseudoDistance(minDistance, p, nearParam);
171 *output(x, row) = float(minDistance.distance/range+.5);
172 }
173 }
174}
175
176void generateMSDF_legacy(const BitmapRef<float, 3> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig) {
177#ifdef MSDFGEN_USE_OPENMP
178 #pragma omp parallel for
179#endif
180 for (int y = 0; y < output.height; ++y) {
181 int row = shape.inverseYAxis ? output.height-y-1 : y;
182 for (int x = 0; x < output.width; ++x) {
183 Point2 p = Vector2(x+.5, y+.5)/scale-translate;
184
185 struct {
186 SignedDistance minDistance;
187 const EdgeHolder *nearEdge;
188 double nearParam;
189 } r, g, b;
190 r.nearEdge = g.nearEdge = b.nearEdge = NULL;
191 r.nearParam = g.nearParam = b.nearParam = 0;
192
193 for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour)
194 for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
195 double param;
196 SignedDistance distance = (*edge)->signedDistance(p, param);
197 if ((*edge)->color&RED && distance < r.minDistance) {
198 r.minDistance = distance;
199 r.nearEdge = &*edge;
200 r.nearParam = param;
201 }
202 if ((*edge)->color&GREEN && distance < g.minDistance) {
203 g.minDistance = distance;
204 g.nearEdge = &*edge;
205 g.nearParam = param;
206 }
207 if ((*edge)->color&BLUE && distance < b.minDistance) {
208 b.minDistance = distance;
209 b.nearEdge = &*edge;
210 b.nearParam = param;
211 }
212 }
213
214 if (r.nearEdge)
215 (*r.nearEdge)->distanceToPseudoDistance(r.minDistance, p, r.nearParam);
216 if (g.nearEdge)
217 (*g.nearEdge)->distanceToPseudoDistance(g.minDistance, p, g.nearParam);
218 if (b.nearEdge)
219 (*b.nearEdge)->distanceToPseudoDistance(b.minDistance, p, b.nearParam);
220 output(x, row)[0] = float(r.minDistance.distance/range+.5);
221 output(x, row)[1] = float(g.minDistance.distance/range+.5);
222 output(x, row)[2] = float(b.minDistance.distance/range+.5);
223 }
224 }
225
226 errorCorrectionConfig.distanceCheckMode = ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;
227 msdfErrorCorrection(output, shape, Projection(scale, translate), range, MSDFGeneratorConfig(false, errorCorrectionConfig));
228}
229
230void generateMTSDF_legacy(const BitmapRef<float, 4> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig) {
231#ifdef MSDFGEN_USE_OPENMP
232 #pragma omp parallel for
233#endif
234 for (int y = 0; y < output.height; ++y) {
235 int row = shape.inverseYAxis ? output.height-y-1 : y;
236 for (int x = 0; x < output.width; ++x) {
237 Point2 p = Vector2(x+.5, y+.5)/scale-translate;
238
239 SignedDistance minDistance;
240 struct {
241 SignedDistance minDistance;
242 const EdgeHolder *nearEdge;
243 double nearParam;
244 } r, g, b;
245 r.nearEdge = g.nearEdge = b.nearEdge = NULL;
246 r.nearParam = g.nearParam = b.nearParam = 0;
247
248 for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour)
249 for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
250 double param;
251 SignedDistance distance = (*edge)->signedDistance(p, param);
252 if (distance < minDistance)
253 minDistance = distance;
254 if ((*edge)->color&RED && distance < r.minDistance) {
255 r.minDistance = distance;
256 r.nearEdge = &*edge;
257 r.nearParam = param;
258 }
259 if ((*edge)->color&GREEN && distance < g.minDistance) {
260 g.minDistance = distance;
261 g.nearEdge = &*edge;
262 g.nearParam = param;
263 }
264 if ((*edge)->color&BLUE && distance < b.minDistance) {
265 b.minDistance = distance;
266 b.nearEdge = &*edge;
267 b.nearParam = param;
268 }
269 }
270
271 if (r.nearEdge)
272 (*r.nearEdge)->distanceToPseudoDistance(r.minDistance, p, r.nearParam);
273 if (g.nearEdge)
274 (*g.nearEdge)->distanceToPseudoDistance(g.minDistance, p, g.nearParam);
275 if (b.nearEdge)
276 (*b.nearEdge)->distanceToPseudoDistance(b.minDistance, p, b.nearParam);
277 output(x, row)[0] = float(r.minDistance.distance/range+.5);
278 output(x, row)[1] = float(g.minDistance.distance/range+.5);
279 output(x, row)[2] = float(b.minDistance.distance/range+.5);
280 output(x, row)[3] = float(minDistance.distance/range+.5);
281 }
282 }
283
284 errorCorrectionConfig.distanceCheckMode = ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;
285 msdfErrorCorrection(output, shape, Projection(scale, translate), range, MSDFGeneratorConfig(false, errorCorrectionConfig));
286}
287
288}
289