mirror of https://github.com/Chlumsky/msdfgen.git
Asymmetrical range
This commit is contained in:
parent
937f31ff41
commit
6d252a7dc3
|
|
@ -128,10 +128,11 @@ int main() {
|
|||
shape.normalize();
|
||||
// max. angle
|
||||
edgeColoringSimple(shape, 3.0);
|
||||
// image width, height
|
||||
// output width, height
|
||||
Bitmap<float, 3> msdf(32, 32);
|
||||
// range, scale, translation
|
||||
generateMSDF(msdf, shape, 4.0, 1.0, Vector2(4.0, 4.0));
|
||||
// scale, translation
|
||||
SDFTransformation t(Projection(1.0, Vector2(4.0, 4.0)), Range(4.0));
|
||||
generateMSDF(msdf, shape, t);
|
||||
savePng(msdf, "output.png");
|
||||
}
|
||||
destroyFont(font);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
|
||||
#include "DistanceMapping.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
DistanceMapping DistanceMapping::inverse(Range range) {
|
||||
double rangeWidth = range.upper-range.lower;
|
||||
return DistanceMapping(rangeWidth, range.lower/(rangeWidth ? rangeWidth : 1));
|
||||
}
|
||||
|
||||
DistanceMapping::DistanceMapping() : scale(1), translate(0) { }
|
||||
|
||||
DistanceMapping::DistanceMapping(Range range) : scale(1/(range.upper-range.lower)), translate(-range.lower) { }
|
||||
|
||||
double DistanceMapping::operator()(double d) const {
|
||||
return scale*(d+translate);
|
||||
}
|
||||
|
||||
double DistanceMapping::operator()(Delta d) const {
|
||||
return scale*d.value;
|
||||
}
|
||||
|
||||
DistanceMapping DistanceMapping::inverse() const {
|
||||
return DistanceMapping(1/scale, -scale*translate);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "Range.hpp"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Linear transformation of signed distance values.
|
||||
class DistanceMapping {
|
||||
|
||||
public:
|
||||
/// Explicitly designates value as distance delta rather than an absolute distance.
|
||||
class Delta {
|
||||
public:
|
||||
double value;
|
||||
inline explicit Delta(double distanceDelta) : value(distanceDelta) { }
|
||||
inline operator double() const { return value; }
|
||||
};
|
||||
|
||||
static DistanceMapping inverse(Range range);
|
||||
|
||||
DistanceMapping();
|
||||
DistanceMapping(Range range);
|
||||
double operator()(double d) const;
|
||||
double operator()(Delta d) const;
|
||||
DistanceMapping inverse() const;
|
||||
|
||||
private:
|
||||
double scale;
|
||||
double translate;
|
||||
|
||||
inline DistanceMapping(double scale, double translate) : scale(scale), translate(translate) { }
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -74,7 +74,7 @@ public:
|
|||
// Compute the evaluated distance (interpolated median) before and after error correction, as well as the exact shape distance.
|
||||
float oldPSD = median(oldMSD[0], oldMSD[1], oldMSD[2]);
|
||||
float newPSD = median(newMSD[0], newMSD[1], newMSD[2]);
|
||||
float refPSD = float(parent->invRange*parent->distanceFinder.distance(parent->shapeCoord+tVector*parent->texelSize)+.5);
|
||||
float refPSD = float(parent->distanceMapping(parent->distanceFinder.distance(parent->shapeCoord+tVector*parent->texelSize)));
|
||||
// Compare the differences of the exact distance and the before and after distances.
|
||||
return parent->minImproveRatio*fabsf(newPSD-refPSD) < double(fabsf(oldPSD-refPSD));
|
||||
}
|
||||
|
|
@ -87,7 +87,7 @@ public:
|
|||
Point2 shapeCoord, sdfCoord;
|
||||
const float *msd;
|
||||
bool protectedFlag;
|
||||
inline ShapeDistanceChecker(const BitmapConstRef<float, N> &sdf, const Shape &shape, const Projection &projection, double invRange, double minImproveRatio) : distanceFinder(shape), sdf(sdf), invRange(invRange), minImproveRatio(minImproveRatio) {
|
||||
inline ShapeDistanceChecker(const BitmapConstRef<float, N> &sdf, const Shape &shape, const Projection &projection, DistanceMapping distanceMapping, double minImproveRatio) : distanceFinder(shape), sdf(sdf), distanceMapping(distanceMapping), minImproveRatio(minImproveRatio) {
|
||||
texelSize = projection.unprojectVector(Vector2(1));
|
||||
}
|
||||
inline ArtifactClassifier classifier(const Vector2 &direction, double span) {
|
||||
|
|
@ -96,15 +96,14 @@ public:
|
|||
private:
|
||||
ShapeDistanceFinder<ContourCombiner<PerpendicularDistanceSelector> > distanceFinder;
|
||||
BitmapConstRef<float, N> sdf;
|
||||
double invRange;
|
||||
DistanceMapping distanceMapping;
|
||||
Vector2 texelSize;
|
||||
double minImproveRatio;
|
||||
};
|
||||
|
||||
MSDFErrorCorrection::MSDFErrorCorrection() { }
|
||||
|
||||
MSDFErrorCorrection::MSDFErrorCorrection(const BitmapRef<byte, 1> &stencil, const Projection &projection, double range) : stencil(stencil), projection(projection) {
|
||||
invRange = 1/range;
|
||||
MSDFErrorCorrection::MSDFErrorCorrection(const BitmapRef<byte, 1> &stencil, const SDFTransformation &transformation) : stencil(stencil), transformation(transformation) {
|
||||
minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio;
|
||||
minImproveRatio = ErrorCorrectionConfig::defaultMinImproveRatio;
|
||||
memset(stencil.pixels, 0, sizeof(byte)*stencil.width*stencil.height);
|
||||
|
|
@ -127,7 +126,7 @@ void MSDFErrorCorrection::protectCorners(const Shape &shape) {
|
|||
// If the color changes from prevEdge to edge, this is a corner.
|
||||
if (!(commonColor&(commonColor-1))) {
|
||||
// Find the four texels that envelop the corner and mark them as protected.
|
||||
Point2 p = projection.project((*edge)->point(0));
|
||||
Point2 p = transformation.project((*edge)->point(0));
|
||||
if (shape.inverseYAxis)
|
||||
p.y = stencil.height-p.y;
|
||||
int l = (int) floor(p.x-.5);
|
||||
|
|
@ -191,7 +190,7 @@ template <int N>
|
|||
void MSDFErrorCorrection::protectEdges(const BitmapConstRef<float, N> &sdf) {
|
||||
float radius;
|
||||
// Horizontal texel pairs
|
||||
radius = float(PROTECTION_RADIUS_TOLERANCE*projection.unprojectVector(Vector2(invRange, 0)).length());
|
||||
radius = float(PROTECTION_RADIUS_TOLERANCE*transformation.unprojectVector(Vector2(transformation.distanceMapping(DistanceMapping::Delta(1)), 0)).length());
|
||||
for (int y = 0; y < sdf.height; ++y) {
|
||||
const float *left = sdf(0, y);
|
||||
const float *right = sdf(1, y);
|
||||
|
|
@ -207,7 +206,7 @@ void MSDFErrorCorrection::protectEdges(const BitmapConstRef<float, N> &sdf) {
|
|||
}
|
||||
}
|
||||
// Vertical texel pairs
|
||||
radius = float(PROTECTION_RADIUS_TOLERANCE*projection.unprojectVector(Vector2(0, invRange)).length());
|
||||
radius = float(PROTECTION_RADIUS_TOLERANCE*transformation.unprojectVector(Vector2(0, transformation.distanceMapping(DistanceMapping::Delta(1)))).length());
|
||||
for (int y = 0; y < sdf.height-1; ++y) {
|
||||
const float *bottom = sdf(0, y);
|
||||
const float *top = sdf(0, y+1);
|
||||
|
|
@ -223,7 +222,7 @@ void MSDFErrorCorrection::protectEdges(const BitmapConstRef<float, N> &sdf) {
|
|||
}
|
||||
}
|
||||
// Diagonal texel pairs
|
||||
radius = float(PROTECTION_RADIUS_TOLERANCE*projection.unprojectVector(Vector2(invRange)).length());
|
||||
radius = float(PROTECTION_RADIUS_TOLERANCE*transformation.unprojectVector(Vector2(transformation.distanceMapping(DistanceMapping::Delta(1)))).length());
|
||||
for (int y = 0; y < sdf.height-1; ++y) {
|
||||
const float *lb = sdf(0, y);
|
||||
const float *rb = sdf(1, y);
|
||||
|
|
@ -391,9 +390,9 @@ static bool hasDiagonalArtifact(const ArtifactClassifier &artifactClassifier, fl
|
|||
template <int N>
|
||||
void MSDFErrorCorrection::findErrors(const BitmapConstRef<float, N> &sdf) {
|
||||
// Compute the expected deltas between values of horizontally, vertically, and diagonally adjacent texels.
|
||||
double hSpan = minDeviationRatio*projection.unprojectVector(Vector2(invRange, 0)).length();
|
||||
double vSpan = minDeviationRatio*projection.unprojectVector(Vector2(0, invRange)).length();
|
||||
double dSpan = minDeviationRatio*projection.unprojectVector(Vector2(invRange)).length();
|
||||
double hSpan = minDeviationRatio*transformation.unprojectVector(Vector2(transformation.distanceMapping(DistanceMapping::Delta(1)), 0)).length();
|
||||
double vSpan = minDeviationRatio*transformation.unprojectVector(Vector2(0, transformation.distanceMapping(DistanceMapping::Delta(1)))).length();
|
||||
double dSpan = minDeviationRatio*transformation.unprojectVector(Vector2(transformation.distanceMapping(DistanceMapping::Delta(1)))).length();
|
||||
// Inspect all texels.
|
||||
for (int y = 0; y < sdf.height; ++y) {
|
||||
for (int x = 0; x < sdf.width; ++x) {
|
||||
|
|
@ -419,14 +418,14 @@ void MSDFErrorCorrection::findErrors(const BitmapConstRef<float, N> &sdf) {
|
|||
template <template <typename> class ContourCombiner, int N>
|
||||
void MSDFErrorCorrection::findErrors(const BitmapConstRef<float, N> &sdf, const Shape &shape) {
|
||||
// Compute the expected deltas between values of horizontally, vertically, and diagonally adjacent texels.
|
||||
double hSpan = minDeviationRatio*projection.unprojectVector(Vector2(invRange, 0)).length();
|
||||
double vSpan = minDeviationRatio*projection.unprojectVector(Vector2(0, invRange)).length();
|
||||
double dSpan = minDeviationRatio*projection.unprojectVector(Vector2(invRange)).length();
|
||||
double hSpan = minDeviationRatio*transformation.unprojectVector(Vector2(transformation.distanceMapping(DistanceMapping::Delta(1)), 0)).length();
|
||||
double vSpan = minDeviationRatio*transformation.unprojectVector(Vector2(0, transformation.distanceMapping(DistanceMapping::Delta(1)))).length();
|
||||
double dSpan = minDeviationRatio*transformation.unprojectVector(Vector2(transformation.distanceMapping(DistanceMapping::Delta(1)))).length();
|
||||
#ifdef MSDFGEN_USE_OPENMP
|
||||
#pragma omp parallel
|
||||
#endif
|
||||
{
|
||||
ShapeDistanceChecker<ContourCombiner, N> shapeDistanceChecker(sdf, shape, projection, invRange, minImproveRatio);
|
||||
ShapeDistanceChecker<ContourCombiner, N> shapeDistanceChecker(sdf, shape, transformation, transformation.distanceMapping, minImproveRatio);
|
||||
bool rightToLeft = false;
|
||||
// Inspect all texels.
|
||||
#ifdef MSDFGEN_USE_OPENMP
|
||||
|
|
@ -439,7 +438,7 @@ void MSDFErrorCorrection::findErrors(const BitmapConstRef<float, N> &sdf, const
|
|||
if ((*stencil(x, row)&ERROR))
|
||||
continue;
|
||||
const float *c = sdf(x, row);
|
||||
shapeDistanceChecker.shapeCoord = projection.unproject(Point2(x+.5, y+.5));
|
||||
shapeDistanceChecker.shapeCoord = transformation.unproject(Point2(x+.5, y+.5));
|
||||
shapeDistanceChecker.sdfCoord = Point2(x+.5, row+.5);
|
||||
shapeDistanceChecker.msd = c;
|
||||
shapeDistanceChecker.protectedFlag = (*stencil(x, row)&PROTECTED) != 0;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "Projection.h"
|
||||
#include "SDFTransformation.h"
|
||||
#include "Shape.h"
|
||||
#include "BitmapRef.hpp"
|
||||
|
||||
|
|
@ -20,7 +20,7 @@ public:
|
|||
};
|
||||
|
||||
MSDFErrorCorrection();
|
||||
explicit MSDFErrorCorrection(const BitmapRef<byte, 1> &stencil, const Projection &projection, double range);
|
||||
explicit MSDFErrorCorrection(const BitmapRef<byte, 1> &stencil, const SDFTransformation &transformation);
|
||||
/// Sets the minimum ratio between the actual and maximum expected distance delta to be considered an error.
|
||||
void setMinDeviationRatio(double minDeviationRatio);
|
||||
/// Sets the minimum ratio between the pre-correction distance error and the post-correction distance error.
|
||||
|
|
@ -46,8 +46,7 @@ public:
|
|||
|
||||
private:
|
||||
BitmapRef<byte, 1> stencil;
|
||||
Projection projection;
|
||||
double invRange;
|
||||
SDFTransformation transformation;
|
||||
double minDeviationRatio;
|
||||
double minImproveRatio;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "base.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/**
|
||||
* Represents the range between two real values.
|
||||
* For example, the range of representable signed distances.
|
||||
*/
|
||||
struct Range {
|
||||
|
||||
double lower, upper;
|
||||
|
||||
inline Range(double symmetricalWidth = 0) : lower(-.5*symmetricalWidth), upper(.5*symmetricalWidth) { }
|
||||
|
||||
inline Range(double lowerBound, double upperBound) : lower(lowerBound), upper(upperBound) { }
|
||||
|
||||
inline Range &operator*=(double factor) {
|
||||
lower *= factor;
|
||||
upper *= factor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Range &operator/=(double divisor) {
|
||||
lower /= divisor;
|
||||
upper /= divisor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Range operator*(double factor) const {
|
||||
return Range(lower*factor, upper*factor);
|
||||
}
|
||||
|
||||
inline Range operator/(double divisor) const {
|
||||
return Range(lower/divisor, upper/divisor);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inline Range operator*(double factor, const Range &range) {
|
||||
return Range(factor*range.lower, factor*range.upper);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "Projection.h"
|
||||
#include "DistanceMapping.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/**
|
||||
* Full signed distance field transformation specifies both spatial transformation (Projection)
|
||||
* as well as distance value transformation (DistanceMapping).
|
||||
*/
|
||||
class SDFTransformation : public Projection {
|
||||
|
||||
public:
|
||||
DistanceMapping distanceMapping;
|
||||
|
||||
inline SDFTransformation() { }
|
||||
|
||||
inline SDFTransformation(const Projection &projection, const DistanceMapping &distanceMapping) : Projection(projection), distanceMapping(distanceMapping) { }
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
namespace msdfgen {
|
||||
|
||||
template <int N>
|
||||
static void msdfErrorCorrectionInner(const BitmapRef<float, N> &sdf, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config) {
|
||||
static void msdfErrorCorrectionInner(const BitmapRef<float, N> &sdf, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config) {
|
||||
if (config.errorCorrection.mode == ErrorCorrectionConfig::DISABLED)
|
||||
return;
|
||||
Bitmap<byte, 1> stencilBuffer;
|
||||
|
|
@ -19,7 +19,7 @@ static void msdfErrorCorrectionInner(const BitmapRef<float, N> &sdf, const Shape
|
|||
BitmapRef<byte, 1> stencil;
|
||||
stencil.pixels = config.errorCorrection.buffer ? config.errorCorrection.buffer : (byte *) stencilBuffer;
|
||||
stencil.width = sdf.width, stencil.height = sdf.height;
|
||||
MSDFErrorCorrection ec(stencil, projection, range);
|
||||
MSDFErrorCorrection ec(stencil, transformation);
|
||||
ec.setMinDeviationRatio(config.errorCorrection.minDeviationRatio);
|
||||
ec.setMinImproveRatio(config.errorCorrection.minImproveRatio);
|
||||
switch (config.errorCorrection.mode) {
|
||||
|
|
@ -49,9 +49,9 @@ static void msdfErrorCorrectionInner(const BitmapRef<float, N> &sdf, const Shape
|
|||
}
|
||||
|
||||
template <int N>
|
||||
static void msdfErrorCorrectionShapeless(const BitmapRef<float, N> &sdf, const Projection &projection, double range, double minDeviationRatio, bool protectAll) {
|
||||
static void msdfErrorCorrectionShapeless(const BitmapRef<float, N> &sdf, const SDFTransformation &transformation, double minDeviationRatio, bool protectAll) {
|
||||
Bitmap<byte, 1> stencilBuffer(sdf.width, sdf.height);
|
||||
MSDFErrorCorrection ec(stencilBuffer, projection, range);
|
||||
MSDFErrorCorrection ec(stencilBuffer, transformation);
|
||||
ec.setMinDeviationRatio(minDeviationRatio);
|
||||
if (protectAll)
|
||||
ec.protectAll();
|
||||
|
|
@ -59,25 +59,43 @@ static void msdfErrorCorrectionShapeless(const BitmapRef<float, N> &sdf, const P
|
|||
ec.apply(sdf);
|
||||
}
|
||||
|
||||
void msdfErrorCorrection(const BitmapRef<float, 3> &sdf, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config) {
|
||||
msdfErrorCorrectionInner(sdf, shape, projection, range, config);
|
||||
void msdfErrorCorrection(const BitmapRef<float, 3> &sdf, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config) {
|
||||
msdfErrorCorrectionInner(sdf, shape, transformation, config);
|
||||
}
|
||||
void msdfErrorCorrection(const BitmapRef<float, 4> &sdf, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config) {
|
||||
msdfErrorCorrectionInner(sdf, shape, projection, range, config);
|
||||
void msdfErrorCorrection(const BitmapRef<float, 4> &sdf, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config) {
|
||||
msdfErrorCorrectionInner(sdf, shape, transformation, config);
|
||||
}
|
||||
void msdfErrorCorrection(const BitmapRef<float, 3> &sdf, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config) {
|
||||
msdfErrorCorrectionInner(sdf, shape, SDFTransformation(projection, range), config);
|
||||
}
|
||||
void msdfErrorCorrection(const BitmapRef<float, 4> &sdf, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config) {
|
||||
msdfErrorCorrectionInner(sdf, shape, SDFTransformation(projection, range), config);
|
||||
}
|
||||
|
||||
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 3> &sdf, const Projection &projection, double range, double minDeviationRatio) {
|
||||
msdfErrorCorrectionShapeless(sdf, projection, range, minDeviationRatio, false);
|
||||
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 3> &sdf, const SDFTransformation &transformation, double minDeviationRatio) {
|
||||
msdfErrorCorrectionShapeless(sdf, transformation, minDeviationRatio, false);
|
||||
}
|
||||
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 4> &sdf, const Projection &projection, double range, double minDeviationRatio) {
|
||||
msdfErrorCorrectionShapeless(sdf, projection, range, minDeviationRatio, false);
|
||||
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 4> &sdf, const SDFTransformation &transformation, double minDeviationRatio) {
|
||||
msdfErrorCorrectionShapeless(sdf, transformation, minDeviationRatio, false);
|
||||
}
|
||||
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 3> &sdf, const Projection &projection, Range range, double minDeviationRatio) {
|
||||
msdfErrorCorrectionShapeless(sdf, SDFTransformation(projection, range), minDeviationRatio, false);
|
||||
}
|
||||
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 4> &sdf, const Projection &projection, Range range, double minDeviationRatio) {
|
||||
msdfErrorCorrectionShapeless(sdf, SDFTransformation(projection, range), minDeviationRatio, false);
|
||||
}
|
||||
|
||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 3> &sdf, const Projection &projection, double range, double minDeviationRatio) {
|
||||
msdfErrorCorrectionShapeless(sdf, projection, range, minDeviationRatio, true);
|
||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 3> &sdf, const SDFTransformation &transformation, double minDeviationRatio) {
|
||||
msdfErrorCorrectionShapeless(sdf, transformation, minDeviationRatio, true);
|
||||
}
|
||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 4> &sdf, const Projection &projection, double range, double minDeviationRatio) {
|
||||
msdfErrorCorrectionShapeless(sdf, projection, range, minDeviationRatio, true);
|
||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 4> &sdf, const SDFTransformation &transformation, double minDeviationRatio) {
|
||||
msdfErrorCorrectionShapeless(sdf, transformation, minDeviationRatio, true);
|
||||
}
|
||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 3> &sdf, const Projection &projection, Range range, double minDeviationRatio) {
|
||||
msdfErrorCorrectionShapeless(sdf, SDFTransformation(projection, range), minDeviationRatio, true);
|
||||
}
|
||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 4> &sdf, const Projection &projection, Range range, double minDeviationRatio) {
|
||||
msdfErrorCorrectionShapeless(sdf, SDFTransformation(projection, range), minDeviationRatio, true);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "Vector2.hpp"
|
||||
#include "Range.hpp"
|
||||
#include "Projection.h"
|
||||
#include "SDFTransformation.h"
|
||||
#include "Shape.h"
|
||||
#include "BitmapRef.hpp"
|
||||
#include "generator-config.h"
|
||||
|
|
@ -10,16 +12,22 @@
|
|||
namespace msdfgen {
|
||||
|
||||
/// Predicts potential artifacts caused by the interpolation of the MSDF and corrects them by converting nearby texels to single-channel.
|
||||
void msdfErrorCorrection(const BitmapRef<float, 3> &sdf, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void msdfErrorCorrection(const BitmapRef<float, 4> &sdf, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void msdfErrorCorrection(const BitmapRef<float, 3> &sdf, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void msdfErrorCorrection(const BitmapRef<float, 4> &sdf, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void msdfErrorCorrection(const BitmapRef<float, 3> &sdf, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void msdfErrorCorrection(const BitmapRef<float, 4> &sdf, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
|
||||
/// Applies the simplified error correction to all discontiunous distances (INDISCRIMINATE mode). Does not need shape or translation.
|
||||
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 3> &sdf, const Projection &projection, double range, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 4> &sdf, const Projection &projection, double range, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 3> &sdf, const SDFTransformation &transformation, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 4> &sdf, const SDFTransformation &transformation, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 3> &sdf, const Projection &projection, Range range, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 4> &sdf, const Projection &projection, Range range, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
|
||||
/// Applies the simplified error correction to edges only (EDGE_ONLY mode). Does not need shape or translation.
|
||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 3> &sdf, const Projection &projection, double range, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 4> &sdf, const Projection &projection, double range, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 3> &sdf, const SDFTransformation &transformation, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 4> &sdf, const SDFTransformation &transformation, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 3> &sdf, const Projection &projection, Range range, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 4> &sdf, const Projection &projection, Range range, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
|
||||
/// The original version of the error correction algorithm.
|
||||
void msdfErrorCorrection_legacy(const BitmapRef<float, 3> &output, const Vector2 &threshold);
|
||||
|
|
|
|||
138
core/msdfgen.cpp
138
core/msdfgen.cpp
|
|
@ -13,45 +13,45 @@ class DistancePixelConversion;
|
|||
|
||||
template <>
|
||||
class DistancePixelConversion<double> {
|
||||
double invRange;
|
||||
DistanceMapping mapping;
|
||||
public:
|
||||
typedef BitmapRef<float, 1> BitmapRefType;
|
||||
inline explicit DistancePixelConversion(double range) : invRange(1/range) { }
|
||||
inline explicit DistancePixelConversion(DistanceMapping mapping) : mapping(mapping) { }
|
||||
inline void operator()(float *pixels, double distance) const {
|
||||
*pixels = float(invRange*distance+.5);
|
||||
*pixels = float(mapping(distance));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class DistancePixelConversion<MultiDistance> {
|
||||
double invRange;
|
||||
DistanceMapping mapping;
|
||||
public:
|
||||
typedef BitmapRef<float, 3> BitmapRefType;
|
||||
inline explicit DistancePixelConversion(double range) : invRange(1/range) { }
|
||||
inline explicit DistancePixelConversion(DistanceMapping mapping) : mapping(mapping) { }
|
||||
inline void operator()(float *pixels, const MultiDistance &distance) const {
|
||||
pixels[0] = float(invRange*distance.r+.5);
|
||||
pixels[1] = float(invRange*distance.g+.5);
|
||||
pixels[2] = float(invRange*distance.b+.5);
|
||||
pixels[0] = float(mapping(distance.r));
|
||||
pixels[1] = float(mapping(distance.g));
|
||||
pixels[2] = float(mapping(distance.b));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class DistancePixelConversion<MultiAndTrueDistance> {
|
||||
double invRange;
|
||||
DistanceMapping mapping;
|
||||
public:
|
||||
typedef BitmapRef<float, 4> BitmapRefType;
|
||||
inline explicit DistancePixelConversion(double range) : invRange(1/range) { }
|
||||
inline explicit DistancePixelConversion(DistanceMapping mapping) : mapping(mapping) { }
|
||||
inline void operator()(float *pixels, const MultiAndTrueDistance &distance) const {
|
||||
pixels[0] = float(invRange*distance.r+.5);
|
||||
pixels[1] = float(invRange*distance.g+.5);
|
||||
pixels[2] = float(invRange*distance.b+.5);
|
||||
pixels[3] = float(invRange*distance.a+.5);
|
||||
pixels[0] = float(mapping(distance.r));
|
||||
pixels[1] = float(mapping(distance.g));
|
||||
pixels[2] = float(mapping(distance.b));
|
||||
pixels[3] = float(mapping(distance.a));
|
||||
}
|
||||
};
|
||||
|
||||
template <class ContourCombiner>
|
||||
void generateDistanceField(const typename DistancePixelConversion<typename ContourCombiner::DistanceType>::BitmapRefType &output, const Shape &shape, const Projection &projection, double range) {
|
||||
DistancePixelConversion<typename ContourCombiner::DistanceType> distancePixelConversion(range);
|
||||
void generateDistanceField(const typename DistancePixelConversion<typename ContourCombiner::DistanceType>::BitmapRefType &output, const Shape &shape, const SDFTransformation &transformation) {
|
||||
DistancePixelConversion<typename ContourCombiner::DistanceType> distancePixelConversion(transformation.distanceMapping);
|
||||
#ifdef MSDFGEN_USE_OPENMP
|
||||
#pragma omp parallel
|
||||
#endif
|
||||
|
|
@ -65,7 +65,7 @@ void generateDistanceField(const typename DistancePixelConversion<typename Conto
|
|||
int row = shape.inverseYAxis ? output.height-y-1 : y;
|
||||
for (int col = 0; col < output.width; ++col) {
|
||||
int x = rightToLeft ? output.width-col-1 : col;
|
||||
Point2 p = projection.unproject(Point2(x+.5, y+.5));
|
||||
Point2 p = transformation.unproject(Point2(x+.5, y+.5));
|
||||
typename ContourCombiner::DistanceType distance = distanceFinder.distance(p);
|
||||
distancePixelConversion(output(x, row), distance);
|
||||
}
|
||||
|
|
@ -74,65 +74,96 @@ void generateDistanceField(const typename DistancePixelConversion<typename Conto
|
|||
}
|
||||
}
|
||||
|
||||
void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, double range, const GeneratorConfig &config) {
|
||||
void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, const SDFTransformation &transformation, const GeneratorConfig &config) {
|
||||
if (config.overlapSupport)
|
||||
generateDistanceField<OverlappingContourCombiner<TrueDistanceSelector> >(output, shape, projection, range);
|
||||
generateDistanceField<OverlappingContourCombiner<TrueDistanceSelector> >(output, shape, transformation);
|
||||
else
|
||||
generateDistanceField<SimpleContourCombiner<TrueDistanceSelector> >(output, shape, projection, range);
|
||||
generateDistanceField<SimpleContourCombiner<TrueDistanceSelector> >(output, shape, transformation);
|
||||
}
|
||||
|
||||
void generatePSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, double range, const GeneratorConfig &config) {
|
||||
void generatePSDF(const BitmapRef<float, 1> &output, const Shape &shape, const SDFTransformation &transformation, const GeneratorConfig &config) {
|
||||
if (config.overlapSupport)
|
||||
generateDistanceField<OverlappingContourCombiner<PerpendicularDistanceSelector> >(output, shape, projection, range);
|
||||
generateDistanceField<OverlappingContourCombiner<PerpendicularDistanceSelector> >(output, shape, transformation);
|
||||
else
|
||||
generateDistanceField<SimpleContourCombiner<PerpendicularDistanceSelector> >(output, shape, projection, range);
|
||||
generateDistanceField<SimpleContourCombiner<PerpendicularDistanceSelector> >(output, shape, transformation);
|
||||
}
|
||||
|
||||
void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config) {
|
||||
void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config) {
|
||||
if (config.overlapSupport)
|
||||
generateDistanceField<OverlappingContourCombiner<MultiDistanceSelector> >(output, shape, projection, range);
|
||||
generateDistanceField<OverlappingContourCombiner<MultiDistanceSelector> >(output, shape, transformation);
|
||||
else
|
||||
generateDistanceField<SimpleContourCombiner<MultiDistanceSelector> >(output, shape, projection, range);
|
||||
msdfErrorCorrection(output, shape, projection, range, config);
|
||||
generateDistanceField<SimpleContourCombiner<MultiDistanceSelector> >(output, shape, transformation);
|
||||
msdfErrorCorrection(output, shape, transformation, config);
|
||||
}
|
||||
|
||||
void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config) {
|
||||
void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config) {
|
||||
if (config.overlapSupport)
|
||||
generateDistanceField<OverlappingContourCombiner<MultiAndTrueDistanceSelector> >(output, shape, projection, range);
|
||||
generateDistanceField<OverlappingContourCombiner<MultiAndTrueDistanceSelector> >(output, shape, transformation);
|
||||
else
|
||||
generateDistanceField<SimpleContourCombiner<MultiAndTrueDistanceSelector> >(output, shape, projection, range);
|
||||
msdfErrorCorrection(output, shape, projection, range, config);
|
||||
generateDistanceField<SimpleContourCombiner<MultiAndTrueDistanceSelector> >(output, shape, transformation);
|
||||
msdfErrorCorrection(output, shape, transformation, config);
|
||||
}
|
||||
|
||||
void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config) {
|
||||
if (config.overlapSupport)
|
||||
generateDistanceField<OverlappingContourCombiner<TrueDistanceSelector> >(output, shape, SDFTransformation(projection, range));
|
||||
else
|
||||
generateDistanceField<SimpleContourCombiner<TrueDistanceSelector> >(output, shape, SDFTransformation(projection, range));
|
||||
}
|
||||
|
||||
void generatePSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config) {
|
||||
if (config.overlapSupport)
|
||||
generateDistanceField<OverlappingContourCombiner<PerpendicularDistanceSelector> >(output, shape, SDFTransformation(projection, range));
|
||||
else
|
||||
generateDistanceField<SimpleContourCombiner<PerpendicularDistanceSelector> >(output, shape, SDFTransformation(projection, range));
|
||||
}
|
||||
|
||||
void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config) {
|
||||
if (config.overlapSupport)
|
||||
generateDistanceField<OverlappingContourCombiner<MultiDistanceSelector> >(output, shape, SDFTransformation(projection, range));
|
||||
else
|
||||
generateDistanceField<SimpleContourCombiner<MultiDistanceSelector> >(output, shape, SDFTransformation(projection, range));
|
||||
msdfErrorCorrection(output, shape, SDFTransformation(projection, range), config);
|
||||
}
|
||||
|
||||
void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config) {
|
||||
if (config.overlapSupport)
|
||||
generateDistanceField<OverlappingContourCombiner<MultiAndTrueDistanceSelector> >(output, shape, SDFTransformation(projection, range));
|
||||
else
|
||||
generateDistanceField<SimpleContourCombiner<MultiAndTrueDistanceSelector> >(output, shape, SDFTransformation(projection, range));
|
||||
msdfErrorCorrection(output, shape, SDFTransformation(projection, range), config);
|
||||
}
|
||||
|
||||
// Legacy API
|
||||
|
||||
void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, double range, const GeneratorConfig &config) {
|
||||
generatePSDF(output, shape, projection, range, config);
|
||||
void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config) {
|
||||
generatePSDF(output, shape, SDFTransformation(projection, range), config);
|
||||
}
|
||||
|
||||
void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
|
||||
void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
|
||||
generateSDF(output, shape, Projection(scale, translate), range, GeneratorConfig(overlapSupport));
|
||||
}
|
||||
|
||||
void generatePSDF(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
|
||||
void generatePSDF(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
|
||||
generatePSDF(output, shape, Projection(scale, translate), range, GeneratorConfig(overlapSupport));
|
||||
}
|
||||
|
||||
void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
|
||||
void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
|
||||
generatePSDF(output, shape, Projection(scale, translate), range, GeneratorConfig(overlapSupport));
|
||||
}
|
||||
|
||||
void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig, bool overlapSupport) {
|
||||
void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig, bool overlapSupport) {
|
||||
generateMSDF(output, shape, Projection(scale, translate), range, MSDFGeneratorConfig(overlapSupport, errorCorrectionConfig));
|
||||
}
|
||||
|
||||
void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig, bool overlapSupport) {
|
||||
void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig, bool overlapSupport) {
|
||||
generateMTSDF(output, shape, Projection(scale, translate), range, MSDFGeneratorConfig(overlapSupport, errorCorrectionConfig));
|
||||
}
|
||||
|
||||
// Legacy version
|
||||
|
||||
void generateSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate) {
|
||||
void generateSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate) {
|
||||
DistanceMapping distanceMapping(range);
|
||||
#ifdef MSDFGEN_USE_OPENMP
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
|
|
@ -148,12 +179,13 @@ void generateSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, d
|
|||
if (distance < minDistance)
|
||||
minDistance = distance;
|
||||
}
|
||||
*output(x, row) = float(minDistance.distance/range+.5);
|
||||
*output(x, row) = float(distanceMapping(minDistance.distance));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void generatePSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate) {
|
||||
void generatePSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate) {
|
||||
DistanceMapping distanceMapping(range);
|
||||
#ifdef MSDFGEN_USE_OPENMP
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
|
|
@ -176,16 +208,17 @@ void generatePSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape,
|
|||
}
|
||||
if (nearEdge)
|
||||
(*nearEdge)->distanceToPerpendicularDistance(minDistance, p, nearParam);
|
||||
*output(x, row) = float(minDistance.distance/range+.5);
|
||||
*output(x, row) = float(distanceMapping(minDistance.distance));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void generatePseudoSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate) {
|
||||
void generatePseudoSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate) {
|
||||
generatePSDF_legacy(output, shape, range, scale, translate);
|
||||
}
|
||||
|
||||
void generateMSDF_legacy(const BitmapRef<float, 3> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig) {
|
||||
void generateMSDF_legacy(const BitmapRef<float, 3> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig) {
|
||||
DistanceMapping distanceMapping(range);
|
||||
#ifdef MSDFGEN_USE_OPENMP
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
|
|
@ -229,9 +262,9 @@ void generateMSDF_legacy(const BitmapRef<float, 3> &output, const Shape &shape,
|
|||
(*g.nearEdge)->distanceToPerpendicularDistance(g.minDistance, p, g.nearParam);
|
||||
if (b.nearEdge)
|
||||
(*b.nearEdge)->distanceToPerpendicularDistance(b.minDistance, p, b.nearParam);
|
||||
output(x, row)[0] = float(r.minDistance.distance/range+.5);
|
||||
output(x, row)[1] = float(g.minDistance.distance/range+.5);
|
||||
output(x, row)[2] = float(b.minDistance.distance/range+.5);
|
||||
output(x, row)[0] = float(distanceMapping(r.minDistance.distance));
|
||||
output(x, row)[1] = float(distanceMapping(g.minDistance.distance));
|
||||
output(x, row)[2] = float(distanceMapping(b.minDistance.distance));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -239,7 +272,8 @@ void generateMSDF_legacy(const BitmapRef<float, 3> &output, const Shape &shape,
|
|||
msdfErrorCorrection(output, shape, Projection(scale, translate), range, MSDFGeneratorConfig(false, errorCorrectionConfig));
|
||||
}
|
||||
|
||||
void generateMTSDF_legacy(const BitmapRef<float, 4> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig) {
|
||||
void generateMTSDF_legacy(const BitmapRef<float, 4> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig) {
|
||||
DistanceMapping distanceMapping(range);
|
||||
#ifdef MSDFGEN_USE_OPENMP
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
|
|
@ -286,10 +320,10 @@ void generateMTSDF_legacy(const BitmapRef<float, 4> &output, const Shape &shape,
|
|||
(*g.nearEdge)->distanceToPerpendicularDistance(g.minDistance, p, g.nearParam);
|
||||
if (b.nearEdge)
|
||||
(*b.nearEdge)->distanceToPerpendicularDistance(b.minDistance, p, b.nearParam);
|
||||
output(x, row)[0] = float(r.minDistance.distance/range+.5);
|
||||
output(x, row)[1] = float(g.minDistance.distance/range+.5);
|
||||
output(x, row)[2] = float(b.minDistance.distance/range+.5);
|
||||
output(x, row)[3] = float(minDistance.distance/range+.5);
|
||||
output(x, row)[0] = float(distanceMapping(r.minDistance.distance));
|
||||
output(x, row)[1] = float(distanceMapping(g.minDistance.distance));
|
||||
output(x, row)[2] = float(distanceMapping(b.minDistance.distance));
|
||||
output(x, row)[3] = float(distanceMapping(minDistance.distance));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,89 +2,175 @@
|
|||
#include "render-sdf.h"
|
||||
|
||||
#include "arithmetics.hpp"
|
||||
#include "DistanceMapping.h"
|
||||
#include "pixel-conversion.hpp"
|
||||
#include "bitmap-interpolation.hpp"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
static float distVal(float dist, double pxRange, float midValue) {
|
||||
if (!pxRange)
|
||||
return (float) (dist > midValue);
|
||||
return (float) clamp((dist-midValue)*pxRange+.5);
|
||||
static float distVal(float dist, DistanceMapping mapping) {
|
||||
return (float) clamp(mapping(dist)+.5);
|
||||
}
|
||||
|
||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 1> &sdf, double pxRange, float midValue) {
|
||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 1> &sdf, Range sdfPxRange, float sdThreshold) {
|
||||
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
||||
for (int y = 0; y < output.height; ++y)
|
||||
for (int x = 0; x < output.width; ++x) {
|
||||
float sd;
|
||||
interpolate(&sd, sdf, scale*Point2(x+.5, y+.5));
|
||||
*output(x, y) = distVal(sd, pxRange, midValue);
|
||||
if (sdfPxRange.lower == sdfPxRange.upper) {
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
for (int x = 0; x < output.width; ++x) {
|
||||
float sd;
|
||||
interpolate(&sd, sdf, scale*Point2(x+.5, y+.5));
|
||||
*output(x, y) = float(sd >= sdThreshold);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sdfPxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
||||
DistanceMapping distanceMapping = DistanceMapping::inverse(sdfPxRange);
|
||||
float sdBias = .5f-sdThreshold;
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
for (int x = 0; x < output.width; ++x) {
|
||||
float sd;
|
||||
interpolate(&sd, sdf, scale*Point2(x+.5, y+.5));
|
||||
*output(x, y) = distVal(sd+sdBias, distanceMapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void renderSDF(const BitmapRef<float, 3> &output, const BitmapConstRef<float, 1> &sdf, double pxRange, float midValue) {
|
||||
void renderSDF(const BitmapRef<float, 3> &output, const BitmapConstRef<float, 1> &sdf, Range sdfPxRange, float sdThreshold) {
|
||||
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
||||
for (int y = 0; y < output.height; ++y)
|
||||
for (int x = 0; x < output.width; ++x) {
|
||||
float sd;
|
||||
interpolate(&sd, sdf, scale*Point2(x+.5, y+.5));
|
||||
float v = distVal(sd, pxRange, midValue);
|
||||
output(x, y)[0] = v;
|
||||
output(x, y)[1] = v;
|
||||
output(x, y)[2] = v;
|
||||
if (sdfPxRange.lower == sdfPxRange.upper) {
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
for (int x = 0; x < output.width; ++x) {
|
||||
float sd;
|
||||
interpolate(&sd, sdf, scale*Point2(x+.5, y+.5));
|
||||
float v = float(sd >= sdThreshold);
|
||||
output(x, y)[0] = v;
|
||||
output(x, y)[1] = v;
|
||||
output(x, y)[2] = v;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sdfPxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
||||
DistanceMapping distanceMapping = DistanceMapping::inverse(sdfPxRange);
|
||||
float sdBias = .5f-sdThreshold;
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
for (int x = 0; x < output.width; ++x) {
|
||||
float sd;
|
||||
interpolate(&sd, sdf, scale*Point2(x+.5, y+.5));
|
||||
float v = distVal(sd+sdBias, distanceMapping);
|
||||
output(x, y)[0] = v;
|
||||
output(x, y)[1] = v;
|
||||
output(x, y)[2] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 3> &sdf, double pxRange, float midValue) {
|
||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 3> &sdf, Range sdfPxRange, float sdThreshold) {
|
||||
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
||||
for (int y = 0; y < output.height; ++y)
|
||||
for (int x = 0; x < output.width; ++x) {
|
||||
float sd[3];
|
||||
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
||||
*output(x, y) = distVal(median(sd[0], sd[1], sd[2]), pxRange, midValue);
|
||||
if (sdfPxRange.lower == sdfPxRange.upper) {
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
for (int x = 0; x < output.width; ++x) {
|
||||
float sd[3];
|
||||
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
||||
*output(x, y) = float(median(sd[0], sd[1], sd[2]) >= sdThreshold);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sdfPxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
||||
DistanceMapping distanceMapping = DistanceMapping::inverse(sdfPxRange);
|
||||
float sdBias = .5f-sdThreshold;
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
for (int x = 0; x < output.width; ++x) {
|
||||
float sd[3];
|
||||
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
||||
*output(x, y) = distVal(median(sd[0], sd[1], sd[2])+sdBias, distanceMapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void renderSDF(const BitmapRef<float, 3> &output, const BitmapConstRef<float, 3> &sdf, double pxRange, float midValue) {
|
||||
void renderSDF(const BitmapRef<float, 3> &output, const BitmapConstRef<float, 3> &sdf, Range sdfPxRange, float sdThreshold) {
|
||||
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
||||
for (int y = 0; y < output.height; ++y)
|
||||
for (int x = 0; x < output.width; ++x) {
|
||||
float sd[3];
|
||||
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
||||
output(x, y)[0] = distVal(sd[0], pxRange, midValue);
|
||||
output(x, y)[1] = distVal(sd[1], pxRange, midValue);
|
||||
output(x, y)[2] = distVal(sd[2], pxRange, midValue);
|
||||
if (sdfPxRange.lower == sdfPxRange.upper) {
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
for (int x = 0; x < output.width; ++x) {
|
||||
float sd[3];
|
||||
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
||||
output(x, y)[0] = float(sd[0] >= sdThreshold);
|
||||
output(x, y)[1] = float(sd[1] >= sdThreshold);
|
||||
output(x, y)[2] = float(sd[2] >= sdThreshold);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sdfPxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
||||
DistanceMapping distanceMapping = DistanceMapping::inverse(sdfPxRange);
|
||||
float sdBias = .5f-sdThreshold;
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
for (int x = 0; x < output.width; ++x) {
|
||||
float sd[3];
|
||||
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
||||
output(x, y)[0] = distVal(sd[0]+sdBias, distanceMapping);
|
||||
output(x, y)[1] = distVal(sd[1]+sdBias, distanceMapping);
|
||||
output(x, y)[2] = distVal(sd[2]+sdBias, distanceMapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 4> &sdf, double pxRange, float midValue) {
|
||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 4> &sdf, Range sdfPxRange, float sdThreshold) {
|
||||
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
||||
for (int y = 0; y < output.height; ++y)
|
||||
for (int x = 0; x < output.width; ++x) {
|
||||
float sd[4];
|
||||
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
||||
*output(x, y) = distVal(median(sd[0], sd[1], sd[2]), pxRange, midValue);
|
||||
if (sdfPxRange.lower == sdfPxRange.upper) {
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
for (int x = 0; x < output.width; ++x) {
|
||||
float sd[4];
|
||||
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
||||
*output(x, y) = float(median(sd[0], sd[1], sd[2]) >= sdThreshold);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sdfPxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
||||
DistanceMapping distanceMapping = DistanceMapping::inverse(sdfPxRange);
|
||||
float sdBias = .5f-sdThreshold;
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
for (int x = 0; x < output.width; ++x) {
|
||||
float sd[4];
|
||||
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
||||
*output(x, y) = distVal(median(sd[0], sd[1], sd[2])+sdBias, distanceMapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void renderSDF(const BitmapRef<float, 4> &output, const BitmapConstRef<float, 4> &sdf, double pxRange, float midValue) {
|
||||
void renderSDF(const BitmapRef<float, 4> &output, const BitmapConstRef<float, 4> &sdf, Range sdfPxRange, float sdThreshold) {
|
||||
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
||||
for (int y = 0; y < output.height; ++y)
|
||||
for (int x = 0; x < output.width; ++x) {
|
||||
float sd[4];
|
||||
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
||||
output(x, y)[0] = distVal(sd[0], pxRange, midValue);
|
||||
output(x, y)[1] = distVal(sd[1], pxRange, midValue);
|
||||
output(x, y)[2] = distVal(sd[2], pxRange, midValue);
|
||||
output(x, y)[3] = distVal(sd[3], pxRange, midValue);
|
||||
if (sdfPxRange.lower == sdfPxRange.upper) {
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
for (int x = 0; x < output.width; ++x) {
|
||||
float sd[4];
|
||||
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
||||
output(x, y)[0] = float(sd[0] >= sdThreshold);
|
||||
output(x, y)[1] = float(sd[1] >= sdThreshold);
|
||||
output(x, y)[2] = float(sd[2] >= sdThreshold);
|
||||
output(x, y)[3] = float(sd[3] >= sdThreshold);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sdfPxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
||||
DistanceMapping distanceMapping = DistanceMapping::inverse(sdfPxRange);
|
||||
float sdBias = .5f-sdThreshold;
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
for (int x = 0; x < output.width; ++x) {
|
||||
float sd[4];
|
||||
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
||||
output(x, y)[0] = distVal(sd[0]+sdBias, distanceMapping);
|
||||
output(x, y)[1] = distVal(sd[1]+sdBias, distanceMapping);
|
||||
output(x, y)[2] = distVal(sd[2]+sdBias, distanceMapping);
|
||||
output(x, y)[3] = distVal(sd[3]+sdBias, distanceMapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void simulate8bit(const BitmapRef<float, 1> &bitmap) {
|
||||
|
|
|
|||
|
|
@ -2,17 +2,18 @@
|
|||
#pragma once
|
||||
|
||||
#include "Vector2.hpp"
|
||||
#include "Range.hpp"
|
||||
#include "BitmapRef.hpp"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Reconstructs the shape's appearance into output from the distance field sdf.
|
||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 1> &sdf, double pxRange = 0, float midValue = .5f);
|
||||
void renderSDF(const BitmapRef<float, 3> &output, const BitmapConstRef<float, 1> &sdf, double pxRange = 0, float midValue = .5f);
|
||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 3> &sdf, double pxRange = 0, float midValue = .5f);
|
||||
void renderSDF(const BitmapRef<float, 3> &output, const BitmapConstRef<float, 3> &sdf, double pxRange = 0, float midValue = .5f);
|
||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 4> &sdf, double pxRange = 0, float midValue = .5f);
|
||||
void renderSDF(const BitmapRef<float, 4> &output, const BitmapConstRef<float, 4> &sdf, double pxRange = 0, float midValue = .5f);
|
||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 1> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
void renderSDF(const BitmapRef<float, 3> &output, const BitmapConstRef<float, 1> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 3> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
void renderSDF(const BitmapRef<float, 3> &output, const BitmapConstRef<float, 3> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 4> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
void renderSDF(const BitmapRef<float, 4> &output, const BitmapConstRef<float, 4> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
|
||||
/// Snaps the values of the floating-point bitmaps into one of the 256 values representable in a standard 8-bit bitmap.
|
||||
void simulate8bit(const BitmapRef<float, 1> &bitmap);
|
||||
|
|
|
|||
121
main.cpp
121
main.cpp
|
|
@ -388,6 +388,10 @@ static const char *const helpText =
|
|||
"OPTIONS\n"
|
||||
" -angle <angle>\n"
|
||||
"\tSpecifies the minimum angle between adjacent edges to be considered a corner. Append D for degrees.\n"
|
||||
" -apxrange <outermost distance> <innermost distance>\n"
|
||||
"\tSpecifies the outermost (negative) and innermost representable distance in pixels.\n"
|
||||
" -arange <outermost distance> <innermost distance>\n"
|
||||
"\tSpecifies the outermost (negative) and innermost representable distance in shape units.\n"
|
||||
" -ascale <x scale> <y scale>\n"
|
||||
"\tSets the scale used to convert shape units to pixels asymmetrically.\n"
|
||||
" -autoframe\n"
|
||||
|
|
@ -396,8 +400,6 @@ static const char *const helpText =
|
|||
"\tSelects the strategy of the edge coloring heuristic.\n"
|
||||
" -dimensions <width> <height>\n"
|
||||
"\tSets the dimensions of the output image.\n"
|
||||
" -distanceshift <shift>\n"
|
||||
"\tShifts all normalized distances in the output distance field by this value.\n"
|
||||
" -edgecolors <sequence>\n"
|
||||
"\tOverrides automatic edge coloring with the specified color sequence.\n"
|
||||
" -errorcorrection <mode>\n"
|
||||
|
|
@ -555,8 +557,8 @@ int main(int argc, const char *const *argv) {
|
|||
RANGE_UNIT,
|
||||
RANGE_PX
|
||||
} rangeMode = RANGE_PX;
|
||||
double range = 1;
|
||||
double pxRange = 2;
|
||||
Range range(1);
|
||||
Range pxRange(2);
|
||||
Vector2 translate;
|
||||
Vector2 scale = 1;
|
||||
bool scaleSpecified = false;
|
||||
|
|
@ -740,18 +742,42 @@ int main(int argc, const char *const *argv) {
|
|||
}
|
||||
ARG_CASE("-range" ARG_CASE_OR "-unitrange", 1) {
|
||||
double r;
|
||||
if (!(parseDouble(r, argv[argPos++]) && r > 0))
|
||||
ABORT("Invalid range argument. Use -range <range> with a positive real number.");
|
||||
if (!parseDouble(r, argv[argPos++]))
|
||||
ABORT("Invalid range argument. Use -range <range> with a real number.");
|
||||
if (r == 0)
|
||||
ABORT("Range must be non-zero.");
|
||||
rangeMode = RANGE_UNIT;
|
||||
range = r;
|
||||
range = Range(r);
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-pxrange", 1) {
|
||||
double r;
|
||||
if (!(parseDouble(r, argv[argPos++]) && r > 0))
|
||||
ABORT("Invalid range argument. Use -pxrange <range> with a positive real number.");
|
||||
if (!parseDouble(r, argv[argPos++]))
|
||||
ABORT("Invalid range argument. Use -pxrange <range> with a real number.");
|
||||
if (r == 0)
|
||||
ABORT("Range must be non-zero.");
|
||||
rangeMode = RANGE_PX;
|
||||
pxRange = r;
|
||||
pxRange = Range(r);
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-arange" ARG_CASE_OR "-aunitrange", 2) {
|
||||
double r0, r1;
|
||||
if (!(parseDouble(r0, argv[argPos++]) && parseDouble(r1, argv[argPos++])))
|
||||
ABORT("Invalid range arguments. Use -arange <minimum> <maximum> with two real numbers.");
|
||||
if (r0 == r1)
|
||||
ABORT("Range must be non-empty.");
|
||||
rangeMode = RANGE_UNIT;
|
||||
range = Range(r0, r1);
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-apxrange", 2) {
|
||||
double r0, r1;
|
||||
if (!(parseDouble(r0, argv[argPos++]) && parseDouble(r1, argv[argPos++])))
|
||||
ABORT("Invalid range arguments. Use -apxrange <minimum> <maximum> with two real numbers.");
|
||||
if (r0 == r1)
|
||||
ABORT("Range must be non-empty.");
|
||||
rangeMode = RANGE_PX;
|
||||
pxRange = Range(r0, r1);
|
||||
continue;
|
||||
}
|
||||
ARG_CASE("-scale", 1) {
|
||||
|
|
@ -1039,16 +1065,22 @@ int main(int argc, const char *const *argv) {
|
|||
if (autoFrame || mode == METRICS || printMetrics || orientation == GUESS)
|
||||
bounds = shape.getBounds();
|
||||
|
||||
if (outputDistanceShift) {
|
||||
Range &rangeRef = rangeMode == RANGE_PX ? pxRange : range;
|
||||
double rangeShift = -outputDistanceShift*(rangeRef.upper-rangeRef.lower);
|
||||
rangeRef.lower += rangeShift;
|
||||
rangeRef.upper += rangeShift;
|
||||
}
|
||||
|
||||
// Auto-frame
|
||||
if (autoFrame) {
|
||||
double l = bounds.l, b = bounds.b, r = bounds.r, t = bounds.t;
|
||||
Vector2 frame(width, height);
|
||||
double m = .5+(double) outputDistanceShift;
|
||||
if (!scaleSpecified) {
|
||||
if (rangeMode == RANGE_UNIT)
|
||||
l -= m*range, b -= m*range, r += m*range, t += m*range;
|
||||
l += range.lower, b += range.lower, r -= range.lower, t -= range.lower;
|
||||
else
|
||||
frame -= 2*m*pxRange;
|
||||
frame += 2*pxRange.lower;
|
||||
}
|
||||
if (l >= r || b >= t)
|
||||
l = 0, b = 0, r = 1, t = 1;
|
||||
|
|
@ -1067,7 +1099,7 @@ int main(int argc, const char *const *argv) {
|
|||
}
|
||||
}
|
||||
if (rangeMode == RANGE_PX && !scaleSpecified)
|
||||
translate += m*pxRange/scale;
|
||||
translate -= pxRange.lower/scale;
|
||||
}
|
||||
|
||||
if (rangeMode == RANGE_PX)
|
||||
|
|
@ -1094,13 +1126,13 @@ int main(int argc, const char *const *argv) {
|
|||
fprintf(out, "translate = %.17g, %.17g\n", translate.x, translate.y);
|
||||
}
|
||||
if (rangeMode == RANGE_PX)
|
||||
fprintf(out, "range = %.17g\n", range);
|
||||
fprintf(out, "range %.17g to %.17g\n", range.lower, range.upper);
|
||||
if (mode == METRICS && outputSpecified)
|
||||
fclose(out);
|
||||
}
|
||||
|
||||
// Compute output
|
||||
Projection projection(scale, translate);
|
||||
SDFTransformation transformation(Projection(scale, translate), range);
|
||||
Bitmap<float, 1> sdf;
|
||||
Bitmap<float, 3> msdf;
|
||||
Bitmap<float, 4> mtsdf;
|
||||
|
|
@ -1125,7 +1157,7 @@ int main(int argc, const char *const *argv) {
|
|||
if (legacyMode)
|
||||
generateSDF_legacy(sdf, shape, range, scale, translate);
|
||||
else
|
||||
generateSDF(sdf, shape, projection, range, generatorConfig);
|
||||
generateSDF(sdf, shape, transformation, generatorConfig);
|
||||
break;
|
||||
}
|
||||
case PERPENDICULAR: {
|
||||
|
|
@ -1133,7 +1165,7 @@ int main(int argc, const char *const *argv) {
|
|||
if (legacyMode)
|
||||
generatePSDF_legacy(sdf, shape, range, scale, translate);
|
||||
else
|
||||
generatePSDF(sdf, shape, projection, range, generatorConfig);
|
||||
generatePSDF(sdf, shape, transformation, generatorConfig);
|
||||
break;
|
||||
}
|
||||
case MULTI: {
|
||||
|
|
@ -1145,7 +1177,7 @@ int main(int argc, const char *const *argv) {
|
|||
if (legacyMode)
|
||||
generateMSDF_legacy(msdf, shape, range, scale, translate, generatorConfig.errorCorrection);
|
||||
else
|
||||
generateMSDF(msdf, shape, projection, range, generatorConfig);
|
||||
generateMSDF(msdf, shape, transformation, generatorConfig);
|
||||
break;
|
||||
}
|
||||
case MULTI_AND_TRUE: {
|
||||
|
|
@ -1157,7 +1189,7 @@ int main(int argc, const char *const *argv) {
|
|||
if (legacyMode)
|
||||
generateMTSDF_legacy(mtsdf, shape, range, scale, translate, generatorConfig.errorCorrection);
|
||||
else
|
||||
generateMTSDF(mtsdf, shape, projection, range, generatorConfig);
|
||||
generateMTSDF(mtsdf, shape, transformation, generatorConfig);
|
||||
break;
|
||||
}
|
||||
default:;
|
||||
|
|
@ -1188,40 +1220,19 @@ int main(int argc, const char *const *argv) {
|
|||
switch (mode) {
|
||||
case SINGLE:
|
||||
case PERPENDICULAR:
|
||||
distanceSignCorrection(sdf, shape, projection, fillRule);
|
||||
distanceSignCorrection(sdf, shape, transformation, fillRule);
|
||||
break;
|
||||
case MULTI:
|
||||
distanceSignCorrection(msdf, shape, projection, fillRule);
|
||||
msdfErrorCorrection(msdf, shape, projection, range, postErrorCorrectionConfig);
|
||||
distanceSignCorrection(msdf, shape, transformation, fillRule);
|
||||
msdfErrorCorrection(msdf, shape, transformation, postErrorCorrectionConfig);
|
||||
break;
|
||||
case MULTI_AND_TRUE:
|
||||
distanceSignCorrection(mtsdf, shape, projection, fillRule);
|
||||
msdfErrorCorrection(msdf, shape, projection, range, postErrorCorrectionConfig);
|
||||
distanceSignCorrection(mtsdf, shape, transformation, fillRule);
|
||||
msdfErrorCorrection(msdf, shape, transformation, postErrorCorrectionConfig);
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
if (outputDistanceShift) {
|
||||
float *pixel = NULL, *pixelsEnd = NULL;
|
||||
switch (mode) {
|
||||
case SINGLE:
|
||||
case PERPENDICULAR:
|
||||
pixel = (float *) sdf;
|
||||
pixelsEnd = pixel+1*sdf.width()*sdf.height();
|
||||
break;
|
||||
case MULTI:
|
||||
pixel = (float *) msdf;
|
||||
pixelsEnd = pixel+3*msdf.width()*msdf.height();
|
||||
break;
|
||||
case MULTI_AND_TRUE:
|
||||
pixel = (float *) mtsdf;
|
||||
pixelsEnd = pixel+4*mtsdf.width()*mtsdf.height();
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
while (pixel < pixelsEnd)
|
||||
*pixel++ += outputDistanceShift;
|
||||
}
|
||||
|
||||
// Save output
|
||||
if (shapeExport) {
|
||||
|
|
@ -1243,18 +1254,18 @@ int main(int argc, const char *const *argv) {
|
|||
if (is8bitFormat(format) && (testRenderMulti || testRender || estimateError))
|
||||
simulate8bit(sdf);
|
||||
if (estimateError) {
|
||||
double sdfError = estimateSDFError(sdf, shape, projection, SDF_ERROR_ESTIMATE_PRECISION, fillRule);
|
||||
double sdfError = estimateSDFError(sdf, shape, transformation, SDF_ERROR_ESTIMATE_PRECISION, fillRule);
|
||||
printf("SDF error ~ %e\n", sdfError);
|
||||
}
|
||||
if (testRenderMulti) {
|
||||
Bitmap<float, 3> render(testWidthM, testHeightM);
|
||||
renderSDF(render, sdf, avgScale*range, .5f+outputDistanceShift);
|
||||
renderSDF(render, sdf, avgScale*range);
|
||||
if (!SAVE_DEFAULT_IMAGE_FORMAT(render, testRenderMulti))
|
||||
fputs("Failed to write test render file.\n", stderr);
|
||||
}
|
||||
if (testRender) {
|
||||
Bitmap<float, 1> render(testWidth, testHeight);
|
||||
renderSDF(render, sdf, avgScale*range, .5f+outputDistanceShift);
|
||||
renderSDF(render, sdf, avgScale*range);
|
||||
if (!SAVE_DEFAULT_IMAGE_FORMAT(render, testRender))
|
||||
fputs("Failed to write test render file.\n", stderr);
|
||||
}
|
||||
|
|
@ -1267,18 +1278,18 @@ int main(int argc, const char *const *argv) {
|
|||
if (is8bitFormat(format) && (testRenderMulti || testRender || estimateError))
|
||||
simulate8bit(msdf);
|
||||
if (estimateError) {
|
||||
double sdfError = estimateSDFError(msdf, shape, projection, SDF_ERROR_ESTIMATE_PRECISION, fillRule);
|
||||
double sdfError = estimateSDFError(msdf, shape, transformation, SDF_ERROR_ESTIMATE_PRECISION, fillRule);
|
||||
printf("SDF error ~ %e\n", sdfError);
|
||||
}
|
||||
if (testRenderMulti) {
|
||||
Bitmap<float, 3> render(testWidthM, testHeightM);
|
||||
renderSDF(render, msdf, avgScale*range, .5f+outputDistanceShift);
|
||||
renderSDF(render, msdf, avgScale*range);
|
||||
if (!SAVE_DEFAULT_IMAGE_FORMAT(render, testRenderMulti))
|
||||
fputs("Failed to write test render file.\n", stderr);
|
||||
}
|
||||
if (testRender) {
|
||||
Bitmap<float, 1> render(testWidth, testHeight);
|
||||
renderSDF(render, msdf, avgScale*range, .5f+outputDistanceShift);
|
||||
renderSDF(render, msdf, avgScale*range);
|
||||
if (!SAVE_DEFAULT_IMAGE_FORMAT(render, testRender))
|
||||
fputs("Failed to write test render file.\n", stderr);
|
||||
}
|
||||
|
|
@ -1291,18 +1302,18 @@ int main(int argc, const char *const *argv) {
|
|||
if (is8bitFormat(format) && (testRenderMulti || testRender || estimateError))
|
||||
simulate8bit(mtsdf);
|
||||
if (estimateError) {
|
||||
double sdfError = estimateSDFError(mtsdf, shape, projection, SDF_ERROR_ESTIMATE_PRECISION, fillRule);
|
||||
double sdfError = estimateSDFError(mtsdf, shape, transformation, SDF_ERROR_ESTIMATE_PRECISION, fillRule);
|
||||
printf("SDF error ~ %e\n", sdfError);
|
||||
}
|
||||
if (testRenderMulti) {
|
||||
Bitmap<float, 4> render(testWidthM, testHeightM);
|
||||
renderSDF(render, mtsdf, avgScale*range, .5f+outputDistanceShift);
|
||||
renderSDF(render, mtsdf, avgScale*range);
|
||||
if (!SAVE_DEFAULT_IMAGE_FORMAT(render, testRenderMulti))
|
||||
fputs("Failed to write test render file.\n", stderr);
|
||||
}
|
||||
if (testRender) {
|
||||
Bitmap<float, 1> render(testWidth, testHeight);
|
||||
renderSDF(render, mtsdf, avgScale*range, .5f+outputDistanceShift);
|
||||
renderSDF(render, mtsdf, avgScale*range);
|
||||
if (!SAVE_DEFAULT_IMAGE_FORMAT(render, testRender))
|
||||
fputs("Failed to write test render file.\n", stderr);
|
||||
}
|
||||
|
|
|
|||
37
msdfgen.h
37
msdfgen.h
|
|
@ -18,7 +18,10 @@
|
|||
#include "core/base.h"
|
||||
#include "core/arithmetics.hpp"
|
||||
#include "core/Vector2.hpp"
|
||||
#include "core/Range.hpp"
|
||||
#include "core/Projection.h"
|
||||
#include "core/DistanceMapping.h"
|
||||
#include "core/SDFTransformation.h"
|
||||
#include "core/Scanline.h"
|
||||
#include "core/Shape.h"
|
||||
#include "core/BitmapRef.hpp"
|
||||
|
|
@ -38,31 +41,35 @@
|
|||
namespace msdfgen {
|
||||
|
||||
/// Generates a conventional single-channel signed distance field.
|
||||
void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, double range, const GeneratorConfig &config = GeneratorConfig());
|
||||
void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, const SDFTransformation &transformation, const GeneratorConfig &config = GeneratorConfig());
|
||||
|
||||
/// Generates a single-channel signed perpendicular distance field.
|
||||
void generatePSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, double range, const GeneratorConfig &config = GeneratorConfig());
|
||||
void generatePSDF(const BitmapRef<float, 1> &output, const Shape &shape, const SDFTransformation &transformation, const GeneratorConfig &config = GeneratorConfig());
|
||||
|
||||
/// Generates a multi-channel signed distance field. Edge colors must be assigned first! (See edgeColoringSimple)
|
||||
void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
|
||||
/// Generates a multi-channel signed distance field with true distance in the alpha channel. Edge colors must be assigned first.
|
||||
void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
|
||||
// Old version of the function API's kept for backwards compatibility
|
||||
void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, double range, const GeneratorConfig &config = GeneratorConfig());
|
||||
void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config = GeneratorConfig());
|
||||
void generatePSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config = GeneratorConfig());
|
||||
void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config = GeneratorConfig());
|
||||
void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
|
||||
void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport = true);
|
||||
void generatePSDF(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport = true);
|
||||
void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport = true);
|
||||
void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig = ErrorCorrectionConfig(), bool overlapSupport = true);
|
||||
void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig = ErrorCorrectionConfig(), bool overlapSupport = true);
|
||||
void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport = true);
|
||||
void generatePSDF(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport = true);
|
||||
void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport = true);
|
||||
void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig = ErrorCorrectionConfig(), bool overlapSupport = true);
|
||||
void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig = ErrorCorrectionConfig(), bool overlapSupport = true);
|
||||
|
||||
// Original simpler versions of the previous functions, which work well under normal circumstances, but cannot deal with overlapping contours.
|
||||
void generateSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate);
|
||||
void generatePSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate);
|
||||
void generatePseudoSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate);
|
||||
void generateMSDF_legacy(const BitmapRef<float, 3> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig = ErrorCorrectionConfig());
|
||||
void generateMTSDF_legacy(const BitmapRef<float, 4> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig = ErrorCorrectionConfig());
|
||||
void generateSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate);
|
||||
void generatePSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate);
|
||||
void generatePseudoSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate);
|
||||
void generateMSDF_legacy(const BitmapRef<float, 3> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig = ErrorCorrectionConfig());
|
||||
void generateMTSDF_legacy(const BitmapRef<float, 4> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig = ErrorCorrectionConfig());
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue