msdfgen.cpp 16 KB

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