2
0

msdfgen.cpp 13 KB

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