msdfgen.cpp 13 KB

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