Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/msdfgen/core/msdfgen.cpp
9902 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 BitmapRef<float, 1> BitmapRefType;
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 BitmapRef<float, 3> BitmapRefType;
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 BitmapRef<float, 4> BitmapRefType;
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(const typename DistancePixelConversion<typename ContourCombiner::DistanceType>::BitmapRefType &output, const Shape &shape, const SDFTransformation &transformation) {
54
DistancePixelConversion<typename ContourCombiner::DistanceType> distancePixelConversion(transformation.distanceMapping);
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 = transformation.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
77
void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, const SDFTransformation &transformation, const GeneratorConfig &config) {
78
if (config.overlapSupport)
79
generateDistanceField<OverlappingContourCombiner<TrueDistanceSelector> >(output, shape, transformation);
80
else
81
generateDistanceField<SimpleContourCombiner<TrueDistanceSelector> >(output, shape, transformation);
82
}
83
84
void generatePSDF(const BitmapRef<float, 1> &output, const Shape &shape, const SDFTransformation &transformation, const GeneratorConfig &config) {
85
if (config.overlapSupport)
86
generateDistanceField<OverlappingContourCombiner<PerpendicularDistanceSelector> >(output, shape, transformation);
87
else
88
generateDistanceField<SimpleContourCombiner<PerpendicularDistanceSelector> >(output, shape, transformation);
89
}
90
91
void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config) {
92
if (config.overlapSupport)
93
generateDistanceField<OverlappingContourCombiner<MultiDistanceSelector> >(output, shape, transformation);
94
else
95
generateDistanceField<SimpleContourCombiner<MultiDistanceSelector> >(output, shape, transformation);
96
msdfErrorCorrection(output, shape, transformation, config);
97
}
98
99
void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config) {
100
if (config.overlapSupport)
101
generateDistanceField<OverlappingContourCombiner<MultiAndTrueDistanceSelector> >(output, shape, transformation);
102
else
103
generateDistanceField<SimpleContourCombiner<MultiAndTrueDistanceSelector> >(output, shape, transformation);
104
msdfErrorCorrection(output, shape, transformation, config);
105
}
106
107
void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config) {
108
if (config.overlapSupport)
109
generateDistanceField<OverlappingContourCombiner<TrueDistanceSelector> >(output, shape, SDFTransformation(projection, range));
110
else
111
generateDistanceField<SimpleContourCombiner<TrueDistanceSelector> >(output, shape, SDFTransformation(projection, range));
112
}
113
114
void generatePSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config) {
115
if (config.overlapSupport)
116
generateDistanceField<OverlappingContourCombiner<PerpendicularDistanceSelector> >(output, shape, SDFTransformation(projection, range));
117
else
118
generateDistanceField<SimpleContourCombiner<PerpendicularDistanceSelector> >(output, shape, SDFTransformation(projection, range));
119
}
120
121
void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config) {
122
if (config.overlapSupport)
123
generateDistanceField<OverlappingContourCombiner<MultiDistanceSelector> >(output, shape, SDFTransformation(projection, range));
124
else
125
generateDistanceField<SimpleContourCombiner<MultiDistanceSelector> >(output, shape, SDFTransformation(projection, range));
126
msdfErrorCorrection(output, shape, SDFTransformation(projection, range), config);
127
}
128
129
void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config) {
130
if (config.overlapSupport)
131
generateDistanceField<OverlappingContourCombiner<MultiAndTrueDistanceSelector> >(output, shape, SDFTransformation(projection, range));
132
else
133
generateDistanceField<SimpleContourCombiner<MultiAndTrueDistanceSelector> >(output, shape, SDFTransformation(projection, range));
134
msdfErrorCorrection(output, shape, SDFTransformation(projection, range), config);
135
}
136
137
// Legacy API
138
139
void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config) {
140
generatePSDF(output, shape, SDFTransformation(projection, range), config);
141
}
142
143
void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
144
generateSDF(output, shape, Projection(scale, translate), range, GeneratorConfig(overlapSupport));
145
}
146
147
void generatePSDF(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
148
generatePSDF(output, shape, Projection(scale, translate), range, GeneratorConfig(overlapSupport));
149
}
150
151
void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
152
generatePSDF(output, shape, Projection(scale, translate), range, GeneratorConfig(overlapSupport));
153
}
154
155
void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig, bool overlapSupport) {
156
generateMSDF(output, shape, Projection(scale, translate), range, MSDFGeneratorConfig(overlapSupport, errorCorrectionConfig));
157
}
158
159
void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig, bool overlapSupport) {
160
generateMTSDF(output, shape, Projection(scale, translate), range, MSDFGeneratorConfig(overlapSupport, errorCorrectionConfig));
161
}
162
163
// Legacy version
164
165
void generateSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate) {
166
DistanceMapping distanceMapping(range);
167
#ifdef MSDFGEN_USE_OPENMP
168
#pragma omp parallel for
169
#endif
170
for (int y = 0; y < output.height; ++y) {
171
int row = shape.inverseYAxis ? output.height-y-1 : y;
172
for (int x = 0; x < output.width; ++x) {
173
double dummy;
174
Point2 p = Vector2(x+.5, y+.5)/scale-translate;
175
SignedDistance minDistance;
176
for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour)
177
for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
178
SignedDistance distance = (*edge)->signedDistance(p, dummy);
179
if (distance < minDistance)
180
minDistance = distance;
181
}
182
*output(x, row) = float(distanceMapping(minDistance.distance));
183
}
184
}
185
}
186
187
void generatePSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate) {
188
DistanceMapping distanceMapping(range);
189
#ifdef MSDFGEN_USE_OPENMP
190
#pragma omp parallel for
191
#endif
192
for (int y = 0; y < output.height; ++y) {
193
int row = shape.inverseYAxis ? output.height-y-1 : y;
194
for (int x = 0; x < output.width; ++x) {
195
Point2 p = Vector2(x+.5, y+.5)/scale-translate;
196
SignedDistance minDistance;
197
const EdgeHolder *nearEdge = NULL;
198
double nearParam = 0;
199
for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour)
200
for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
201
double param;
202
SignedDistance distance = (*edge)->signedDistance(p, param);
203
if (distance < minDistance) {
204
minDistance = distance;
205
nearEdge = &*edge;
206
nearParam = param;
207
}
208
}
209
if (nearEdge)
210
(*nearEdge)->distanceToPerpendicularDistance(minDistance, p, nearParam);
211
*output(x, row) = float(distanceMapping(minDistance.distance));
212
}
213
}
214
}
215
216
void generatePseudoSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate) {
217
generatePSDF_legacy(output, shape, range, scale, translate);
218
}
219
220
void generateMSDF_legacy(const BitmapRef<float, 3> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig) {
221
DistanceMapping distanceMapping(range);
222
#ifdef MSDFGEN_USE_OPENMP
223
#pragma omp parallel for
224
#endif
225
for (int y = 0; y < output.height; ++y) {
226
int row = shape.inverseYAxis ? output.height-y-1 : y;
227
for (int x = 0; x < output.width; ++x) {
228
Point2 p = Vector2(x+.5, y+.5)/scale-translate;
229
230
struct {
231
SignedDistance minDistance;
232
const EdgeHolder *nearEdge;
233
double nearParam;
234
} r, g, b;
235
r.nearEdge = g.nearEdge = b.nearEdge = NULL;
236
r.nearParam = g.nearParam = b.nearParam = 0;
237
238
for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour)
239
for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
240
double param;
241
SignedDistance distance = (*edge)->signedDistance(p, param);
242
if ((*edge)->color&RED && distance < r.minDistance) {
243
r.minDistance = distance;
244
r.nearEdge = &*edge;
245
r.nearParam = param;
246
}
247
if ((*edge)->color&GREEN && distance < g.minDistance) {
248
g.minDistance = distance;
249
g.nearEdge = &*edge;
250
g.nearParam = param;
251
}
252
if ((*edge)->color&BLUE && distance < b.minDistance) {
253
b.minDistance = distance;
254
b.nearEdge = &*edge;
255
b.nearParam = param;
256
}
257
}
258
259
if (r.nearEdge)
260
(*r.nearEdge)->distanceToPerpendicularDistance(r.minDistance, p, r.nearParam);
261
if (g.nearEdge)
262
(*g.nearEdge)->distanceToPerpendicularDistance(g.minDistance, p, g.nearParam);
263
if (b.nearEdge)
264
(*b.nearEdge)->distanceToPerpendicularDistance(b.minDistance, p, b.nearParam);
265
output(x, row)[0] = float(distanceMapping(r.minDistance.distance));
266
output(x, row)[1] = float(distanceMapping(g.minDistance.distance));
267
output(x, row)[2] = float(distanceMapping(b.minDistance.distance));
268
}
269
}
270
271
errorCorrectionConfig.distanceCheckMode = ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;
272
msdfErrorCorrection(output, shape, Projection(scale, translate), range, MSDFGeneratorConfig(false, errorCorrectionConfig));
273
}
274
275
void generateMTSDF_legacy(const BitmapRef<float, 4> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig) {
276
DistanceMapping distanceMapping(range);
277
#ifdef MSDFGEN_USE_OPENMP
278
#pragma omp parallel for
279
#endif
280
for (int y = 0; y < output.height; ++y) {
281
int row = shape.inverseYAxis ? output.height-y-1 : y;
282
for (int x = 0; x < output.width; ++x) {
283
Point2 p = Vector2(x+.5, y+.5)/scale-translate;
284
285
SignedDistance minDistance;
286
struct {
287
SignedDistance minDistance;
288
const EdgeHolder *nearEdge;
289
double nearParam;
290
} r, g, b;
291
r.nearEdge = g.nearEdge = b.nearEdge = NULL;
292
r.nearParam = g.nearParam = b.nearParam = 0;
293
294
for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour)
295
for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
296
double param;
297
SignedDistance distance = (*edge)->signedDistance(p, param);
298
if (distance < minDistance)
299
minDistance = distance;
300
if ((*edge)->color&RED && distance < r.minDistance) {
301
r.minDistance = distance;
302
r.nearEdge = &*edge;
303
r.nearParam = param;
304
}
305
if ((*edge)->color&GREEN && distance < g.minDistance) {
306
g.minDistance = distance;
307
g.nearEdge = &*edge;
308
g.nearParam = param;
309
}
310
if ((*edge)->color&BLUE && distance < b.minDistance) {
311
b.minDistance = distance;
312
b.nearEdge = &*edge;
313
b.nearParam = param;
314
}
315
}
316
317
if (r.nearEdge)
318
(*r.nearEdge)->distanceToPerpendicularDistance(r.minDistance, p, r.nearParam);
319
if (g.nearEdge)
320
(*g.nearEdge)->distanceToPerpendicularDistance(g.minDistance, p, g.nearParam);
321
if (b.nearEdge)
322
(*b.nearEdge)->distanceToPerpendicularDistance(b.minDistance, p, b.nearParam);
323
output(x, row)[0] = float(distanceMapping(r.minDistance.distance));
324
output(x, row)[1] = float(distanceMapping(g.minDistance.distance));
325
output(x, row)[2] = float(distanceMapping(b.minDistance.distance));
326
output(x, row)[3] = float(distanceMapping(minDistance.distance));
327
}
328
}
329
330
errorCorrectionConfig.distanceCheckMode = ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;
331
msdfErrorCorrection(output, shape, Projection(scale, translate), range, MSDFGeneratorConfig(false, errorCorrectionConfig));
332
}
333
334
}
335
336