Path: blob/master/thirdparty/msdfgen/core/msdfgen.cpp
20920 views
1#include "../msdfgen.h"23#include <vector>4#include "edge-selectors.h"5#include "contour-combiners.h"6#include "ShapeDistanceFinder.h"78namespace msdfgen {910template <typename DistanceType>11class DistancePixelConversion;1213template <>14class DistancePixelConversion<double> {15DistanceMapping mapping;16public:17typedef BitmapSection<float, 1> BitmapSectionType;18inline explicit DistancePixelConversion(DistanceMapping mapping) : mapping(mapping) { }19inline void operator()(float *pixels, double distance) const {20*pixels = float(mapping(distance));21}22};2324template <>25class DistancePixelConversion<MultiDistance> {26DistanceMapping mapping;27public:28typedef BitmapSection<float, 3> BitmapSectionType;29inline explicit DistancePixelConversion(DistanceMapping mapping) : mapping(mapping) { }30inline void operator()(float *pixels, const MultiDistance &distance) const {31pixels[0] = float(mapping(distance.r));32pixels[1] = float(mapping(distance.g));33pixels[2] = float(mapping(distance.b));34}35};3637template <>38class DistancePixelConversion<MultiAndTrueDistance> {39DistanceMapping mapping;40public:41typedef BitmapSection<float, 4> BitmapSectionType;42inline explicit DistancePixelConversion(DistanceMapping mapping) : mapping(mapping) { }43inline void operator()(float *pixels, const MultiAndTrueDistance &distance) const {44pixels[0] = float(mapping(distance.r));45pixels[1] = float(mapping(distance.g));46pixels[2] = float(mapping(distance.b));47pixels[3] = float(mapping(distance.a));48}49};5051template <class ContourCombiner>52void generateDistanceField(typename DistancePixelConversion<typename ContourCombiner::DistanceType>::BitmapSectionType output, const Shape &shape, const SDFTransformation &transformation) {53DistancePixelConversion<typename ContourCombiner::DistanceType> distancePixelConversion(transformation.distanceMapping);54output.reorient(shape.getYAxisOrientation());55#ifdef MSDFGEN_USE_OPENMP56#pragma omp parallel57#endif58{59ShapeDistanceFinder<ContourCombiner> distanceFinder(shape);60int xDirection = 1;61#ifdef MSDFGEN_USE_OPENMP62#pragma omp for63#endif64for (int y = 0; y < output.height; ++y) {65int x = xDirection < 0 ? output.width-1 : 0;66for (int col = 0; col < output.width; ++col) {67Point2 p = transformation.unproject(Point2(x+.5, y+.5));68typename ContourCombiner::DistanceType distance = distanceFinder.distance(p);69distancePixelConversion(output(x, y), distance);70x += xDirection;71}72xDirection = -xDirection;73}74}75}7677void generateSDF(const BitmapSection<float, 1> &output, const Shape &shape, const SDFTransformation &transformation, const GeneratorConfig &config) {78if (config.overlapSupport)79generateDistanceField<OverlappingContourCombiner<TrueDistanceSelector> >(output, shape, transformation);80else81generateDistanceField<SimpleContourCombiner<TrueDistanceSelector> >(output, shape, transformation);82}8384void generatePSDF(const BitmapSection<float, 1> &output, const Shape &shape, const SDFTransformation &transformation, const GeneratorConfig &config) {85if (config.overlapSupport)86generateDistanceField<OverlappingContourCombiner<PerpendicularDistanceSelector> >(output, shape, transformation);87else88generateDistanceField<SimpleContourCombiner<PerpendicularDistanceSelector> >(output, shape, transformation);89}9091void generateMSDF(const BitmapSection<float, 3> &output, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config) {92if (config.overlapSupport)93generateDistanceField<OverlappingContourCombiner<MultiDistanceSelector> >(output, shape, transformation);94else95generateDistanceField<SimpleContourCombiner<MultiDistanceSelector> >(output, shape, transformation);96msdfErrorCorrection(output, shape, transformation, config);97}9899void generateMTSDF(const BitmapSection<float, 4> &output, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config) {100if (config.overlapSupport)101generateDistanceField<OverlappingContourCombiner<MultiAndTrueDistanceSelector> >(output, shape, transformation);102else103generateDistanceField<SimpleContourCombiner<MultiAndTrueDistanceSelector> >(output, shape, transformation);104msdfErrorCorrection(output, shape, transformation, config);105}106107void generateSDF(const BitmapSection<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config) {108if (config.overlapSupport)109generateDistanceField<OverlappingContourCombiner<TrueDistanceSelector> >(output, shape, SDFTransformation(projection, range));110else111generateDistanceField<SimpleContourCombiner<TrueDistanceSelector> >(output, shape, SDFTransformation(projection, range));112}113114void generatePSDF(const BitmapSection<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config) {115if (config.overlapSupport)116generateDistanceField<OverlappingContourCombiner<PerpendicularDistanceSelector> >(output, shape, SDFTransformation(projection, range));117else118generateDistanceField<SimpleContourCombiner<PerpendicularDistanceSelector> >(output, shape, SDFTransformation(projection, range));119}120121void generateMSDF(const BitmapSection<float, 3> &output, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config) {122if (config.overlapSupport)123generateDistanceField<OverlappingContourCombiner<MultiDistanceSelector> >(output, shape, SDFTransformation(projection, range));124else125generateDistanceField<SimpleContourCombiner<MultiDistanceSelector> >(output, shape, SDFTransformation(projection, range));126msdfErrorCorrection(output, shape, SDFTransformation(projection, range), config);127}128129void generateMTSDF(const BitmapSection<float, 4> &output, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config) {130if (config.overlapSupport)131generateDistanceField<OverlappingContourCombiner<MultiAndTrueDistanceSelector> >(output, shape, SDFTransformation(projection, range));132else133generateDistanceField<SimpleContourCombiner<MultiAndTrueDistanceSelector> >(output, shape, SDFTransformation(projection, range));134msdfErrorCorrection(output, shape, SDFTransformation(projection, range), config);135}136137// Legacy API138139void generatePseudoSDF(const BitmapSection<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config) {140generatePSDF(output, shape, SDFTransformation(projection, range), config);141}142143void generateSDF(const BitmapSection<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {144generateSDF(output, shape, Projection(scale, translate), range, GeneratorConfig(overlapSupport));145}146147void generatePSDF(const BitmapSection<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {148generatePSDF(output, shape, Projection(scale, translate), range, GeneratorConfig(overlapSupport));149}150151void generatePseudoSDF(const BitmapSection<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {152generatePSDF(output, shape, Projection(scale, translate), range, GeneratorConfig(overlapSupport));153}154155void generateMSDF(const BitmapSection<float, 3> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig, bool overlapSupport) {156generateMSDF(output, shape, Projection(scale, translate), range, MSDFGeneratorConfig(overlapSupport, errorCorrectionConfig));157}158159void generateMTSDF(const BitmapSection<float, 4> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig, bool overlapSupport) {160generateMTSDF(output, shape, Projection(scale, translate), range, MSDFGeneratorConfig(overlapSupport, errorCorrectionConfig));161}162163// Legacy version164165void generateSDF_legacy(BitmapSection<float, 1> output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate) {166DistanceMapping distanceMapping(range);167output.reorient(shape.getYAxisOrientation());168#ifdef MSDFGEN_USE_OPENMP169#pragma omp parallel for170#endif171for (int y = 0; y < output.height; ++y) {172for (int x = 0; x < output.width; ++x) {173double dummy;174Point2 p = Vector2(x+.5, y+.5)/scale-translate;175SignedDistance minDistance;176for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour)177for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {178SignedDistance distance = (*edge)->signedDistance(p, dummy);179if (distance < minDistance)180minDistance = distance;181}182*output(x, y) = float(distanceMapping(minDistance.distance));183}184}185}186187void generatePSDF_legacy(BitmapSection<float, 1> output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate) {188DistanceMapping distanceMapping(range);189output.reorient(shape.getYAxisOrientation());190#ifdef MSDFGEN_USE_OPENMP191#pragma omp parallel for192#endif193for (int y = 0; y < output.height; ++y) {194for (int x = 0; x < output.width; ++x) {195Point2 p = Vector2(x+.5, y+.5)/scale-translate;196SignedDistance minDistance;197const EdgeHolder *nearEdge = NULL;198double nearParam = 0;199for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour)200for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {201double param;202SignedDistance distance = (*edge)->signedDistance(p, param);203if (distance < minDistance) {204minDistance = distance;205nearEdge = &*edge;206nearParam = param;207}208}209if (nearEdge)210(*nearEdge)->distanceToPerpendicularDistance(minDistance, p, nearParam);211*output(x, y) = float(distanceMapping(minDistance.distance));212}213}214}215216void generatePseudoSDF_legacy(BitmapSection<float, 1> output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate) {217generatePSDF_legacy(output, shape, range, scale, translate);218}219220void generateMSDF_legacy(BitmapSection<float, 3> output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig) {221DistanceMapping distanceMapping(range);222output.reorient(shape.getYAxisOrientation());223#ifdef MSDFGEN_USE_OPENMP224#pragma omp parallel for225#endif226for (int y = 0; y < output.height; ++y) {227for (int x = 0; x < output.width; ++x) {228Point2 p = Vector2(x+.5, y+.5)/scale-translate;229230struct {231SignedDistance minDistance;232const EdgeHolder *nearEdge;233double nearParam;234} r, g, b;235r.nearEdge = g.nearEdge = b.nearEdge = NULL;236r.nearParam = g.nearParam = b.nearParam = 0;237238for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour)239for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {240double param;241SignedDistance distance = (*edge)->signedDistance(p, param);242if ((*edge)->color&RED && distance < r.minDistance) {243r.minDistance = distance;244r.nearEdge = &*edge;245r.nearParam = param;246}247if ((*edge)->color&GREEN && distance < g.minDistance) {248g.minDistance = distance;249g.nearEdge = &*edge;250g.nearParam = param;251}252if ((*edge)->color&BLUE && distance < b.minDistance) {253b.minDistance = distance;254b.nearEdge = &*edge;255b.nearParam = param;256}257}258259if (r.nearEdge)260(*r.nearEdge)->distanceToPerpendicularDistance(r.minDistance, p, r.nearParam);261if (g.nearEdge)262(*g.nearEdge)->distanceToPerpendicularDistance(g.minDistance, p, g.nearParam);263if (b.nearEdge)264(*b.nearEdge)->distanceToPerpendicularDistance(b.minDistance, p, b.nearParam);265output(x, y)[0] = float(distanceMapping(r.minDistance.distance));266output(x, y)[1] = float(distanceMapping(g.minDistance.distance));267output(x, y)[2] = float(distanceMapping(b.minDistance.distance));268}269}270271errorCorrectionConfig.distanceCheckMode = ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;272msdfErrorCorrection(output, shape, Projection(scale, translate), range, MSDFGeneratorConfig(false, errorCorrectionConfig));273}274275void generateMTSDF_legacy(BitmapSection<float, 4> output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig) {276DistanceMapping distanceMapping(range);277output.reorient(shape.getYAxisOrientation());278#ifdef MSDFGEN_USE_OPENMP279#pragma omp parallel for280#endif281for (int y = 0; y < output.height; ++y) {282for (int x = 0; x < output.width; ++x) {283Point2 p = Vector2(x+.5, y+.5)/scale-translate;284285SignedDistance minDistance;286struct {287SignedDistance minDistance;288const EdgeHolder *nearEdge;289double nearParam;290} r, g, b;291r.nearEdge = g.nearEdge = b.nearEdge = NULL;292r.nearParam = g.nearParam = b.nearParam = 0;293294for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour)295for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {296double param;297SignedDistance distance = (*edge)->signedDistance(p, param);298if (distance < minDistance)299minDistance = distance;300if ((*edge)->color&RED && distance < r.minDistance) {301r.minDistance = distance;302r.nearEdge = &*edge;303r.nearParam = param;304}305if ((*edge)->color&GREEN && distance < g.minDistance) {306g.minDistance = distance;307g.nearEdge = &*edge;308g.nearParam = param;309}310if ((*edge)->color&BLUE && distance < b.minDistance) {311b.minDistance = distance;312b.nearEdge = &*edge;313b.nearParam = param;314}315}316317if (r.nearEdge)318(*r.nearEdge)->distanceToPerpendicularDistance(r.minDistance, p, r.nearParam);319if (g.nearEdge)320(*g.nearEdge)->distanceToPerpendicularDistance(g.minDistance, p, g.nearParam);321if (b.nearEdge)322(*b.nearEdge)->distanceToPerpendicularDistance(b.minDistance, p, b.nearParam);323output(x, y)[0] = float(distanceMapping(r.minDistance.distance));324output(x, y)[1] = float(distanceMapping(g.minDistance.distance));325output(x, y)[2] = float(distanceMapping(b.minDistance.distance));326output(x, y)[3] = float(distanceMapping(minDistance.distance));327}328}329330errorCorrectionConfig.distanceCheckMode = ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE;331msdfErrorCorrection(output, shape, Projection(scale, translate), range, MSDFGeneratorConfig(false, errorCorrectionConfig));332}333334}335336337