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