msdfgen: Update to 1.12
This commit is contained in:
parent
24d74510e5
commit
c97c7b73e6
@ -469,7 +469,7 @@ License: BSD-2-clause
|
||||
|
||||
Files: ./thirdparty/msdfgen/
|
||||
Comment: Multi-channel signed distance field generator
|
||||
Copyright: 2016-2022, Viktor Chlumsky
|
||||
Copyright: 2014-2024, Viktor Chlumsky
|
||||
License: Expat
|
||||
|
||||
Files: ./thirdparty/nvapi/nvapi_minimal.h
|
||||
|
@ -16,6 +16,7 @@ if env["builtin_msdfgen"]:
|
||||
thirdparty_dir = "#thirdparty/msdfgen/"
|
||||
thirdparty_sources = [
|
||||
"core/Contour.cpp",
|
||||
"core/DistanceMapping.cpp",
|
||||
"core/EdgeHolder.cpp",
|
||||
"core/MSDFErrorCorrection.cpp",
|
||||
"core/Projection.cpp",
|
||||
@ -26,10 +27,15 @@ if env["builtin_msdfgen"]:
|
||||
"core/edge-segments.cpp",
|
||||
"core/edge-selectors.cpp",
|
||||
"core/equation-solver.cpp",
|
||||
# "core/export-svg.cpp",
|
||||
"core/msdf-error-correction.cpp",
|
||||
"core/msdfgen.cpp",
|
||||
"core/rasterization.cpp",
|
||||
"core/render-sdf.cpp",
|
||||
# "core/save-bmp.cpp",
|
||||
# "core/save-fl32.cpp",
|
||||
# "core/save-rgba.cpp",
|
||||
# "core/save-tiff.cpp",
|
||||
"core/sdf-error-estimation.cpp",
|
||||
"core/shape-description.cpp",
|
||||
]
|
||||
|
@ -123,6 +123,7 @@ if env["msdfgen_enabled"] and env["freetype_enabled"]:
|
||||
thirdparty_msdfgen_dir = "../../../thirdparty/msdfgen/"
|
||||
thirdparty_msdfgen_sources = [
|
||||
"core/Contour.cpp",
|
||||
"core/DistanceMapping.cpp",
|
||||
"core/EdgeHolder.cpp",
|
||||
"core/MSDFErrorCorrection.cpp",
|
||||
"core/Projection.cpp",
|
||||
@ -133,10 +134,15 @@ if env["msdfgen_enabled"] and env["freetype_enabled"]:
|
||||
"core/edge-segments.cpp",
|
||||
"core/edge-selectors.cpp",
|
||||
"core/equation-solver.cpp",
|
||||
# "core/export-svg.cpp",
|
||||
"core/msdf-error-correction.cpp",
|
||||
"core/msdfgen.cpp",
|
||||
"core/rasterization.cpp",
|
||||
"core/render-sdf.cpp",
|
||||
# "core/save-bmp.cpp",
|
||||
# "core/save-fl32.cpp",
|
||||
# "core/save-rgba.cpp",
|
||||
# "core/save-tiff.cpp",
|
||||
"core/sdf-error-estimation.cpp",
|
||||
"core/shape-description.cpp",
|
||||
]
|
||||
|
@ -69,6 +69,7 @@ using namespace godot;
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4458)
|
||||
#endif
|
||||
#include <core/EdgeHolder.h>
|
||||
#include <core/ShapeDistanceFinder.h>
|
||||
#include <core/contour-combiners.h>
|
||||
#include <core/edge-selectors.h>
|
||||
|
@ -118,6 +118,7 @@ if env["msdfgen_enabled"] and env["freetype_enabled"]:
|
||||
thirdparty_msdfgen_dir = "../../../thirdparty/msdfgen/"
|
||||
thirdparty_msdfgen_sources = [
|
||||
"core/Contour.cpp",
|
||||
"core/DistanceMapping.cpp",
|
||||
"core/EdgeHolder.cpp",
|
||||
"core/MSDFErrorCorrection.cpp",
|
||||
"core/Projection.cpp",
|
||||
@ -128,10 +129,15 @@ if env["msdfgen_enabled"] and env["freetype_enabled"]:
|
||||
"core/edge-segments.cpp",
|
||||
"core/edge-selectors.cpp",
|
||||
"core/equation-solver.cpp",
|
||||
# "core/export-svg.cpp",
|
||||
"core/msdf-error-correction.cpp",
|
||||
"core/msdfgen.cpp",
|
||||
"core/rasterization.cpp",
|
||||
"core/render-sdf.cpp",
|
||||
# "core/save-bmp.cpp",
|
||||
# "core/save-fl32.cpp",
|
||||
# "core/save-rgba.cpp",
|
||||
# "core/save-tiff.cpp",
|
||||
"core/sdf-error-estimation.cpp",
|
||||
"core/shape-description.cpp",
|
||||
]
|
||||
|
@ -64,6 +64,7 @@ using namespace godot;
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4458)
|
||||
#endif
|
||||
#include <core/EdgeHolder.h>
|
||||
#include <core/ShapeDistanceFinder.h>
|
||||
#include <core/contour-combiners.h>
|
||||
#include <core/edge-selectors.h>
|
||||
|
2
thirdparty/README.md
vendored
2
thirdparty/README.md
vendored
@ -763,7 +763,7 @@ Collection of single-file libraries used in Godot components.
|
||||
## msdfgen
|
||||
|
||||
- Upstream: https://github.com/Chlumsky/msdfgen
|
||||
- Version: 1.11 (f12d7ca00091a632a289865b85c3f2e0bfc6542d, 2023)
|
||||
- Version: 1.12 (85e8b3d47b3d1a42e4a5ebda0a24fb1cc2e669e0, 2024)
|
||||
- License: MIT
|
||||
|
||||
Files extracted from the upstream source:
|
||||
|
2
thirdparty/msdfgen/LICENSE.txt
vendored
2
thirdparty/msdfgen/LICENSE.txt
vendored
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016 - 2023 Viktor Chlumsky
|
||||
Copyright (c) 2014 - 2024 Viktor Chlumsky
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
27
thirdparty/msdfgen/core/DistanceMapping.cpp
vendored
Normal file
27
thirdparty/msdfgen/core/DistanceMapping.cpp
vendored
Normal file
@ -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);
|
||||
}
|
||||
|
||||
}
|
36
thirdparty/msdfgen/core/DistanceMapping.h
vendored
Normal file
36
thirdparty/msdfgen/core/DistanceMapping.h
vendored
Normal file
@ -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) { }
|
||||
|
||||
};
|
||||
|
||||
}
|
10
thirdparty/msdfgen/core/EdgeHolder.cpp
vendored
10
thirdparty/msdfgen/core/EdgeHolder.cpp
vendored
@ -9,16 +9,6 @@ void EdgeHolder::swap(EdgeHolder &a, EdgeHolder &b) {
|
||||
b.edgeSegment = tmp;
|
||||
}
|
||||
|
||||
EdgeHolder::EdgeHolder() : edgeSegment(NULL) { }
|
||||
|
||||
EdgeHolder::EdgeHolder(EdgeSegment *segment) : edgeSegment(segment) { }
|
||||
|
||||
EdgeHolder::EdgeHolder(Point2 p0, Point2 p1, EdgeColor edgeColor) : edgeSegment(new LinearSegment(p0, p1, edgeColor)) { }
|
||||
|
||||
EdgeHolder::EdgeHolder(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor) : edgeSegment(new QuadraticSegment(p0, p1, p2, edgeColor)) { }
|
||||
|
||||
EdgeHolder::EdgeHolder(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor) : edgeSegment(new CubicSegment(p0, p1, p2, p3, edgeColor)) { }
|
||||
|
||||
EdgeHolder::EdgeHolder(const EdgeHolder &orig) : edgeSegment(orig.edgeSegment ? orig.edgeSegment->clone() : NULL) { }
|
||||
|
||||
#ifdef MSDFGEN_USE_CPP11
|
||||
|
10
thirdparty/msdfgen/core/EdgeHolder.h
vendored
10
thirdparty/msdfgen/core/EdgeHolder.h
vendored
@ -12,11 +12,11 @@ public:
|
||||
/// Swaps the edges held by a and b.
|
||||
static void swap(EdgeHolder &a, EdgeHolder &b);
|
||||
|
||||
EdgeHolder();
|
||||
EdgeHolder(EdgeSegment *segment);
|
||||
EdgeHolder(Point2 p0, Point2 p1, EdgeColor edgeColor = WHITE);
|
||||
EdgeHolder(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor = WHITE);
|
||||
EdgeHolder(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor = WHITE);
|
||||
inline EdgeHolder() : edgeSegment() { }
|
||||
inline EdgeHolder(EdgeSegment *segment) : edgeSegment(segment) { }
|
||||
inline EdgeHolder(Point2 p0, Point2 p1, EdgeColor edgeColor = WHITE) : edgeSegment(EdgeSegment::create(p0, p1, edgeColor)) { }
|
||||
inline EdgeHolder(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor = WHITE) : edgeSegment(EdgeSegment::create(p0, p1, p2, edgeColor)) { }
|
||||
inline EdgeHolder(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor = WHITE) : edgeSegment(EdgeSegment::create(p0, p1, p2, p3, edgeColor)) { }
|
||||
EdgeHolder(const EdgeHolder &orig);
|
||||
#ifdef MSDFGEN_USE_CPP11
|
||||
EdgeHolder(EdgeHolder &&orig);
|
||||
|
35
thirdparty/msdfgen/core/MSDFErrorCorrection.cpp
vendored
35
thirdparty/msdfgen/core/MSDFErrorCorrection.cpp
vendored
@ -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,24 +87,23 @@ 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) {
|
||||
return ArtifactClassifier(this, direction, span);
|
||||
}
|
||||
private:
|
||||
ShapeDistanceFinder<ContourCombiner<PseudoDistanceSelector> > distanceFinder;
|
||||
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;
|
||||
|
||||
|
46
thirdparty/msdfgen/core/Range.hpp
vendored
Normal file
46
thirdparty/msdfgen/core/Range.hpp
vendored
Normal file
@ -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);
|
||||
}
|
||||
|
||||
}
|
24
thirdparty/msdfgen/core/SDFTransformation.h
vendored
Normal file
24
thirdparty/msdfgen/core/SDFTransformation.h
vendored
Normal file
@ -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) { }
|
||||
|
||||
};
|
||||
|
||||
}
|
26
thirdparty/msdfgen/core/Shape.cpp
vendored
26
thirdparty/msdfgen/core/Shape.cpp
vendored
@ -4,6 +4,8 @@
|
||||
#include <cstdlib>
|
||||
#include "arithmetics.hpp"
|
||||
|
||||
#define DECONVERGE_OVERSHOOT 1.11111111111111111 // moves control points slightly more than necessary to account for floating-point errors
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
Shape::Shape() : inverseYAxis(false) { }
|
||||
@ -39,13 +41,23 @@ bool Shape::validate() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void deconvergeEdge(EdgeHolder &edgeHolder, int param) {
|
||||
static void deconvergeEdge(EdgeHolder &edgeHolder, int param, Vector2 vector) {
|
||||
switch (edgeHolder->type()) {
|
||||
case (int) QuadraticSegment::EDGE_TYPE:
|
||||
edgeHolder = static_cast<const QuadraticSegment *>(&*edgeHolder)->convertToCubic();
|
||||
// fallthrough
|
||||
case (int) CubicSegment::EDGE_TYPE:
|
||||
static_cast<CubicSegment *>(&*edgeHolder)->deconverge(param, MSDFGEN_DECONVERGENCE_FACTOR);
|
||||
{
|
||||
Point2 *p = static_cast<CubicSegment *>(&*edgeHolder)->p;
|
||||
switch (param) {
|
||||
case 0:
|
||||
p[1] += (p[1]-p[0]).length()*vector;
|
||||
break;
|
||||
case 1:
|
||||
p[2] += (p[2]-p[3]).length()*vector;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,13 +71,19 @@ void Shape::normalize() {
|
||||
contour->edges.push_back(EdgeHolder(parts[1]));
|
||||
contour->edges.push_back(EdgeHolder(parts[2]));
|
||||
} else {
|
||||
// Push apart convergent edge segments
|
||||
EdgeHolder *prevEdge = &contour->edges.back();
|
||||
for (std::vector<EdgeHolder>::iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
|
||||
Vector2 prevDir = (*prevEdge)->direction(1).normalize();
|
||||
Vector2 curDir = (*edge)->direction(0).normalize();
|
||||
if (dotProduct(prevDir, curDir) < MSDFGEN_CORNER_DOT_EPSILON-1) {
|
||||
deconvergeEdge(*prevEdge, 1);
|
||||
deconvergeEdge(*edge, 0);
|
||||
double factor = DECONVERGE_OVERSHOOT*sqrt(1-(MSDFGEN_CORNER_DOT_EPSILON-1)*(MSDFGEN_CORNER_DOT_EPSILON-1))/(MSDFGEN_CORNER_DOT_EPSILON-1);
|
||||
Vector2 axis = factor*(curDir-prevDir).normalize();
|
||||
// Determine curve ordering using third-order derivative (t = 0) of crossProduct((*prevEdge)->point(1-t)-p0, (*edge)->point(t)-p0) where p0 is the corner (*edge)->point(0)
|
||||
if (crossProduct((*prevEdge)->directionChange(1), (*edge)->direction(0))+crossProduct((*edge)->directionChange(0), (*prevEdge)->direction(1)) < 0)
|
||||
axis = -axis;
|
||||
deconvergeEdge(*prevEdge, 1, axis.getOrthogonal(true));
|
||||
deconvergeEdge(*edge, 0, axis.getOrthogonal(false));
|
||||
}
|
||||
prevEdge = &*edge;
|
||||
}
|
||||
|
2
thirdparty/msdfgen/core/Shape.h
vendored
2
thirdparty/msdfgen/core/Shape.h
vendored
@ -9,8 +9,6 @@ namespace msdfgen {
|
||||
|
||||
// Threshold of the dot product of adjacent edge directions to be considered convergent.
|
||||
#define MSDFGEN_CORNER_DOT_EPSILON .000001
|
||||
// The proportional amount by which a curve's control point will be adjusted to eliminate convergent corners.
|
||||
#define MSDFGEN_DECONVERGENCE_FACTOR .000001
|
||||
|
||||
/// Vector shape representation.
|
||||
class Shape {
|
||||
|
4
thirdparty/msdfgen/core/Vector2.hpp
vendored
4
thirdparty/msdfgen/core/Vector2.hpp
vendored
@ -24,8 +24,8 @@ struct Vector2 {
|
||||
}
|
||||
|
||||
/// Sets individual elements of the vector.
|
||||
inline void set(double x, double y) {
|
||||
this->x = x, this->y = y;
|
||||
inline void set(double newX, double newY) {
|
||||
x = newX, y = newY;
|
||||
}
|
||||
|
||||
/// Returns the vector's squared length.
|
||||
|
11
thirdparty/msdfgen/core/contour-combiners.cpp
vendored
11
thirdparty/msdfgen/core/contour-combiners.cpp
vendored
@ -16,6 +16,13 @@ static void initDistance(MultiDistance &distance) {
|
||||
distance.b = -DBL_MAX;
|
||||
}
|
||||
|
||||
static void initDistance(MultiAndTrueDistance &distance) {
|
||||
distance.r = -DBL_MAX;
|
||||
distance.g = -DBL_MAX;
|
||||
distance.b = -DBL_MAX;
|
||||
distance.a = -DBL_MAX;
|
||||
}
|
||||
|
||||
static double resolveDistance(double distance) {
|
||||
return distance;
|
||||
}
|
||||
@ -43,7 +50,7 @@ typename SimpleContourCombiner<EdgeSelector>::DistanceType SimpleContourCombiner
|
||||
}
|
||||
|
||||
template class SimpleContourCombiner<TrueDistanceSelector>;
|
||||
template class SimpleContourCombiner<PseudoDistanceSelector>;
|
||||
template class SimpleContourCombiner<PerpendicularDistanceSelector>;
|
||||
template class SimpleContourCombiner<MultiDistanceSelector>;
|
||||
template class SimpleContourCombiner<MultiAndTrueDistanceSelector>;
|
||||
|
||||
@ -127,7 +134,7 @@ typename OverlappingContourCombiner<EdgeSelector>::DistanceType OverlappingConto
|
||||
}
|
||||
|
||||
template class OverlappingContourCombiner<TrueDistanceSelector>;
|
||||
template class OverlappingContourCombiner<PseudoDistanceSelector>;
|
||||
template class OverlappingContourCombiner<PerpendicularDistanceSelector>;
|
||||
template class OverlappingContourCombiner<MultiDistanceSelector>;
|
||||
template class OverlappingContourCombiner<MultiAndTrueDistanceSelector>;
|
||||
|
||||
|
116
thirdparty/msdfgen/core/edge-coloring.cpp
vendored
116
thirdparty/msdfgen/core/edge-coloring.cpp
vendored
@ -11,6 +11,15 @@
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/**
|
||||
* For each position < n, this function will return -1, 0, or 1,
|
||||
* depending on whether the position is closer to the beginning, middle, or end, respectively.
|
||||
* It is guaranteed that the output will be balanced in that the total for positions 0 through n-1 will be zero.
|
||||
*/
|
||||
static int symmetricalTrichotomy(int position, int n) {
|
||||
return int(3+2.875*position/(n-1)-1.4375+.5)-3;
|
||||
}
|
||||
|
||||
static bool isCorner(const Vector2 &aDir, const Vector2 &bDir, double crossThreshold) {
|
||||
return dotProduct(aDir, bDir) <= 0 || fabs(crossProduct(aDir, bDir)) > crossThreshold;
|
||||
}
|
||||
@ -26,30 +35,45 @@ static double estimateEdgeLength(const EdgeSegment *edge) {
|
||||
return len;
|
||||
}
|
||||
|
||||
static void switchColor(EdgeColor &color, unsigned long long &seed, EdgeColor banned = BLACK) {
|
||||
EdgeColor combined = EdgeColor(color&banned);
|
||||
if (combined == RED || combined == GREEN || combined == BLUE) {
|
||||
color = EdgeColor(combined^WHITE);
|
||||
return;
|
||||
}
|
||||
if (color == BLACK || color == WHITE) {
|
||||
static const EdgeColor start[3] = { CYAN, MAGENTA, YELLOW };
|
||||
color = start[seed%3];
|
||||
seed /= 3;
|
||||
return;
|
||||
}
|
||||
int shifted = color<<(1+(seed&1));
|
||||
color = EdgeColor((shifted|shifted>>3)&WHITE);
|
||||
static int seedExtract2(unsigned long long &seed) {
|
||||
int v = int(seed)&1;
|
||||
seed >>= 1;
|
||||
return v;
|
||||
}
|
||||
|
||||
static int seedExtract3(unsigned long long &seed) {
|
||||
int v = int(seed%3);
|
||||
seed /= 3;
|
||||
return v;
|
||||
}
|
||||
|
||||
static EdgeColor initColor(unsigned long long &seed) {
|
||||
static const EdgeColor colors[3] = { CYAN, MAGENTA, YELLOW };
|
||||
return colors[seedExtract3(seed)];
|
||||
}
|
||||
|
||||
static void switchColor(EdgeColor &color, unsigned long long &seed) {
|
||||
int shifted = color<<(1+seedExtract2(seed));
|
||||
color = EdgeColor((shifted|shifted>>3)&WHITE);
|
||||
}
|
||||
|
||||
static void switchColor(EdgeColor &color, unsigned long long &seed, EdgeColor banned) {
|
||||
EdgeColor combined = EdgeColor(color&banned);
|
||||
if (combined == RED || combined == GREEN || combined == BLUE)
|
||||
color = EdgeColor(combined^WHITE);
|
||||
else
|
||||
switchColor(color, seed);
|
||||
}
|
||||
|
||||
void edgeColoringSimple(Shape &shape, double angleThreshold, unsigned long long seed) {
|
||||
double crossThreshold = sin(angleThreshold);
|
||||
EdgeColor color = initColor(seed);
|
||||
std::vector<int> corners;
|
||||
for (std::vector<Contour>::iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
|
||||
// Identify corners
|
||||
corners.clear();
|
||||
if (!contour->edges.empty()) {
|
||||
if (contour->edges.empty())
|
||||
continue;
|
||||
{ // Identify corners
|
||||
corners.clear();
|
||||
Vector2 prevDirection = contour->edges.back()->direction(1);
|
||||
int index = 0;
|
||||
for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge, ++index) {
|
||||
@ -60,19 +84,24 @@ void edgeColoringSimple(Shape &shape, double angleThreshold, unsigned long long
|
||||
}
|
||||
|
||||
// Smooth contour
|
||||
if (corners.empty())
|
||||
if (corners.empty()) {
|
||||
switchColor(color, seed);
|
||||
for (std::vector<EdgeHolder>::iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge)
|
||||
(*edge)->color = WHITE;
|
||||
(*edge)->color = color;
|
||||
}
|
||||
// "Teardrop" case
|
||||
else if (corners.size() == 1) {
|
||||
EdgeColor colors[3] = { WHITE, WHITE };
|
||||
switchColor(colors[0], seed);
|
||||
switchColor(colors[2] = colors[0], seed);
|
||||
EdgeColor colors[3];
|
||||
switchColor(color, seed);
|
||||
colors[0] = color;
|
||||
colors[1] = WHITE;
|
||||
switchColor(color, seed);
|
||||
colors[2] = color;
|
||||
int corner = corners[0];
|
||||
if (contour->edges.size() >= 3) {
|
||||
int m = (int) contour->edges.size();
|
||||
for (int i = 0; i < m; ++i)
|
||||
contour->edges[(corner+i)%m]->color = (colors+1)[int(3+2.875*i/(m-1)-1.4375+.5)-3];
|
||||
contour->edges[(corner+i)%m]->color = colors[1+symmetricalTrichotomy(i, m)];
|
||||
} else if (contour->edges.size() >= 1) {
|
||||
// Less than three edge segments for three colors => edges must be split
|
||||
EdgeSegment *parts[7] = { };
|
||||
@ -98,7 +127,6 @@ void edgeColoringSimple(Shape &shape, double angleThreshold, unsigned long long
|
||||
int spline = 0;
|
||||
int start = corners[0];
|
||||
int m = (int) contour->edges.size();
|
||||
EdgeColor color = WHITE;
|
||||
switchColor(color, seed);
|
||||
EdgeColor initialColor = color;
|
||||
for (int i = 0; i < m; ++i) {
|
||||
@ -123,12 +151,14 @@ struct EdgeColoringInkTrapCorner {
|
||||
void edgeColoringInkTrap(Shape &shape, double angleThreshold, unsigned long long seed) {
|
||||
typedef EdgeColoringInkTrapCorner Corner;
|
||||
double crossThreshold = sin(angleThreshold);
|
||||
EdgeColor color = initColor(seed);
|
||||
std::vector<Corner> corners;
|
||||
for (std::vector<Contour>::iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
|
||||
// Identify corners
|
||||
if (contour->edges.empty())
|
||||
continue;
|
||||
double splineLength = 0;
|
||||
corners.clear();
|
||||
if (!contour->edges.empty()) {
|
||||
{ // Identify corners
|
||||
corners.clear();
|
||||
Vector2 prevDirection = contour->edges.back()->direction(1);
|
||||
int index = 0;
|
||||
for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge, ++index) {
|
||||
@ -143,19 +173,24 @@ void edgeColoringInkTrap(Shape &shape, double angleThreshold, unsigned long long
|
||||
}
|
||||
|
||||
// Smooth contour
|
||||
if (corners.empty())
|
||||
if (corners.empty()) {
|
||||
switchColor(color, seed);
|
||||
for (std::vector<EdgeHolder>::iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge)
|
||||
(*edge)->color = WHITE;
|
||||
(*edge)->color = color;
|
||||
}
|
||||
// "Teardrop" case
|
||||
else if (corners.size() == 1) {
|
||||
EdgeColor colors[3] = { WHITE, WHITE };
|
||||
switchColor(colors[0], seed);
|
||||
switchColor(colors[2] = colors[0], seed);
|
||||
EdgeColor colors[3];
|
||||
switchColor(color, seed);
|
||||
colors[0] = color;
|
||||
colors[1] = WHITE;
|
||||
switchColor(color, seed);
|
||||
colors[2] = color;
|
||||
int corner = corners[0].index;
|
||||
if (contour->edges.size() >= 3) {
|
||||
int m = (int) contour->edges.size();
|
||||
for (int i = 0; i < m; ++i)
|
||||
contour->edges[(corner+i)%m]->color = (colors+1)[int(3+2.875*i/(m-1)-1.4375+.5)-3];
|
||||
contour->edges[(corner+i)%m]->color = colors[1+symmetricalTrichotomy(i, m)];
|
||||
} else if (contour->edges.size() >= 1) {
|
||||
// Less than three edge segments for three colors => edges must be split
|
||||
EdgeSegment *parts[7] = { };
|
||||
@ -191,7 +226,6 @@ void edgeColoringInkTrap(Shape &shape, double angleThreshold, unsigned long long
|
||||
}
|
||||
}
|
||||
}
|
||||
EdgeColor color = WHITE;
|
||||
EdgeColor initialColor = BLACK;
|
||||
for (int i = 0; i < cornerCount; ++i) {
|
||||
if (!corners[i].minor) {
|
||||
@ -271,23 +305,19 @@ static void colorSecondDegreeGraph(int *coloring, const int *const *edgeMatrix,
|
||||
color = 1;
|
||||
break;
|
||||
case 3:
|
||||
color = (int) seed&1;
|
||||
seed >>= 1;
|
||||
color = seedExtract2(seed); // 0 or 1
|
||||
break;
|
||||
case 4:
|
||||
color = 2;
|
||||
break;
|
||||
case 5:
|
||||
color = ((int) seed+1&1)<<1;
|
||||
seed >>= 1;
|
||||
color = (int) !seedExtract2(seed)<<1; // 2 or 0
|
||||
break;
|
||||
case 6:
|
||||
color = ((int) seed&1)+1;
|
||||
seed >>= 1;
|
||||
color = seedExtract2(seed)+1; // 1 or 2
|
||||
break;
|
||||
case 7:
|
||||
color = int((seed+i)%3);
|
||||
seed /= 3;
|
||||
color = (seedExtract3(seed)+i)%3; // 0 or 1 or 2
|
||||
break;
|
||||
}
|
||||
coloring[i] = color;
|
||||
@ -394,7 +424,7 @@ void edgeColoringByDistance(Shape &shape, double angleThreshold, unsigned long l
|
||||
for (int i = 0; i < m; ++i) {
|
||||
if (i == m/2)
|
||||
splineStarts.push_back((int) edgeSegments.size());
|
||||
if (int(3+2.875*i/(m-1)-1.4375+.5)-3)
|
||||
if (symmetricalTrichotomy(i, m))
|
||||
edgeSegments.push_back(&*contour->edges[(corner+i)%m]);
|
||||
else
|
||||
contour->edges[(corner+i)%m]->color = WHITE;
|
||||
|
77
thirdparty/msdfgen/core/edge-segments.cpp
vendored
77
thirdparty/msdfgen/core/edge-segments.cpp
vendored
@ -6,15 +6,34 @@
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
void EdgeSegment::distanceToPseudoDistance(SignedDistance &distance, Point2 origin, double param) const {
|
||||
EdgeSegment *EdgeSegment::create(Point2 p0, Point2 p1, EdgeColor edgeColor) {
|
||||
return new LinearSegment(p0, p1, edgeColor);
|
||||
}
|
||||
|
||||
EdgeSegment *EdgeSegment::create(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor) {
|
||||
if (!crossProduct(p1-p0, p2-p1))
|
||||
return new LinearSegment(p0, p2, edgeColor);
|
||||
return new QuadraticSegment(p0, p1, p2, edgeColor);
|
||||
}
|
||||
|
||||
EdgeSegment *EdgeSegment::create(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor) {
|
||||
Vector2 p12 = p2-p1;
|
||||
if (!crossProduct(p1-p0, p12) && !crossProduct(p12, p3-p2))
|
||||
return new LinearSegment(p0, p3, edgeColor);
|
||||
if ((p12 = 1.5*p1-.5*p0) == 1.5*p2-.5*p3)
|
||||
return new QuadraticSegment(p0, p12, p3, edgeColor);
|
||||
return new CubicSegment(p0, p1, p2, p3, edgeColor);
|
||||
}
|
||||
|
||||
void EdgeSegment::distanceToPerpendicularDistance(SignedDistance &distance, Point2 origin, double param) const {
|
||||
if (param < 0) {
|
||||
Vector2 dir = direction(0).normalize();
|
||||
Vector2 aq = origin-point(0);
|
||||
double ts = dotProduct(aq, dir);
|
||||
if (ts < 0) {
|
||||
double pseudoDistance = crossProduct(aq, dir);
|
||||
if (fabs(pseudoDistance) <= fabs(distance.distance)) {
|
||||
distance.distance = pseudoDistance;
|
||||
double perpendicularDistance = crossProduct(aq, dir);
|
||||
if (fabs(perpendicularDistance) <= fabs(distance.distance)) {
|
||||
distance.distance = perpendicularDistance;
|
||||
distance.dot = 0;
|
||||
}
|
||||
}
|
||||
@ -23,9 +42,9 @@ void EdgeSegment::distanceToPseudoDistance(SignedDistance &distance, Point2 orig
|
||||
Vector2 bq = origin-point(1);
|
||||
double ts = dotProduct(bq, dir);
|
||||
if (ts > 0) {
|
||||
double pseudoDistance = crossProduct(bq, dir);
|
||||
if (fabs(pseudoDistance) <= fabs(distance.distance)) {
|
||||
distance.distance = pseudoDistance;
|
||||
double perpendicularDistance = crossProduct(bq, dir);
|
||||
if (fabs(perpendicularDistance) <= fabs(distance.distance)) {
|
||||
distance.distance = perpendicularDistance;
|
||||
distance.dot = 0;
|
||||
}
|
||||
}
|
||||
@ -38,18 +57,12 @@ LinearSegment::LinearSegment(Point2 p0, Point2 p1, EdgeColor edgeColor) : EdgeSe
|
||||
}
|
||||
|
||||
QuadraticSegment::QuadraticSegment(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor) : EdgeSegment(edgeColor) {
|
||||
if (p1 == p0 || p1 == p2)
|
||||
p1 = 0.5*(p0+p2);
|
||||
p[0] = p0;
|
||||
p[1] = p1;
|
||||
p[2] = p2;
|
||||
}
|
||||
|
||||
CubicSegment::CubicSegment(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor) : EdgeSegment(edgeColor) {
|
||||
if ((p1 == p0 || p1 == p3) && (p2 == p0 || p2 == p3)) {
|
||||
p1 = mix(p0, p3, 1/3.);
|
||||
p2 = mix(p0, p3, 2/3.);
|
||||
}
|
||||
p[0] = p0;
|
||||
p[1] = p1;
|
||||
p[2] = p2;
|
||||
@ -486,43 +499,29 @@ void CubicSegment::moveEndPoint(Point2 to) {
|
||||
p[3] = to;
|
||||
}
|
||||
|
||||
void LinearSegment::splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const {
|
||||
part1 = new LinearSegment(p[0], point(1/3.), color);
|
||||
part2 = new LinearSegment(point(1/3.), point(2/3.), color);
|
||||
part3 = new LinearSegment(point(2/3.), p[1], color);
|
||||
void LinearSegment::splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const {
|
||||
part0 = new LinearSegment(p[0], point(1/3.), color);
|
||||
part1 = new LinearSegment(point(1/3.), point(2/3.), color);
|
||||
part2 = new LinearSegment(point(2/3.), p[1], color);
|
||||
}
|
||||
|
||||
void QuadraticSegment::splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const {
|
||||
part1 = new QuadraticSegment(p[0], mix(p[0], p[1], 1/3.), point(1/3.), color);
|
||||
part2 = new QuadraticSegment(point(1/3.), mix(mix(p[0], p[1], 5/9.), mix(p[1], p[2], 4/9.), .5), point(2/3.), color);
|
||||
part3 = new QuadraticSegment(point(2/3.), mix(p[1], p[2], 2/3.), p[2], color);
|
||||
void QuadraticSegment::splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const {
|
||||
part0 = new QuadraticSegment(p[0], mix(p[0], p[1], 1/3.), point(1/3.), color);
|
||||
part1 = new QuadraticSegment(point(1/3.), mix(mix(p[0], p[1], 5/9.), mix(p[1], p[2], 4/9.), .5), point(2/3.), color);
|
||||
part2 = new QuadraticSegment(point(2/3.), mix(p[1], p[2], 2/3.), p[2], color);
|
||||
}
|
||||
|
||||
void CubicSegment::splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const {
|
||||
part1 = new CubicSegment(p[0], p[0] == p[1] ? p[0] : mix(p[0], p[1], 1/3.), mix(mix(p[0], p[1], 1/3.), mix(p[1], p[2], 1/3.), 1/3.), point(1/3.), color);
|
||||
part2 = new CubicSegment(point(1/3.),
|
||||
void CubicSegment::splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const {
|
||||
part0 = new CubicSegment(p[0], p[0] == p[1] ? p[0] : mix(p[0], p[1], 1/3.), mix(mix(p[0], p[1], 1/3.), mix(p[1], p[2], 1/3.), 1/3.), point(1/3.), color);
|
||||
part1 = new CubicSegment(point(1/3.),
|
||||
mix(mix(mix(p[0], p[1], 1/3.), mix(p[1], p[2], 1/3.), 1/3.), mix(mix(p[1], p[2], 1/3.), mix(p[2], p[3], 1/3.), 1/3.), 2/3.),
|
||||
mix(mix(mix(p[0], p[1], 2/3.), mix(p[1], p[2], 2/3.), 2/3.), mix(mix(p[1], p[2], 2/3.), mix(p[2], p[3], 2/3.), 2/3.), 1/3.),
|
||||
point(2/3.), color);
|
||||
part3 = new CubicSegment(point(2/3.), mix(mix(p[1], p[2], 2/3.), mix(p[2], p[3], 2/3.), 2/3.), p[2] == p[3] ? p[3] : mix(p[2], p[3], 2/3.), p[3], color);
|
||||
part2 = new CubicSegment(point(2/3.), mix(mix(p[1], p[2], 2/3.), mix(p[2], p[3], 2/3.), 2/3.), p[2] == p[3] ? p[3] : mix(p[2], p[3], 2/3.), p[3], color);
|
||||
}
|
||||
|
||||
EdgeSegment *QuadraticSegment::convertToCubic() const {
|
||||
return new CubicSegment(p[0], mix(p[0], p[1], 2/3.), mix(p[1], p[2], 1/3.), p[2], color);
|
||||
}
|
||||
|
||||
void CubicSegment::deconverge(int param, double amount) {
|
||||
Vector2 dir = direction(param);
|
||||
Vector2 normal = dir.getOrthonormal();
|
||||
double h = dotProduct(directionChange(param)-dir, normal);
|
||||
switch (param) {
|
||||
case 0:
|
||||
p[1] += amount*(dir+sign(h)*sqrt(fabs(h))*normal);
|
||||
break;
|
||||
case 1:
|
||||
p[2] -= amount*(dir-sign(h)*sqrt(fabs(h))*normal);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
18
thirdparty/msdfgen/core/edge-segments.h
vendored
18
thirdparty/msdfgen/core/edge-segments.h
vendored
@ -17,6 +17,10 @@ class EdgeSegment {
|
||||
public:
|
||||
EdgeColor color;
|
||||
|
||||
static EdgeSegment *create(Point2 p0, Point2 p1, EdgeColor edgeColor = WHITE);
|
||||
static EdgeSegment *create(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor = WHITE);
|
||||
static EdgeSegment *create(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor = WHITE);
|
||||
|
||||
EdgeSegment(EdgeColor edgeColor = WHITE) : color(edgeColor) { }
|
||||
virtual ~EdgeSegment() { }
|
||||
/// Creates a copy of the edge segment.
|
||||
@ -33,8 +37,8 @@ public:
|
||||
virtual Vector2 directionChange(double param) const = 0;
|
||||
/// Returns the minimum signed distance between origin and the edge.
|
||||
virtual SignedDistance signedDistance(Point2 origin, double ¶m) const = 0;
|
||||
/// Converts a previously retrieved signed distance from origin to pseudo-distance.
|
||||
virtual void distanceToPseudoDistance(SignedDistance &distance, Point2 origin, double param) const;
|
||||
/// Converts a previously retrieved signed distance from origin to perpendicular distance.
|
||||
virtual void distanceToPerpendicularDistance(SignedDistance &distance, Point2 origin, double param) const;
|
||||
/// Outputs a list of (at most three) intersections (their X coordinates) with an infinite horizontal scanline at y and returns how many there are.
|
||||
virtual int scanlineIntersections(double x[3], int dy[3], double y) const = 0;
|
||||
/// Adjusts the bounding box to fit the edge segment.
|
||||
@ -47,7 +51,7 @@ public:
|
||||
/// Moves the end point of the edge segment.
|
||||
virtual void moveEndPoint(Point2 to) = 0;
|
||||
/// Splits the edge segments into thirds which together represent the original edge.
|
||||
virtual void splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const = 0;
|
||||
virtual void splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const = 0;
|
||||
|
||||
};
|
||||
|
||||
@ -76,7 +80,7 @@ public:
|
||||
void reverse();
|
||||
void moveStartPoint(Point2 to);
|
||||
void moveEndPoint(Point2 to);
|
||||
void splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const;
|
||||
void splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const;
|
||||
|
||||
};
|
||||
|
||||
@ -105,7 +109,7 @@ public:
|
||||
void reverse();
|
||||
void moveStartPoint(Point2 to);
|
||||
void moveEndPoint(Point2 to);
|
||||
void splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const;
|
||||
void splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const;
|
||||
|
||||
EdgeSegment *convertToCubic() const;
|
||||
|
||||
@ -135,9 +139,7 @@ public:
|
||||
void reverse();
|
||||
void moveStartPoint(Point2 to);
|
||||
void moveEndPoint(Point2 to);
|
||||
void splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const;
|
||||
|
||||
void deconverge(int param, double amount);
|
||||
void splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const;
|
||||
|
||||
};
|
||||
|
||||
|
102
thirdparty/msdfgen/core/edge-selectors.cpp
vendored
102
thirdparty/msdfgen/core/edge-selectors.cpp
vendored
@ -36,48 +36,48 @@ TrueDistanceSelector::DistanceType TrueDistanceSelector::distance() const {
|
||||
return minDistance.distance;
|
||||
}
|
||||
|
||||
PseudoDistanceSelectorBase::EdgeCache::EdgeCache() : absDistance(0), aDomainDistance(0), bDomainDistance(0), aPseudoDistance(0), bPseudoDistance(0) { }
|
||||
PerpendicularDistanceSelectorBase::EdgeCache::EdgeCache() : absDistance(0), aDomainDistance(0), bDomainDistance(0), aPerpendicularDistance(0), bPerpendicularDistance(0) { }
|
||||
|
||||
bool PseudoDistanceSelectorBase::getPseudoDistance(double &distance, const Vector2 &ep, const Vector2 &edgeDir) {
|
||||
bool PerpendicularDistanceSelectorBase::getPerpendicularDistance(double &distance, const Vector2 &ep, const Vector2 &edgeDir) {
|
||||
double ts = dotProduct(ep, edgeDir);
|
||||
if (ts > 0) {
|
||||
double pseudoDistance = crossProduct(ep, edgeDir);
|
||||
if (fabs(pseudoDistance) < fabs(distance)) {
|
||||
distance = pseudoDistance;
|
||||
double perpendicularDistance = crossProduct(ep, edgeDir);
|
||||
if (fabs(perpendicularDistance) < fabs(distance)) {
|
||||
distance = perpendicularDistance;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
PseudoDistanceSelectorBase::PseudoDistanceSelectorBase() : minNegativePseudoDistance(-fabs(minTrueDistance.distance)), minPositivePseudoDistance(fabs(minTrueDistance.distance)), nearEdge(NULL), nearEdgeParam(0) { }
|
||||
PerpendicularDistanceSelectorBase::PerpendicularDistanceSelectorBase() : minNegativePerpendicularDistance(-fabs(minTrueDistance.distance)), minPositivePerpendicularDistance(fabs(minTrueDistance.distance)), nearEdge(NULL), nearEdgeParam(0) { }
|
||||
|
||||
void PseudoDistanceSelectorBase::reset(double delta) {
|
||||
void PerpendicularDistanceSelectorBase::reset(double delta) {
|
||||
minTrueDistance.distance += nonZeroSign(minTrueDistance.distance)*delta;
|
||||
minNegativePseudoDistance = -fabs(minTrueDistance.distance);
|
||||
minPositivePseudoDistance = fabs(minTrueDistance.distance);
|
||||
minNegativePerpendicularDistance = -fabs(minTrueDistance.distance);
|
||||
minPositivePerpendicularDistance = fabs(minTrueDistance.distance);
|
||||
nearEdge = NULL;
|
||||
nearEdgeParam = 0;
|
||||
}
|
||||
|
||||
bool PseudoDistanceSelectorBase::isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *edge, const Point2 &p) const {
|
||||
bool PerpendicularDistanceSelectorBase::isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *edge, const Point2 &p) const {
|
||||
double delta = DISTANCE_DELTA_FACTOR*(p-cache.point).length();
|
||||
return (
|
||||
cache.absDistance-delta <= fabs(minTrueDistance.distance) ||
|
||||
fabs(cache.aDomainDistance) < delta ||
|
||||
fabs(cache.bDomainDistance) < delta ||
|
||||
(cache.aDomainDistance > 0 && (cache.aPseudoDistance < 0 ?
|
||||
cache.aPseudoDistance+delta >= minNegativePseudoDistance :
|
||||
cache.aPseudoDistance-delta <= minPositivePseudoDistance
|
||||
(cache.aDomainDistance > 0 && (cache.aPerpendicularDistance < 0 ?
|
||||
cache.aPerpendicularDistance+delta >= minNegativePerpendicularDistance :
|
||||
cache.aPerpendicularDistance-delta <= minPositivePerpendicularDistance
|
||||
)) ||
|
||||
(cache.bDomainDistance > 0 && (cache.bPseudoDistance < 0 ?
|
||||
cache.bPseudoDistance+delta >= minNegativePseudoDistance :
|
||||
cache.bPseudoDistance-delta <= minPositivePseudoDistance
|
||||
(cache.bDomainDistance > 0 && (cache.bPerpendicularDistance < 0 ?
|
||||
cache.bPerpendicularDistance+delta >= minNegativePerpendicularDistance :
|
||||
cache.bPerpendicularDistance-delta <= minPositivePerpendicularDistance
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
void PseudoDistanceSelectorBase::addEdgeTrueDistance(const EdgeSegment *edge, const SignedDistance &distance, double param) {
|
||||
void PerpendicularDistanceSelectorBase::addEdgeTrueDistance(const EdgeSegment *edge, const SignedDistance &distance, double param) {
|
||||
if (distance < minTrueDistance) {
|
||||
minTrueDistance = distance;
|
||||
nearEdge = edge;
|
||||
@ -85,47 +85,47 @@ void PseudoDistanceSelectorBase::addEdgeTrueDistance(const EdgeSegment *edge, co
|
||||
}
|
||||
}
|
||||
|
||||
void PseudoDistanceSelectorBase::addEdgePseudoDistance(double distance) {
|
||||
if (distance <= 0 && distance > minNegativePseudoDistance)
|
||||
minNegativePseudoDistance = distance;
|
||||
if (distance >= 0 && distance < minPositivePseudoDistance)
|
||||
minPositivePseudoDistance = distance;
|
||||
void PerpendicularDistanceSelectorBase::addEdgePerpendicularDistance(double distance) {
|
||||
if (distance <= 0 && distance > minNegativePerpendicularDistance)
|
||||
minNegativePerpendicularDistance = distance;
|
||||
if (distance >= 0 && distance < minPositivePerpendicularDistance)
|
||||
minPositivePerpendicularDistance = distance;
|
||||
}
|
||||
|
||||
void PseudoDistanceSelectorBase::merge(const PseudoDistanceSelectorBase &other) {
|
||||
void PerpendicularDistanceSelectorBase::merge(const PerpendicularDistanceSelectorBase &other) {
|
||||
if (other.minTrueDistance < minTrueDistance) {
|
||||
minTrueDistance = other.minTrueDistance;
|
||||
nearEdge = other.nearEdge;
|
||||
nearEdgeParam = other.nearEdgeParam;
|
||||
}
|
||||
if (other.minNegativePseudoDistance > minNegativePseudoDistance)
|
||||
minNegativePseudoDistance = other.minNegativePseudoDistance;
|
||||
if (other.minPositivePseudoDistance < minPositivePseudoDistance)
|
||||
minPositivePseudoDistance = other.minPositivePseudoDistance;
|
||||
if (other.minNegativePerpendicularDistance > minNegativePerpendicularDistance)
|
||||
minNegativePerpendicularDistance = other.minNegativePerpendicularDistance;
|
||||
if (other.minPositivePerpendicularDistance < minPositivePerpendicularDistance)
|
||||
minPositivePerpendicularDistance = other.minPositivePerpendicularDistance;
|
||||
}
|
||||
|
||||
double PseudoDistanceSelectorBase::computeDistance(const Point2 &p) const {
|
||||
double minDistance = minTrueDistance.distance < 0 ? minNegativePseudoDistance : minPositivePseudoDistance;
|
||||
double PerpendicularDistanceSelectorBase::computeDistance(const Point2 &p) const {
|
||||
double minDistance = minTrueDistance.distance < 0 ? minNegativePerpendicularDistance : minPositivePerpendicularDistance;
|
||||
if (nearEdge) {
|
||||
SignedDistance distance = minTrueDistance;
|
||||
nearEdge->distanceToPseudoDistance(distance, p, nearEdgeParam);
|
||||
nearEdge->distanceToPerpendicularDistance(distance, p, nearEdgeParam);
|
||||
if (fabs(distance.distance) < fabs(minDistance))
|
||||
minDistance = distance.distance;
|
||||
}
|
||||
return minDistance;
|
||||
}
|
||||
|
||||
SignedDistance PseudoDistanceSelectorBase::trueDistance() const {
|
||||
SignedDistance PerpendicularDistanceSelectorBase::trueDistance() const {
|
||||
return minTrueDistance;
|
||||
}
|
||||
|
||||
void PseudoDistanceSelector::reset(const Point2 &p) {
|
||||
void PerpendicularDistanceSelector::reset(const Point2 &p) {
|
||||
double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
|
||||
PseudoDistanceSelectorBase::reset(delta);
|
||||
PerpendicularDistanceSelectorBase::reset(delta);
|
||||
this->p = p;
|
||||
}
|
||||
|
||||
void PseudoDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
|
||||
void PerpendicularDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
|
||||
if (isEdgeRelevant(cache, edge, p)) {
|
||||
double param;
|
||||
SignedDistance distance = edge->signedDistance(p, param);
|
||||
@ -143,22 +143,22 @@ void PseudoDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEd
|
||||
double bdd = -dotProduct(bp, (bDir+nextDir).normalize(true));
|
||||
if (add > 0) {
|
||||
double pd = distance.distance;
|
||||
if (getPseudoDistance(pd, ap, -aDir))
|
||||
addEdgePseudoDistance(pd = -pd);
|
||||
cache.aPseudoDistance = pd;
|
||||
if (getPerpendicularDistance(pd, ap, -aDir))
|
||||
addEdgePerpendicularDistance(pd = -pd);
|
||||
cache.aPerpendicularDistance = pd;
|
||||
}
|
||||
if (bdd > 0) {
|
||||
double pd = distance.distance;
|
||||
if (getPseudoDistance(pd, bp, bDir))
|
||||
addEdgePseudoDistance(pd);
|
||||
cache.bPseudoDistance = pd;
|
||||
if (getPerpendicularDistance(pd, bp, bDir))
|
||||
addEdgePerpendicularDistance(pd);
|
||||
cache.bPerpendicularDistance = pd;
|
||||
}
|
||||
cache.aDomainDistance = add;
|
||||
cache.bDomainDistance = bdd;
|
||||
}
|
||||
}
|
||||
|
||||
PseudoDistanceSelector::DistanceType PseudoDistanceSelector::distance() const {
|
||||
PerpendicularDistanceSelector::DistanceType PerpendicularDistanceSelector::distance() const {
|
||||
return computeDistance(p);
|
||||
}
|
||||
|
||||
@ -197,28 +197,28 @@ void MultiDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdg
|
||||
double bdd = -dotProduct(bp, (bDir+nextDir).normalize(true));
|
||||
if (add > 0) {
|
||||
double pd = distance.distance;
|
||||
if (PseudoDistanceSelectorBase::getPseudoDistance(pd, ap, -aDir)) {
|
||||
if (PerpendicularDistanceSelectorBase::getPerpendicularDistance(pd, ap, -aDir)) {
|
||||
pd = -pd;
|
||||
if (edge->color&RED)
|
||||
r.addEdgePseudoDistance(pd);
|
||||
r.addEdgePerpendicularDistance(pd);
|
||||
if (edge->color&GREEN)
|
||||
g.addEdgePseudoDistance(pd);
|
||||
g.addEdgePerpendicularDistance(pd);
|
||||
if (edge->color&BLUE)
|
||||
b.addEdgePseudoDistance(pd);
|
||||
b.addEdgePerpendicularDistance(pd);
|
||||
}
|
||||
cache.aPseudoDistance = pd;
|
||||
cache.aPerpendicularDistance = pd;
|
||||
}
|
||||
if (bdd > 0) {
|
||||
double pd = distance.distance;
|
||||
if (PseudoDistanceSelectorBase::getPseudoDistance(pd, bp, bDir)) {
|
||||
if (PerpendicularDistanceSelectorBase::getPerpendicularDistance(pd, bp, bDir)) {
|
||||
if (edge->color&RED)
|
||||
r.addEdgePseudoDistance(pd);
|
||||
r.addEdgePerpendicularDistance(pd);
|
||||
if (edge->color&GREEN)
|
||||
g.addEdgePseudoDistance(pd);
|
||||
g.addEdgePerpendicularDistance(pd);
|
||||
if (edge->color&BLUE)
|
||||
b.addEdgePseudoDistance(pd);
|
||||
b.addEdgePerpendicularDistance(pd);
|
||||
}
|
||||
cache.bPseudoDistance = pd;
|
||||
cache.bPerpendicularDistance = pd;
|
||||
}
|
||||
cache.aDomainDistance = add;
|
||||
cache.bDomainDistance = bdd;
|
||||
|
28
thirdparty/msdfgen/core/edge-selectors.h
vendored
28
thirdparty/msdfgen/core/edge-selectors.h
vendored
@ -38,40 +38,40 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class PseudoDistanceSelectorBase {
|
||||
class PerpendicularDistanceSelectorBase {
|
||||
|
||||
public:
|
||||
struct EdgeCache {
|
||||
Point2 point;
|
||||
double absDistance;
|
||||
double aDomainDistance, bDomainDistance;
|
||||
double aPseudoDistance, bPseudoDistance;
|
||||
double aPerpendicularDistance, bPerpendicularDistance;
|
||||
|
||||
EdgeCache();
|
||||
};
|
||||
|
||||
static bool getPseudoDistance(double &distance, const Vector2 &ep, const Vector2 &edgeDir);
|
||||
static bool getPerpendicularDistance(double &distance, const Vector2 &ep, const Vector2 &edgeDir);
|
||||
|
||||
PseudoDistanceSelectorBase();
|
||||
PerpendicularDistanceSelectorBase();
|
||||
void reset(double delta);
|
||||
bool isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *edge, const Point2 &p) const;
|
||||
void addEdgeTrueDistance(const EdgeSegment *edge, const SignedDistance &distance, double param);
|
||||
void addEdgePseudoDistance(double distance);
|
||||
void merge(const PseudoDistanceSelectorBase &other);
|
||||
void addEdgePerpendicularDistance(double distance);
|
||||
void merge(const PerpendicularDistanceSelectorBase &other);
|
||||
double computeDistance(const Point2 &p) const;
|
||||
SignedDistance trueDistance() const;
|
||||
|
||||
private:
|
||||
SignedDistance minTrueDistance;
|
||||
double minNegativePseudoDistance;
|
||||
double minPositivePseudoDistance;
|
||||
double minNegativePerpendicularDistance;
|
||||
double minPositivePerpendicularDistance;
|
||||
const EdgeSegment *nearEdge;
|
||||
double nearEdgeParam;
|
||||
|
||||
};
|
||||
|
||||
/// Selects the nearest edge by its pseudo-distance.
|
||||
class PseudoDistanceSelector : public PseudoDistanceSelectorBase {
|
||||
/// Selects the nearest edge by its perpendicular distance.
|
||||
class PerpendicularDistanceSelector : public PerpendicularDistanceSelectorBase {
|
||||
|
||||
public:
|
||||
typedef double DistanceType;
|
||||
@ -85,12 +85,12 @@ private:
|
||||
|
||||
};
|
||||
|
||||
/// Selects the nearest edge for each of the three channels by its pseudo-distance.
|
||||
/// Selects the nearest edge for each of the three channels by its perpendicular distance.
|
||||
class MultiDistanceSelector {
|
||||
|
||||
public:
|
||||
typedef MultiDistance DistanceType;
|
||||
typedef PseudoDistanceSelectorBase::EdgeCache EdgeCache;
|
||||
typedef PerpendicularDistanceSelectorBase::EdgeCache EdgeCache;
|
||||
|
||||
void reset(const Point2 &p);
|
||||
void addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge);
|
||||
@ -100,11 +100,11 @@ public:
|
||||
|
||||
private:
|
||||
Point2 p;
|
||||
PseudoDistanceSelectorBase r, g, b;
|
||||
PerpendicularDistanceSelectorBase r, g, b;
|
||||
|
||||
};
|
||||
|
||||
/// Selects the nearest edge for each of the three color channels by its pseudo-distance and by true distance for the alpha channel.
|
||||
/// Selects the nearest edge for each of the three color channels by its perpendicular distance and by true distance for the alpha channel.
|
||||
class MultiAndTrueDistanceSelector : public MultiDistanceSelector {
|
||||
|
||||
public:
|
||||
|
79
thirdparty/msdfgen/core/export-svg.cpp
vendored
Normal file
79
thirdparty/msdfgen/core/export-svg.cpp
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
|
||||
#include "export-svg.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include "edge-segments.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
static void writeSvgCoord(FILE *f, Point2 coord) {
|
||||
fprintf(f, "%.17g %.17g", coord.x, coord.y);
|
||||
}
|
||||
|
||||
static void writeSvgPathDef(FILE *f, const Shape &shape) {
|
||||
bool beginning = true;
|
||||
for (const Contour &c : shape.contours) {
|
||||
if (c.edges.empty())
|
||||
continue;
|
||||
if (beginning)
|
||||
beginning = false;
|
||||
else
|
||||
fputc(' ', f);
|
||||
fputs("M ", f);
|
||||
writeSvgCoord(f, c.edges[0]->controlPoints()[0]);
|
||||
for (const EdgeHolder &e : c.edges) {
|
||||
const Point2 *cp = e->controlPoints();
|
||||
switch (e->type()) {
|
||||
case (int) LinearSegment::EDGE_TYPE:
|
||||
fputs(" L ", f);
|
||||
writeSvgCoord(f, cp[1]);
|
||||
break;
|
||||
case (int) QuadraticSegment::EDGE_TYPE:
|
||||
fputs(" Q ", f);
|
||||
writeSvgCoord(f, cp[1]);
|
||||
fputc(' ', f);
|
||||
writeSvgCoord(f, cp[2]);
|
||||
break;
|
||||
case (int) CubicSegment::EDGE_TYPE:
|
||||
fputs(" C ", f);
|
||||
writeSvgCoord(f, cp[1]);
|
||||
fputc(' ', f);
|
||||
writeSvgCoord(f, cp[2]);
|
||||
fputc(' ', f);
|
||||
writeSvgCoord(f, cp[3]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
fputs(" Z", f);
|
||||
}
|
||||
}
|
||||
|
||||
bool saveSvgShape(const Shape &shape, const char *filename) {
|
||||
if (FILE *f = fopen(filename, "w")) {
|
||||
fputs("<svg xmlns=\"http://www.w3.org/2000/svg\"><path", f);
|
||||
if (!shape.inverseYAxis)
|
||||
fputs(" transform=\"scale(1 -1)\"", f);
|
||||
fputs(" d=\"", f);
|
||||
writeSvgPathDef(f, shape);
|
||||
fputs("\"/></svg>\n", f);
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool saveSvgShape(const Shape &shape, const Shape::Bounds &bounds, const char *filename) {
|
||||
if (FILE *f = fopen(filename, "w")) {
|
||||
fprintf(f, "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"%.17g %.17g %.17g %.17g\"><path", bounds.l, bounds.b, bounds.r-bounds.l, bounds.t-bounds.b);
|
||||
if (!shape.inverseYAxis)
|
||||
fprintf(f, " transform=\"translate(0 %.17g) scale(1 -1)\"", bounds.b+bounds.t);
|
||||
fputs(" d=\"", f);
|
||||
writeSvgPathDef(f, shape);
|
||||
fputs("\"/></svg>\n", f);
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
11
thirdparty/msdfgen/core/export-svg.h
vendored
Normal file
11
thirdparty/msdfgen/core/export-svg.h
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Shape.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
bool saveSvgShape(const Shape &shape, const char *filename);
|
||||
bool saveSvgShape(const Shape &shape, const Shape::Bounds &bounds, const char *filename);
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
20
thirdparty/msdfgen/core/msdf-error-correction.h
vendored
20
thirdparty/msdfgen/core/msdf-error-correction.h
vendored
@ -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);
|
||||
|
158
thirdparty/msdfgen/core/msdfgen.cpp
vendored
158
thirdparty/msdfgen/core/msdfgen.cpp
vendored
@ -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,57 +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 generatePseudoSDF(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<PseudoDistanceSelector> >(output, shape, projection, range);
|
||||
generateDistanceField<OverlappingContourCombiner<PerpendicularDistanceSelector> >(output, shape, transformation);
|
||||
else
|
||||
generateDistanceField<SimpleContourCombiner<PseudoDistanceSelector> >(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 generateSDF(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, 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, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
|
||||
generateSDF(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) {
|
||||
generatePseudoSDF(output, shape, Projection(scale, translate), range, GeneratorConfig(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 generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig, 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, 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
|
||||
@ -140,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 generatePseudoSDF_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
|
||||
@ -167,13 +207,18 @@ void generatePseudoSDF_legacy(const BitmapRef<float, 1> &output, const Shape &sh
|
||||
}
|
||||
}
|
||||
if (nearEdge)
|
||||
(*nearEdge)->distanceToPseudoDistance(minDistance, p, nearParam);
|
||||
*output(x, row) = float(minDistance.distance/range+.5);
|
||||
(*nearEdge)->distanceToPerpendicularDistance(minDistance, p, nearParam);
|
||||
*output(x, row) = float(distanceMapping(minDistance.distance));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void generateMSDF_legacy(const BitmapRef<float, 3> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig) {
|
||||
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, Range range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig) {
|
||||
DistanceMapping distanceMapping(range);
|
||||
#ifdef MSDFGEN_USE_OPENMP
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
@ -212,14 +257,14 @@ void generateMSDF_legacy(const BitmapRef<float, 3> &output, const Shape &shape,
|
||||
}
|
||||
|
||||
if (r.nearEdge)
|
||||
(*r.nearEdge)->distanceToPseudoDistance(r.minDistance, p, r.nearParam);
|
||||
(*r.nearEdge)->distanceToPerpendicularDistance(r.minDistance, p, r.nearParam);
|
||||
if (g.nearEdge)
|
||||
(*g.nearEdge)->distanceToPseudoDistance(g.minDistance, p, g.nearParam);
|
||||
(*g.nearEdge)->distanceToPerpendicularDistance(g.minDistance, p, g.nearParam);
|
||||
if (b.nearEdge)
|
||||
(*b.nearEdge)->distanceToPseudoDistance(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);
|
||||
(*b.nearEdge)->distanceToPerpendicularDistance(b.minDistance, p, b.nearParam);
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -227,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
|
||||
@ -269,15 +315,15 @@ void generateMTSDF_legacy(const BitmapRef<float, 4> &output, const Shape &shape,
|
||||
}
|
||||
|
||||
if (r.nearEdge)
|
||||
(*r.nearEdge)->distanceToPseudoDistance(r.minDistance, p, r.nearParam);
|
||||
(*r.nearEdge)->distanceToPerpendicularDistance(r.minDistance, p, r.nearParam);
|
||||
if (g.nearEdge)
|
||||
(*g.nearEdge)->distanceToPseudoDistance(g.minDistance, p, g.nearParam);
|
||||
(*g.nearEdge)->distanceToPerpendicularDistance(g.minDistance, p, g.nearParam);
|
||||
if (b.nearEdge)
|
||||
(*b.nearEdge)->distanceToPseudoDistance(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);
|
||||
(*b.nearEdge)->distanceToPerpendicularDistance(b.minDistance, p, b.nearParam);
|
||||
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
thirdparty/msdfgen/core/pixel-conversion.hpp
vendored
2
thirdparty/msdfgen/core/pixel-conversion.hpp
vendored
@ -6,7 +6,7 @@
|
||||
namespace msdfgen {
|
||||
|
||||
inline byte pixelFloatToByte(float x) {
|
||||
return byte(clamp(256.f*x, 255.f));
|
||||
return byte(~int(255.5f-255.f*clamp(x)));
|
||||
}
|
||||
|
||||
inline float pixelByteToFloat(byte x) {
|
||||
|
194
thirdparty/msdfgen/core/render-sdf.cpp
vendored
194
thirdparty/msdfgen/core/render-sdf.cpp
vendored
@ -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) {
|
||||
|
13
thirdparty/msdfgen/core/render-sdf.h
vendored
13
thirdparty/msdfgen/core/render-sdf.h
vendored
@ -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);
|
||||
|
2
thirdparty/msdfgen/core/save-bmp.cpp
vendored
2
thirdparty/msdfgen/core/save-bmp.cpp
vendored
@ -8,10 +8,12 @@
|
||||
#ifdef MSDFGEN_USE_CPP11
|
||||
#include <cstdint>
|
||||
#else
|
||||
namespace msdfgen {
|
||||
typedef int int32_t;
|
||||
typedef unsigned uint32_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned char uint8_t;
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "pixel-conversion.hpp"
|
||||
|
39
thirdparty/msdfgen/core/save-fl32.cpp
vendored
Normal file
39
thirdparty/msdfgen/core/save-fl32.cpp
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
|
||||
#include "save-fl32.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
// Requires byte reversal for floats on big-endian platform
|
||||
#ifndef __BIG_ENDIAN__
|
||||
|
||||
template <int N>
|
||||
bool saveFl32(const BitmapConstRef<float, N> &bitmap, const char *filename) {
|
||||
if (FILE *f = fopen(filename, "wb")) {
|
||||
byte header[16] = { byte('F'), byte('L'), byte('3'), byte('2') };
|
||||
header[4] = byte(bitmap.height);
|
||||
header[5] = byte(bitmap.height>>8);
|
||||
header[6] = byte(bitmap.height>>16);
|
||||
header[7] = byte(bitmap.height>>24);
|
||||
header[8] = byte(bitmap.width);
|
||||
header[9] = byte(bitmap.width>>8);
|
||||
header[10] = byte(bitmap.width>>16);
|
||||
header[11] = byte(bitmap.width>>24);
|
||||
header[12] = byte(N);
|
||||
fwrite(header, 1, 16, f);
|
||||
fwrite(bitmap.pixels, sizeof(float), N*bitmap.width*bitmap.height, f);
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template bool saveFl32(const BitmapConstRef<float, 1> &bitmap, const char *filename);
|
||||
template bool saveFl32(const BitmapConstRef<float, 2> &bitmap, const char *filename);
|
||||
template bool saveFl32(const BitmapConstRef<float, 3> &bitmap, const char *filename);
|
||||
template bool saveFl32(const BitmapConstRef<float, 4> &bitmap, const char *filename);
|
||||
|
||||
#endif
|
||||
|
||||
}
|
12
thirdparty/msdfgen/core/save-fl32.h
vendored
Normal file
12
thirdparty/msdfgen/core/save-fl32.h
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BitmapRef.hpp"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Saves the bitmap as an uncompressed floating-point FL32 file, which can be decoded trivially.
|
||||
template <int N>
|
||||
bool saveFl32(const BitmapConstRef<float, N> &bitmap, const char *filename);
|
||||
|
||||
}
|
133
thirdparty/msdfgen/core/save-rgba.cpp
vendored
Normal file
133
thirdparty/msdfgen/core/save-rgba.cpp
vendored
Normal file
@ -0,0 +1,133 @@
|
||||
|
||||
#include "save-rgba.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include "pixel-conversion.hpp"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
class RgbaFileOutput {
|
||||
FILE *file;
|
||||
|
||||
public:
|
||||
RgbaFileOutput(const char *filename, unsigned width, unsigned height) {
|
||||
if ((file = fopen(filename, "wb"))) {
|
||||
byte header[12] = { byte('R'), byte('G'), byte('B'), byte('A') };
|
||||
header[4] = byte(width>>24);
|
||||
header[5] = byte(width>>16);
|
||||
header[6] = byte(width>>8);
|
||||
header[7] = byte(width);
|
||||
header[8] = byte(height>>24);
|
||||
header[9] = byte(height>>16);
|
||||
header[10] = byte(height>>8);
|
||||
header[11] = byte(height);
|
||||
fwrite(header, 1, 12, file);
|
||||
}
|
||||
}
|
||||
|
||||
~RgbaFileOutput() {
|
||||
if (file)
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
void writePixel(const byte rgba[4]) {
|
||||
fwrite(rgba, 1, 4, file);
|
||||
}
|
||||
|
||||
operator FILE *() {
|
||||
return file;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
bool saveRgba(const BitmapConstRef<byte, 1> &bitmap, const char *filename) {
|
||||
RgbaFileOutput output(filename, bitmap.width, bitmap.height);
|
||||
if (output) {
|
||||
byte rgba[4] = { byte(0), byte(0), byte(0), byte(0xff) };
|
||||
for (int y = bitmap.height; y--;) {
|
||||
for (const byte *p = bitmap(0, y), *end = p+bitmap.width; p < end; ++p) {
|
||||
rgba[0] = rgba[1] = rgba[2] = *p;
|
||||
output.writePixel(rgba);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool saveRgba(const BitmapConstRef<byte, 3> &bitmap, const char *filename) {
|
||||
RgbaFileOutput output(filename, bitmap.width, bitmap.height);
|
||||
if (output) {
|
||||
byte rgba[4] = { byte(0), byte(0), byte(0), byte(0xff) };
|
||||
for (int y = bitmap.height; y--;) {
|
||||
for (const byte *p = bitmap(0, y), *end = p+3*bitmap.width; p < end; p += 3) {
|
||||
rgba[0] = p[0], rgba[1] = p[1], rgba[2] = p[2];
|
||||
output.writePixel(rgba);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool saveRgba(const BitmapConstRef<byte, 4> &bitmap, const char *filename) {
|
||||
RgbaFileOutput output(filename, bitmap.width, bitmap.height);
|
||||
if (output) {
|
||||
for (int y = bitmap.height; y--;)
|
||||
fwrite(bitmap(0, y), 1, 4*bitmap.width, output);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool saveRgba(const BitmapConstRef<float, 1> &bitmap, const char *filename) {
|
||||
RgbaFileOutput output(filename, bitmap.width, bitmap.height);
|
||||
if (output) {
|
||||
byte rgba[4] = { byte(0), byte(0), byte(0), byte(0xff) };
|
||||
for (int y = bitmap.height; y--;) {
|
||||
for (const float *p = bitmap(0, y), *end = p+bitmap.width; p < end; ++p) {
|
||||
rgba[0] = rgba[1] = rgba[2] = pixelFloatToByte(*p);
|
||||
output.writePixel(rgba);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool saveRgba(const BitmapConstRef<float, 3> &bitmap, const char *filename) {
|
||||
RgbaFileOutput output(filename, bitmap.width, bitmap.height);
|
||||
if (output) {
|
||||
byte rgba[4] = { byte(0), byte(0), byte(0), byte(0xff) };
|
||||
for (int y = bitmap.height; y--;) {
|
||||
for (const float *p = bitmap(0, y), *end = p+3*bitmap.width; p < end; p += 3) {
|
||||
rgba[0] = pixelFloatToByte(p[0]);
|
||||
rgba[1] = pixelFloatToByte(p[1]);
|
||||
rgba[2] = pixelFloatToByte(p[2]);
|
||||
output.writePixel(rgba);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool saveRgba(const BitmapConstRef<float, 4> &bitmap, const char *filename) {
|
||||
RgbaFileOutput output(filename, bitmap.width, bitmap.height);
|
||||
if (output) {
|
||||
byte rgba[4];
|
||||
for (int y = bitmap.height; y--;) {
|
||||
for (const float *p = bitmap(0, y), *end = p+4*bitmap.width; p < end; p += 4) {
|
||||
rgba[0] = pixelFloatToByte(p[0]);
|
||||
rgba[1] = pixelFloatToByte(p[1]);
|
||||
rgba[2] = pixelFloatToByte(p[2]);
|
||||
rgba[3] = pixelFloatToByte(p[3]);
|
||||
output.writePixel(rgba);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
16
thirdparty/msdfgen/core/save-rgba.h
vendored
Normal file
16
thirdparty/msdfgen/core/save-rgba.h
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BitmapRef.hpp"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Saves the bitmap as a simple RGBA file, which can be decoded trivially.
|
||||
bool saveRgba(const BitmapConstRef<byte, 1> &bitmap, const char *filename);
|
||||
bool saveRgba(const BitmapConstRef<byte, 3> &bitmap, const char *filename);
|
||||
bool saveRgba(const BitmapConstRef<byte, 4> &bitmap, const char *filename);
|
||||
bool saveRgba(const BitmapConstRef<float, 1> &bitmap, const char *filename);
|
||||
bool saveRgba(const BitmapConstRef<float, 3> &bitmap, const char *filename);
|
||||
bool saveRgba(const BitmapConstRef<float, 4> &bitmap, const char *filename);
|
||||
|
||||
}
|
2
thirdparty/msdfgen/core/save-tiff.cpp
vendored
2
thirdparty/msdfgen/core/save-tiff.cpp
vendored
@ -8,10 +8,12 @@
|
||||
#ifdef MSDFGEN_USE_CPP11
|
||||
#include <cstdint>
|
||||
#else
|
||||
namespace msdfgen {
|
||||
typedef int int32_t;
|
||||
typedef unsigned uint32_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned char uint8_t;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace msdfgen {
|
||||
|
23
thirdparty/msdfgen/core/shape-description.cpp
vendored
23
thirdparty/msdfgen/core/shape-description.cpp
vendored
@ -2,6 +2,8 @@
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#include "shape-description.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
int readCharF(FILE *input) {
|
||||
@ -25,14 +27,25 @@ int readCharS(const char **input) {
|
||||
}
|
||||
|
||||
int readCoordF(FILE *input, Point2 &coord) {
|
||||
return fscanf(input, "%lf,%lf", &coord.x, &coord.y);
|
||||
return fscanf(input, "%lf , %lf", &coord.x, &coord.y);
|
||||
}
|
||||
|
||||
int readCoordS(const char **input, Point2 &coord) {
|
||||
int read = 0;
|
||||
int result = sscanf(*input, "%lf,%lf%n", &coord.x, &coord.y, &read);
|
||||
*input += read;
|
||||
return result;
|
||||
char *end = NULL;
|
||||
coord.x = strtod(*input, &end);
|
||||
if (end <= *input)
|
||||
return 0;
|
||||
*input = end;
|
||||
while (**input == ' ' || **input == '\t' || **input == '\n' || **input == '\r')
|
||||
++*input;
|
||||
if (**input != ',')
|
||||
return 1;
|
||||
++*input;
|
||||
coord.y = strtod(*input, &end);
|
||||
if (end <= *input)
|
||||
return 1;
|
||||
*input = end;
|
||||
return 2;
|
||||
}
|
||||
|
||||
static bool writeCoord(FILE *output, Point2 coord) {
|
||||
|
42
thirdparty/msdfgen/msdfgen.h
vendored
42
thirdparty/msdfgen/msdfgen.h
vendored
@ -4,7 +4,7 @@
|
||||
/*
|
||||
* MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR
|
||||
* ---------------------------------------------
|
||||
* A utility by Viktor Chlumsky, (c) 2014 - 2023
|
||||
* A utility by Viktor Chlumsky, (c) 2014 - 2024
|
||||
*
|
||||
* The technique used to generate multi-channel distance fields in this code
|
||||
* has been developed by Viktor Chlumsky in 2014 for his master's thesis,
|
||||
@ -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"
|
||||
@ -33,32 +36,43 @@
|
||||
#include "core/sdf-error-estimation.h"
|
||||
#include "core/save-bmp.h"
|
||||
#include "core/save-tiff.h"
|
||||
#include "core/save-rgba.h"
|
||||
#include "core/save-fl32.h"
|
||||
#include "core/shape-description.h"
|
||||
#include "core/export-svg.h"
|
||||
|
||||
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 pseudo-distance field.
|
||||
void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, double range, const GeneratorConfig &config = GeneratorConfig());
|
||||
/// Generates a single-channel signed perpendicular distance field.
|
||||
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 generateSDF(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, 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, 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 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…
x
Reference in New Issue
Block a user