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/
|
Files: ./thirdparty/msdfgen/
|
||||||
Comment: Multi-channel signed distance field generator
|
Comment: Multi-channel signed distance field generator
|
||||||
Copyright: 2016-2022, Viktor Chlumsky
|
Copyright: 2014-2024, Viktor Chlumsky
|
||||||
License: Expat
|
License: Expat
|
||||||
|
|
||||||
Files: ./thirdparty/nvapi/nvapi_minimal.h
|
Files: ./thirdparty/nvapi/nvapi_minimal.h
|
||||||
|
@ -16,6 +16,7 @@ if env["builtin_msdfgen"]:
|
|||||||
thirdparty_dir = "#thirdparty/msdfgen/"
|
thirdparty_dir = "#thirdparty/msdfgen/"
|
||||||
thirdparty_sources = [
|
thirdparty_sources = [
|
||||||
"core/Contour.cpp",
|
"core/Contour.cpp",
|
||||||
|
"core/DistanceMapping.cpp",
|
||||||
"core/EdgeHolder.cpp",
|
"core/EdgeHolder.cpp",
|
||||||
"core/MSDFErrorCorrection.cpp",
|
"core/MSDFErrorCorrection.cpp",
|
||||||
"core/Projection.cpp",
|
"core/Projection.cpp",
|
||||||
@ -26,10 +27,15 @@ if env["builtin_msdfgen"]:
|
|||||||
"core/edge-segments.cpp",
|
"core/edge-segments.cpp",
|
||||||
"core/edge-selectors.cpp",
|
"core/edge-selectors.cpp",
|
||||||
"core/equation-solver.cpp",
|
"core/equation-solver.cpp",
|
||||||
|
# "core/export-svg.cpp",
|
||||||
"core/msdf-error-correction.cpp",
|
"core/msdf-error-correction.cpp",
|
||||||
"core/msdfgen.cpp",
|
"core/msdfgen.cpp",
|
||||||
"core/rasterization.cpp",
|
"core/rasterization.cpp",
|
||||||
"core/render-sdf.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/sdf-error-estimation.cpp",
|
||||||
"core/shape-description.cpp",
|
"core/shape-description.cpp",
|
||||||
]
|
]
|
||||||
|
@ -123,6 +123,7 @@ if env["msdfgen_enabled"] and env["freetype_enabled"]:
|
|||||||
thirdparty_msdfgen_dir = "../../../thirdparty/msdfgen/"
|
thirdparty_msdfgen_dir = "../../../thirdparty/msdfgen/"
|
||||||
thirdparty_msdfgen_sources = [
|
thirdparty_msdfgen_sources = [
|
||||||
"core/Contour.cpp",
|
"core/Contour.cpp",
|
||||||
|
"core/DistanceMapping.cpp",
|
||||||
"core/EdgeHolder.cpp",
|
"core/EdgeHolder.cpp",
|
||||||
"core/MSDFErrorCorrection.cpp",
|
"core/MSDFErrorCorrection.cpp",
|
||||||
"core/Projection.cpp",
|
"core/Projection.cpp",
|
||||||
@ -133,10 +134,15 @@ if env["msdfgen_enabled"] and env["freetype_enabled"]:
|
|||||||
"core/edge-segments.cpp",
|
"core/edge-segments.cpp",
|
||||||
"core/edge-selectors.cpp",
|
"core/edge-selectors.cpp",
|
||||||
"core/equation-solver.cpp",
|
"core/equation-solver.cpp",
|
||||||
|
# "core/export-svg.cpp",
|
||||||
"core/msdf-error-correction.cpp",
|
"core/msdf-error-correction.cpp",
|
||||||
"core/msdfgen.cpp",
|
"core/msdfgen.cpp",
|
||||||
"core/rasterization.cpp",
|
"core/rasterization.cpp",
|
||||||
"core/render-sdf.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/sdf-error-estimation.cpp",
|
||||||
"core/shape-description.cpp",
|
"core/shape-description.cpp",
|
||||||
]
|
]
|
||||||
|
@ -69,6 +69,7 @@ using namespace godot;
|
|||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(disable : 4458)
|
#pragma warning(disable : 4458)
|
||||||
#endif
|
#endif
|
||||||
|
#include <core/EdgeHolder.h>
|
||||||
#include <core/ShapeDistanceFinder.h>
|
#include <core/ShapeDistanceFinder.h>
|
||||||
#include <core/contour-combiners.h>
|
#include <core/contour-combiners.h>
|
||||||
#include <core/edge-selectors.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_dir = "../../../thirdparty/msdfgen/"
|
||||||
thirdparty_msdfgen_sources = [
|
thirdparty_msdfgen_sources = [
|
||||||
"core/Contour.cpp",
|
"core/Contour.cpp",
|
||||||
|
"core/DistanceMapping.cpp",
|
||||||
"core/EdgeHolder.cpp",
|
"core/EdgeHolder.cpp",
|
||||||
"core/MSDFErrorCorrection.cpp",
|
"core/MSDFErrorCorrection.cpp",
|
||||||
"core/Projection.cpp",
|
"core/Projection.cpp",
|
||||||
@ -128,10 +129,15 @@ if env["msdfgen_enabled"] and env["freetype_enabled"]:
|
|||||||
"core/edge-segments.cpp",
|
"core/edge-segments.cpp",
|
||||||
"core/edge-selectors.cpp",
|
"core/edge-selectors.cpp",
|
||||||
"core/equation-solver.cpp",
|
"core/equation-solver.cpp",
|
||||||
|
# "core/export-svg.cpp",
|
||||||
"core/msdf-error-correction.cpp",
|
"core/msdf-error-correction.cpp",
|
||||||
"core/msdfgen.cpp",
|
"core/msdfgen.cpp",
|
||||||
"core/rasterization.cpp",
|
"core/rasterization.cpp",
|
||||||
"core/render-sdf.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/sdf-error-estimation.cpp",
|
||||||
"core/shape-description.cpp",
|
"core/shape-description.cpp",
|
||||||
]
|
]
|
||||||
|
@ -64,6 +64,7 @@ using namespace godot;
|
|||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(disable : 4458)
|
#pragma warning(disable : 4458)
|
||||||
#endif
|
#endif
|
||||||
|
#include <core/EdgeHolder.h>
|
||||||
#include <core/ShapeDistanceFinder.h>
|
#include <core/ShapeDistanceFinder.h>
|
||||||
#include <core/contour-combiners.h>
|
#include <core/contour-combiners.h>
|
||||||
#include <core/edge-selectors.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
|
## msdfgen
|
||||||
|
|
||||||
- Upstream: https://github.com/Chlumsky/msdfgen
|
- Upstream: https://github.com/Chlumsky/msdfgen
|
||||||
- Version: 1.11 (f12d7ca00091a632a289865b85c3f2e0bfc6542d, 2023)
|
- Version: 1.12 (85e8b3d47b3d1a42e4a5ebda0a24fb1cc2e669e0, 2024)
|
||||||
- License: MIT
|
- License: MIT
|
||||||
|
|
||||||
Files extracted from the upstream source:
|
Files extracted from the upstream source:
|
||||||
|
2
thirdparty/msdfgen/LICENSE.txt
vendored
2
thirdparty/msdfgen/LICENSE.txt
vendored
@ -1,6 +1,6 @@
|
|||||||
MIT License
|
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
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
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;
|
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) { }
|
EdgeHolder::EdgeHolder(const EdgeHolder &orig) : edgeSegment(orig.edgeSegment ? orig.edgeSegment->clone() : NULL) { }
|
||||||
|
|
||||||
#ifdef MSDFGEN_USE_CPP11
|
#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.
|
/// Swaps the edges held by a and b.
|
||||||
static void swap(EdgeHolder &a, EdgeHolder &b);
|
static void swap(EdgeHolder &a, EdgeHolder &b);
|
||||||
|
|
||||||
EdgeHolder();
|
inline EdgeHolder() : edgeSegment() { }
|
||||||
EdgeHolder(EdgeSegment *segment);
|
inline EdgeHolder(EdgeSegment *segment) : edgeSegment(segment) { }
|
||||||
EdgeHolder(Point2 p0, Point2 p1, EdgeColor edgeColor = WHITE);
|
inline EdgeHolder(Point2 p0, Point2 p1, EdgeColor edgeColor = WHITE) : edgeSegment(EdgeSegment::create(p0, p1, edgeColor)) { }
|
||||||
EdgeHolder(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor = WHITE);
|
inline EdgeHolder(Point2 p0, Point2 p1, Point2 p2, EdgeColor edgeColor = WHITE) : edgeSegment(EdgeSegment::create(p0, p1, p2, edgeColor)) { }
|
||||||
EdgeHolder(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor = WHITE);
|
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);
|
EdgeHolder(const EdgeHolder &orig);
|
||||||
#ifdef MSDFGEN_USE_CPP11
|
#ifdef MSDFGEN_USE_CPP11
|
||||||
EdgeHolder(EdgeHolder &&orig);
|
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.
|
// 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 oldPSD = median(oldMSD[0], oldMSD[1], oldMSD[2]);
|
||||||
float newPSD = median(newMSD[0], newMSD[1], newMSD[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.
|
// Compare the differences of the exact distance and the before and after distances.
|
||||||
return parent->minImproveRatio*fabsf(newPSD-refPSD) < double(fabsf(oldPSD-refPSD));
|
return parent->minImproveRatio*fabsf(newPSD-refPSD) < double(fabsf(oldPSD-refPSD));
|
||||||
}
|
}
|
||||||
@ -87,24 +87,23 @@ public:
|
|||||||
Point2 shapeCoord, sdfCoord;
|
Point2 shapeCoord, sdfCoord;
|
||||||
const float *msd;
|
const float *msd;
|
||||||
bool protectedFlag;
|
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));
|
texelSize = projection.unprojectVector(Vector2(1));
|
||||||
}
|
}
|
||||||
inline ArtifactClassifier classifier(const Vector2 &direction, double span) {
|
inline ArtifactClassifier classifier(const Vector2 &direction, double span) {
|
||||||
return ArtifactClassifier(this, direction, span);
|
return ArtifactClassifier(this, direction, span);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
ShapeDistanceFinder<ContourCombiner<PseudoDistanceSelector> > distanceFinder;
|
ShapeDistanceFinder<ContourCombiner<PerpendicularDistanceSelector> > distanceFinder;
|
||||||
BitmapConstRef<float, N> sdf;
|
BitmapConstRef<float, N> sdf;
|
||||||
double invRange;
|
DistanceMapping distanceMapping;
|
||||||
Vector2 texelSize;
|
Vector2 texelSize;
|
||||||
double minImproveRatio;
|
double minImproveRatio;
|
||||||
};
|
};
|
||||||
|
|
||||||
MSDFErrorCorrection::MSDFErrorCorrection() { }
|
MSDFErrorCorrection::MSDFErrorCorrection() { }
|
||||||
|
|
||||||
MSDFErrorCorrection::MSDFErrorCorrection(const BitmapRef<byte, 1> &stencil, const Projection &projection, double range) : stencil(stencil), projection(projection) {
|
MSDFErrorCorrection::MSDFErrorCorrection(const BitmapRef<byte, 1> &stencil, const SDFTransformation &transformation) : stencil(stencil), transformation(transformation) {
|
||||||
invRange = 1/range;
|
|
||||||
minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio;
|
minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio;
|
||||||
minImproveRatio = ErrorCorrectionConfig::defaultMinImproveRatio;
|
minImproveRatio = ErrorCorrectionConfig::defaultMinImproveRatio;
|
||||||
memset(stencil.pixels, 0, sizeof(byte)*stencil.width*stencil.height);
|
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 the color changes from prevEdge to edge, this is a corner.
|
||||||
if (!(commonColor&(commonColor-1))) {
|
if (!(commonColor&(commonColor-1))) {
|
||||||
// Find the four texels that envelop the corner and mark them as protected.
|
// 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)
|
if (shape.inverseYAxis)
|
||||||
p.y = stencil.height-p.y;
|
p.y = stencil.height-p.y;
|
||||||
int l = (int) floor(p.x-.5);
|
int l = (int) floor(p.x-.5);
|
||||||
@ -191,7 +190,7 @@ template <int N>
|
|||||||
void MSDFErrorCorrection::protectEdges(const BitmapConstRef<float, N> &sdf) {
|
void MSDFErrorCorrection::protectEdges(const BitmapConstRef<float, N> &sdf) {
|
||||||
float radius;
|
float radius;
|
||||||
// Horizontal texel pairs
|
// 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) {
|
for (int y = 0; y < sdf.height; ++y) {
|
||||||
const float *left = sdf(0, y);
|
const float *left = sdf(0, y);
|
||||||
const float *right = sdf(1, y);
|
const float *right = sdf(1, y);
|
||||||
@ -207,7 +206,7 @@ void MSDFErrorCorrection::protectEdges(const BitmapConstRef<float, N> &sdf) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Vertical texel pairs
|
// 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) {
|
for (int y = 0; y < sdf.height-1; ++y) {
|
||||||
const float *bottom = sdf(0, y);
|
const float *bottom = sdf(0, y);
|
||||||
const float *top = sdf(0, y+1);
|
const float *top = sdf(0, y+1);
|
||||||
@ -223,7 +222,7 @@ void MSDFErrorCorrection::protectEdges(const BitmapConstRef<float, N> &sdf) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Diagonal texel pairs
|
// 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) {
|
for (int y = 0; y < sdf.height-1; ++y) {
|
||||||
const float *lb = sdf(0, y);
|
const float *lb = sdf(0, y);
|
||||||
const float *rb = sdf(1, y);
|
const float *rb = sdf(1, y);
|
||||||
@ -391,9 +390,9 @@ static bool hasDiagonalArtifact(const ArtifactClassifier &artifactClassifier, fl
|
|||||||
template <int N>
|
template <int N>
|
||||||
void MSDFErrorCorrection::findErrors(const BitmapConstRef<float, N> &sdf) {
|
void MSDFErrorCorrection::findErrors(const BitmapConstRef<float, N> &sdf) {
|
||||||
// Compute the expected deltas between values of horizontally, vertically, and diagonally adjacent texels.
|
// Compute the expected deltas between values of horizontally, vertically, and diagonally adjacent texels.
|
||||||
double hSpan = minDeviationRatio*projection.unprojectVector(Vector2(invRange, 0)).length();
|
double hSpan = minDeviationRatio*transformation.unprojectVector(Vector2(transformation.distanceMapping(DistanceMapping::Delta(1)), 0)).length();
|
||||||
double vSpan = minDeviationRatio*projection.unprojectVector(Vector2(0, invRange)).length();
|
double vSpan = minDeviationRatio*transformation.unprojectVector(Vector2(0, transformation.distanceMapping(DistanceMapping::Delta(1)))).length();
|
||||||
double dSpan = minDeviationRatio*projection.unprojectVector(Vector2(invRange)).length();
|
double dSpan = minDeviationRatio*transformation.unprojectVector(Vector2(transformation.distanceMapping(DistanceMapping::Delta(1)))).length();
|
||||||
// Inspect all texels.
|
// Inspect all texels.
|
||||||
for (int y = 0; y < sdf.height; ++y) {
|
for (int y = 0; y < sdf.height; ++y) {
|
||||||
for (int x = 0; x < sdf.width; ++x) {
|
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>
|
template <template <typename> class ContourCombiner, int N>
|
||||||
void MSDFErrorCorrection::findErrors(const BitmapConstRef<float, N> &sdf, const Shape &shape) {
|
void MSDFErrorCorrection::findErrors(const BitmapConstRef<float, N> &sdf, const Shape &shape) {
|
||||||
// Compute the expected deltas between values of horizontally, vertically, and diagonally adjacent texels.
|
// Compute the expected deltas between values of horizontally, vertically, and diagonally adjacent texels.
|
||||||
double hSpan = minDeviationRatio*projection.unprojectVector(Vector2(invRange, 0)).length();
|
double hSpan = minDeviationRatio*transformation.unprojectVector(Vector2(transformation.distanceMapping(DistanceMapping::Delta(1)), 0)).length();
|
||||||
double vSpan = minDeviationRatio*projection.unprojectVector(Vector2(0, invRange)).length();
|
double vSpan = minDeviationRatio*transformation.unprojectVector(Vector2(0, transformation.distanceMapping(DistanceMapping::Delta(1)))).length();
|
||||||
double dSpan = minDeviationRatio*projection.unprojectVector(Vector2(invRange)).length();
|
double dSpan = minDeviationRatio*transformation.unprojectVector(Vector2(transformation.distanceMapping(DistanceMapping::Delta(1)))).length();
|
||||||
#ifdef MSDFGEN_USE_OPENMP
|
#ifdef MSDFGEN_USE_OPENMP
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
ShapeDistanceChecker<ContourCombiner, N> shapeDistanceChecker(sdf, shape, projection, invRange, minImproveRatio);
|
ShapeDistanceChecker<ContourCombiner, N> shapeDistanceChecker(sdf, shape, transformation, transformation.distanceMapping, minImproveRatio);
|
||||||
bool rightToLeft = false;
|
bool rightToLeft = false;
|
||||||
// Inspect all texels.
|
// Inspect all texels.
|
||||||
#ifdef MSDFGEN_USE_OPENMP
|
#ifdef MSDFGEN_USE_OPENMP
|
||||||
@ -439,7 +438,7 @@ void MSDFErrorCorrection::findErrors(const BitmapConstRef<float, N> &sdf, const
|
|||||||
if ((*stencil(x, row)&ERROR))
|
if ((*stencil(x, row)&ERROR))
|
||||||
continue;
|
continue;
|
||||||
const float *c = sdf(x, row);
|
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.sdfCoord = Point2(x+.5, row+.5);
|
||||||
shapeDistanceChecker.msd = c;
|
shapeDistanceChecker.msd = c;
|
||||||
shapeDistanceChecker.protectedFlag = (*stencil(x, row)&PROTECTED) != 0;
|
shapeDistanceChecker.protectedFlag = (*stencil(x, row)&PROTECTED) != 0;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Projection.h"
|
#include "SDFTransformation.h"
|
||||||
#include "Shape.h"
|
#include "Shape.h"
|
||||||
#include "BitmapRef.hpp"
|
#include "BitmapRef.hpp"
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
MSDFErrorCorrection();
|
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.
|
/// Sets the minimum ratio between the actual and maximum expected distance delta to be considered an error.
|
||||||
void setMinDeviationRatio(double minDeviationRatio);
|
void setMinDeviationRatio(double minDeviationRatio);
|
||||||
/// Sets the minimum ratio between the pre-correction distance error and the post-correction distance error.
|
/// Sets the minimum ratio between the pre-correction distance error and the post-correction distance error.
|
||||||
@ -46,8 +46,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
BitmapRef<byte, 1> stencil;
|
BitmapRef<byte, 1> stencil;
|
||||||
Projection projection;
|
SDFTransformation transformation;
|
||||||
double invRange;
|
|
||||||
double minDeviationRatio;
|
double minDeviationRatio;
|
||||||
double minImproveRatio;
|
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 <cstdlib>
|
||||||
#include "arithmetics.hpp"
|
#include "arithmetics.hpp"
|
||||||
|
|
||||||
|
#define DECONVERGE_OVERSHOOT 1.11111111111111111 // moves control points slightly more than necessary to account for floating-point errors
|
||||||
|
|
||||||
namespace msdfgen {
|
namespace msdfgen {
|
||||||
|
|
||||||
Shape::Shape() : inverseYAxis(false) { }
|
Shape::Shape() : inverseYAxis(false) { }
|
||||||
@ -39,13 +41,23 @@ bool Shape::validate() const {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void deconvergeEdge(EdgeHolder &edgeHolder, int param) {
|
static void deconvergeEdge(EdgeHolder &edgeHolder, int param, Vector2 vector) {
|
||||||
switch (edgeHolder->type()) {
|
switch (edgeHolder->type()) {
|
||||||
case (int) QuadraticSegment::EDGE_TYPE:
|
case (int) QuadraticSegment::EDGE_TYPE:
|
||||||
edgeHolder = static_cast<const QuadraticSegment *>(&*edgeHolder)->convertToCubic();
|
edgeHolder = static_cast<const QuadraticSegment *>(&*edgeHolder)->convertToCubic();
|
||||||
// fallthrough
|
// fallthrough
|
||||||
case (int) CubicSegment::EDGE_TYPE:
|
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[1]));
|
||||||
contour->edges.push_back(EdgeHolder(parts[2]));
|
contour->edges.push_back(EdgeHolder(parts[2]));
|
||||||
} else {
|
} else {
|
||||||
|
// Push apart convergent edge segments
|
||||||
EdgeHolder *prevEdge = &contour->edges.back();
|
EdgeHolder *prevEdge = &contour->edges.back();
|
||||||
for (std::vector<EdgeHolder>::iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
|
for (std::vector<EdgeHolder>::iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
|
||||||
Vector2 prevDir = (*prevEdge)->direction(1).normalize();
|
Vector2 prevDir = (*prevEdge)->direction(1).normalize();
|
||||||
Vector2 curDir = (*edge)->direction(0).normalize();
|
Vector2 curDir = (*edge)->direction(0).normalize();
|
||||||
if (dotProduct(prevDir, curDir) < MSDFGEN_CORNER_DOT_EPSILON-1) {
|
if (dotProduct(prevDir, curDir) < MSDFGEN_CORNER_DOT_EPSILON-1) {
|
||||||
deconvergeEdge(*prevEdge, 1);
|
double factor = DECONVERGE_OVERSHOOT*sqrt(1-(MSDFGEN_CORNER_DOT_EPSILON-1)*(MSDFGEN_CORNER_DOT_EPSILON-1))/(MSDFGEN_CORNER_DOT_EPSILON-1);
|
||||||
deconvergeEdge(*edge, 0);
|
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;
|
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.
|
// Threshold of the dot product of adjacent edge directions to be considered convergent.
|
||||||
#define MSDFGEN_CORNER_DOT_EPSILON .000001
|
#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.
|
/// Vector shape representation.
|
||||||
class Shape {
|
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.
|
/// Sets individual elements of the vector.
|
||||||
inline void set(double x, double y) {
|
inline void set(double newX, double newY) {
|
||||||
this->x = x, this->y = y;
|
x = newX, y = newY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the vector's squared length.
|
/// 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;
|
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) {
|
static double resolveDistance(double distance) {
|
||||||
return distance;
|
return distance;
|
||||||
}
|
}
|
||||||
@ -43,7 +50,7 @@ typename SimpleContourCombiner<EdgeSelector>::DistanceType SimpleContourCombiner
|
|||||||
}
|
}
|
||||||
|
|
||||||
template class SimpleContourCombiner<TrueDistanceSelector>;
|
template class SimpleContourCombiner<TrueDistanceSelector>;
|
||||||
template class SimpleContourCombiner<PseudoDistanceSelector>;
|
template class SimpleContourCombiner<PerpendicularDistanceSelector>;
|
||||||
template class SimpleContourCombiner<MultiDistanceSelector>;
|
template class SimpleContourCombiner<MultiDistanceSelector>;
|
||||||
template class SimpleContourCombiner<MultiAndTrueDistanceSelector>;
|
template class SimpleContourCombiner<MultiAndTrueDistanceSelector>;
|
||||||
|
|
||||||
@ -127,7 +134,7 @@ typename OverlappingContourCombiner<EdgeSelector>::DistanceType OverlappingConto
|
|||||||
}
|
}
|
||||||
|
|
||||||
template class OverlappingContourCombiner<TrueDistanceSelector>;
|
template class OverlappingContourCombiner<TrueDistanceSelector>;
|
||||||
template class OverlappingContourCombiner<PseudoDistanceSelector>;
|
template class OverlappingContourCombiner<PerpendicularDistanceSelector>;
|
||||||
template class OverlappingContourCombiner<MultiDistanceSelector>;
|
template class OverlappingContourCombiner<MultiDistanceSelector>;
|
||||||
template class OverlappingContourCombiner<MultiAndTrueDistanceSelector>;
|
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 {
|
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) {
|
static bool isCorner(const Vector2 &aDir, const Vector2 &bDir, double crossThreshold) {
|
||||||
return dotProduct(aDir, bDir) <= 0 || fabs(crossProduct(aDir, bDir)) > crossThreshold;
|
return dotProduct(aDir, bDir) <= 0 || fabs(crossProduct(aDir, bDir)) > crossThreshold;
|
||||||
}
|
}
|
||||||
@ -26,30 +35,45 @@ static double estimateEdgeLength(const EdgeSegment *edge) {
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void switchColor(EdgeColor &color, unsigned long long &seed, EdgeColor banned = BLACK) {
|
static int seedExtract2(unsigned long long &seed) {
|
||||||
EdgeColor combined = EdgeColor(color&banned);
|
int v = int(seed)&1;
|
||||||
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);
|
|
||||||
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) {
|
void edgeColoringSimple(Shape &shape, double angleThreshold, unsigned long long seed) {
|
||||||
double crossThreshold = sin(angleThreshold);
|
double crossThreshold = sin(angleThreshold);
|
||||||
|
EdgeColor color = initColor(seed);
|
||||||
std::vector<int> corners;
|
std::vector<int> corners;
|
||||||
for (std::vector<Contour>::iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
|
for (std::vector<Contour>::iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
|
||||||
// Identify corners
|
if (contour->edges.empty())
|
||||||
corners.clear();
|
continue;
|
||||||
if (!contour->edges.empty()) {
|
{ // Identify corners
|
||||||
|
corners.clear();
|
||||||
Vector2 prevDirection = contour->edges.back()->direction(1);
|
Vector2 prevDirection = contour->edges.back()->direction(1);
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge, ++index) {
|
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
|
// 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)
|
for (std::vector<EdgeHolder>::iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge)
|
||||||
(*edge)->color = WHITE;
|
(*edge)->color = color;
|
||||||
|
}
|
||||||
// "Teardrop" case
|
// "Teardrop" case
|
||||||
else if (corners.size() == 1) {
|
else if (corners.size() == 1) {
|
||||||
EdgeColor colors[3] = { WHITE, WHITE };
|
EdgeColor colors[3];
|
||||||
switchColor(colors[0], seed);
|
switchColor(color, seed);
|
||||||
switchColor(colors[2] = colors[0], seed);
|
colors[0] = color;
|
||||||
|
colors[1] = WHITE;
|
||||||
|
switchColor(color, seed);
|
||||||
|
colors[2] = color;
|
||||||
int corner = corners[0];
|
int corner = corners[0];
|
||||||
if (contour->edges.size() >= 3) {
|
if (contour->edges.size() >= 3) {
|
||||||
int m = (int) contour->edges.size();
|
int m = (int) contour->edges.size();
|
||||||
for (int i = 0; i < m; ++i)
|
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) {
|
} else if (contour->edges.size() >= 1) {
|
||||||
// Less than three edge segments for three colors => edges must be split
|
// Less than three edge segments for three colors => edges must be split
|
||||||
EdgeSegment *parts[7] = { };
|
EdgeSegment *parts[7] = { };
|
||||||
@ -98,7 +127,6 @@ void edgeColoringSimple(Shape &shape, double angleThreshold, unsigned long long
|
|||||||
int spline = 0;
|
int spline = 0;
|
||||||
int start = corners[0];
|
int start = corners[0];
|
||||||
int m = (int) contour->edges.size();
|
int m = (int) contour->edges.size();
|
||||||
EdgeColor color = WHITE;
|
|
||||||
switchColor(color, seed);
|
switchColor(color, seed);
|
||||||
EdgeColor initialColor = color;
|
EdgeColor initialColor = color;
|
||||||
for (int i = 0; i < m; ++i) {
|
for (int i = 0; i < m; ++i) {
|
||||||
@ -123,12 +151,14 @@ struct EdgeColoringInkTrapCorner {
|
|||||||
void edgeColoringInkTrap(Shape &shape, double angleThreshold, unsigned long long seed) {
|
void edgeColoringInkTrap(Shape &shape, double angleThreshold, unsigned long long seed) {
|
||||||
typedef EdgeColoringInkTrapCorner Corner;
|
typedef EdgeColoringInkTrapCorner Corner;
|
||||||
double crossThreshold = sin(angleThreshold);
|
double crossThreshold = sin(angleThreshold);
|
||||||
|
EdgeColor color = initColor(seed);
|
||||||
std::vector<Corner> corners;
|
std::vector<Corner> corners;
|
||||||
for (std::vector<Contour>::iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
|
for (std::vector<Contour>::iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
|
||||||
// Identify corners
|
if (contour->edges.empty())
|
||||||
|
continue;
|
||||||
double splineLength = 0;
|
double splineLength = 0;
|
||||||
corners.clear();
|
{ // Identify corners
|
||||||
if (!contour->edges.empty()) {
|
corners.clear();
|
||||||
Vector2 prevDirection = contour->edges.back()->direction(1);
|
Vector2 prevDirection = contour->edges.back()->direction(1);
|
||||||
int index = 0;
|
int index = 0;
|
||||||
for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge, ++index) {
|
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
|
// 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)
|
for (std::vector<EdgeHolder>::iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge)
|
||||||
(*edge)->color = WHITE;
|
(*edge)->color = color;
|
||||||
|
}
|
||||||
// "Teardrop" case
|
// "Teardrop" case
|
||||||
else if (corners.size() == 1) {
|
else if (corners.size() == 1) {
|
||||||
EdgeColor colors[3] = { WHITE, WHITE };
|
EdgeColor colors[3];
|
||||||
switchColor(colors[0], seed);
|
switchColor(color, seed);
|
||||||
switchColor(colors[2] = colors[0], seed);
|
colors[0] = color;
|
||||||
|
colors[1] = WHITE;
|
||||||
|
switchColor(color, seed);
|
||||||
|
colors[2] = color;
|
||||||
int corner = corners[0].index;
|
int corner = corners[0].index;
|
||||||
if (contour->edges.size() >= 3) {
|
if (contour->edges.size() >= 3) {
|
||||||
int m = (int) contour->edges.size();
|
int m = (int) contour->edges.size();
|
||||||
for (int i = 0; i < m; ++i)
|
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) {
|
} else if (contour->edges.size() >= 1) {
|
||||||
// Less than three edge segments for three colors => edges must be split
|
// Less than three edge segments for three colors => edges must be split
|
||||||
EdgeSegment *parts[7] = { };
|
EdgeSegment *parts[7] = { };
|
||||||
@ -191,7 +226,6 @@ void edgeColoringInkTrap(Shape &shape, double angleThreshold, unsigned long long
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EdgeColor color = WHITE;
|
|
||||||
EdgeColor initialColor = BLACK;
|
EdgeColor initialColor = BLACK;
|
||||||
for (int i = 0; i < cornerCount; ++i) {
|
for (int i = 0; i < cornerCount; ++i) {
|
||||||
if (!corners[i].minor) {
|
if (!corners[i].minor) {
|
||||||
@ -271,23 +305,19 @@ static void colorSecondDegreeGraph(int *coloring, const int *const *edgeMatrix,
|
|||||||
color = 1;
|
color = 1;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
color = (int) seed&1;
|
color = seedExtract2(seed); // 0 or 1
|
||||||
seed >>= 1;
|
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
color = 2;
|
color = 2;
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
color = ((int) seed+1&1)<<1;
|
color = (int) !seedExtract2(seed)<<1; // 2 or 0
|
||||||
seed >>= 1;
|
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
color = ((int) seed&1)+1;
|
color = seedExtract2(seed)+1; // 1 or 2
|
||||||
seed >>= 1;
|
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
color = int((seed+i)%3);
|
color = (seedExtract3(seed)+i)%3; // 0 or 1 or 2
|
||||||
seed /= 3;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
coloring[i] = color;
|
coloring[i] = color;
|
||||||
@ -394,7 +424,7 @@ void edgeColoringByDistance(Shape &shape, double angleThreshold, unsigned long l
|
|||||||
for (int i = 0; i < m; ++i) {
|
for (int i = 0; i < m; ++i) {
|
||||||
if (i == m/2)
|
if (i == m/2)
|
||||||
splineStarts.push_back((int) edgeSegments.size());
|
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]);
|
edgeSegments.push_back(&*contour->edges[(corner+i)%m]);
|
||||||
else
|
else
|
||||||
contour->edges[(corner+i)%m]->color = WHITE;
|
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 {
|
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) {
|
if (param < 0) {
|
||||||
Vector2 dir = direction(0).normalize();
|
Vector2 dir = direction(0).normalize();
|
||||||
Vector2 aq = origin-point(0);
|
Vector2 aq = origin-point(0);
|
||||||
double ts = dotProduct(aq, dir);
|
double ts = dotProduct(aq, dir);
|
||||||
if (ts < 0) {
|
if (ts < 0) {
|
||||||
double pseudoDistance = crossProduct(aq, dir);
|
double perpendicularDistance = crossProduct(aq, dir);
|
||||||
if (fabs(pseudoDistance) <= fabs(distance.distance)) {
|
if (fabs(perpendicularDistance) <= fabs(distance.distance)) {
|
||||||
distance.distance = pseudoDistance;
|
distance.distance = perpendicularDistance;
|
||||||
distance.dot = 0;
|
distance.dot = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -23,9 +42,9 @@ void EdgeSegment::distanceToPseudoDistance(SignedDistance &distance, Point2 orig
|
|||||||
Vector2 bq = origin-point(1);
|
Vector2 bq = origin-point(1);
|
||||||
double ts = dotProduct(bq, dir);
|
double ts = dotProduct(bq, dir);
|
||||||
if (ts > 0) {
|
if (ts > 0) {
|
||||||
double pseudoDistance = crossProduct(bq, dir);
|
double perpendicularDistance = crossProduct(bq, dir);
|
||||||
if (fabs(pseudoDistance) <= fabs(distance.distance)) {
|
if (fabs(perpendicularDistance) <= fabs(distance.distance)) {
|
||||||
distance.distance = pseudoDistance;
|
distance.distance = perpendicularDistance;
|
||||||
distance.dot = 0;
|
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) {
|
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[0] = p0;
|
||||||
p[1] = p1;
|
p[1] = p1;
|
||||||
p[2] = p2;
|
p[2] = p2;
|
||||||
}
|
}
|
||||||
|
|
||||||
CubicSegment::CubicSegment(Point2 p0, Point2 p1, Point2 p2, Point2 p3, EdgeColor edgeColor) : EdgeSegment(edgeColor) {
|
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[0] = p0;
|
||||||
p[1] = p1;
|
p[1] = p1;
|
||||||
p[2] = p2;
|
p[2] = p2;
|
||||||
@ -486,43 +499,29 @@ void CubicSegment::moveEndPoint(Point2 to) {
|
|||||||
p[3] = to;
|
p[3] = to;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinearSegment::splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const {
|
void LinearSegment::splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const {
|
||||||
part1 = new LinearSegment(p[0], point(1/3.), color);
|
part0 = new LinearSegment(p[0], point(1/3.), color);
|
||||||
part2 = new LinearSegment(point(1/3.), point(2/3.), color);
|
part1 = new LinearSegment(point(1/3.), point(2/3.), color);
|
||||||
part3 = new LinearSegment(point(2/3.), p[1], color);
|
part2 = new LinearSegment(point(2/3.), p[1], color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuadraticSegment::splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const {
|
void QuadraticSegment::splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const {
|
||||||
part1 = new QuadraticSegment(p[0], mix(p[0], p[1], 1/3.), point(1/3.), color);
|
part0 = 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);
|
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);
|
||||||
part3 = new QuadraticSegment(point(2/3.), mix(p[1], p[2], 2/3.), p[2], 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 {
|
void CubicSegment::splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) 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);
|
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);
|
||||||
part2 = new CubicSegment(point(1/3.),
|
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], 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.),
|
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);
|
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 {
|
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);
|
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:
|
public:
|
||||||
EdgeColor color;
|
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) { }
|
EdgeSegment(EdgeColor edgeColor = WHITE) : color(edgeColor) { }
|
||||||
virtual ~EdgeSegment() { }
|
virtual ~EdgeSegment() { }
|
||||||
/// Creates a copy of the edge segment.
|
/// Creates a copy of the edge segment.
|
||||||
@ -33,8 +37,8 @@ public:
|
|||||||
virtual Vector2 directionChange(double param) const = 0;
|
virtual Vector2 directionChange(double param) const = 0;
|
||||||
/// Returns the minimum signed distance between origin and the edge.
|
/// Returns the minimum signed distance between origin and the edge.
|
||||||
virtual SignedDistance signedDistance(Point2 origin, double ¶m) const = 0;
|
virtual SignedDistance signedDistance(Point2 origin, double ¶m) const = 0;
|
||||||
/// Converts a previously retrieved signed distance from origin to pseudo-distance.
|
/// Converts a previously retrieved signed distance from origin to perpendicular distance.
|
||||||
virtual void distanceToPseudoDistance(SignedDistance &distance, Point2 origin, double param) const;
|
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.
|
/// 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;
|
virtual int scanlineIntersections(double x[3], int dy[3], double y) const = 0;
|
||||||
/// Adjusts the bounding box to fit the edge segment.
|
/// Adjusts the bounding box to fit the edge segment.
|
||||||
@ -47,7 +51,7 @@ public:
|
|||||||
/// Moves the end point of the edge segment.
|
/// Moves the end point of the edge segment.
|
||||||
virtual void moveEndPoint(Point2 to) = 0;
|
virtual void moveEndPoint(Point2 to) = 0;
|
||||||
/// Splits the edge segments into thirds which together represent the original edge.
|
/// 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 reverse();
|
||||||
void moveStartPoint(Point2 to);
|
void moveStartPoint(Point2 to);
|
||||||
void moveEndPoint(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 reverse();
|
||||||
void moveStartPoint(Point2 to);
|
void moveStartPoint(Point2 to);
|
||||||
void moveEndPoint(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;
|
EdgeSegment *convertToCubic() const;
|
||||||
|
|
||||||
@ -135,9 +139,7 @@ public:
|
|||||||
void reverse();
|
void reverse();
|
||||||
void moveStartPoint(Point2 to);
|
void moveStartPoint(Point2 to);
|
||||||
void moveEndPoint(Point2 to);
|
void moveEndPoint(Point2 to);
|
||||||
void splitInThirds(EdgeSegment *&part1, EdgeSegment *&part2, EdgeSegment *&part3) const;
|
void splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const;
|
||||||
|
|
||||||
void deconverge(int param, double amount);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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;
|
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);
|
double ts = dotProduct(ep, edgeDir);
|
||||||
if (ts > 0) {
|
if (ts > 0) {
|
||||||
double pseudoDistance = crossProduct(ep, edgeDir);
|
double perpendicularDistance = crossProduct(ep, edgeDir);
|
||||||
if (fabs(pseudoDistance) < fabs(distance)) {
|
if (fabs(perpendicularDistance) < fabs(distance)) {
|
||||||
distance = pseudoDistance;
|
distance = perpendicularDistance;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
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;
|
minTrueDistance.distance += nonZeroSign(minTrueDistance.distance)*delta;
|
||||||
minNegativePseudoDistance = -fabs(minTrueDistance.distance);
|
minNegativePerpendicularDistance = -fabs(minTrueDistance.distance);
|
||||||
minPositivePseudoDistance = fabs(minTrueDistance.distance);
|
minPositivePerpendicularDistance = fabs(minTrueDistance.distance);
|
||||||
nearEdge = NULL;
|
nearEdge = NULL;
|
||||||
nearEdgeParam = 0;
|
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();
|
double delta = DISTANCE_DELTA_FACTOR*(p-cache.point).length();
|
||||||
return (
|
return (
|
||||||
cache.absDistance-delta <= fabs(minTrueDistance.distance) ||
|
cache.absDistance-delta <= fabs(minTrueDistance.distance) ||
|
||||||
fabs(cache.aDomainDistance) < delta ||
|
fabs(cache.aDomainDistance) < delta ||
|
||||||
fabs(cache.bDomainDistance) < delta ||
|
fabs(cache.bDomainDistance) < delta ||
|
||||||
(cache.aDomainDistance > 0 && (cache.aPseudoDistance < 0 ?
|
(cache.aDomainDistance > 0 && (cache.aPerpendicularDistance < 0 ?
|
||||||
cache.aPseudoDistance+delta >= minNegativePseudoDistance :
|
cache.aPerpendicularDistance+delta >= minNegativePerpendicularDistance :
|
||||||
cache.aPseudoDistance-delta <= minPositivePseudoDistance
|
cache.aPerpendicularDistance-delta <= minPositivePerpendicularDistance
|
||||||
)) ||
|
)) ||
|
||||||
(cache.bDomainDistance > 0 && (cache.bPseudoDistance < 0 ?
|
(cache.bDomainDistance > 0 && (cache.bPerpendicularDistance < 0 ?
|
||||||
cache.bPseudoDistance+delta >= minNegativePseudoDistance :
|
cache.bPerpendicularDistance+delta >= minNegativePerpendicularDistance :
|
||||||
cache.bPseudoDistance-delta <= minPositivePseudoDistance
|
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) {
|
if (distance < minTrueDistance) {
|
||||||
minTrueDistance = distance;
|
minTrueDistance = distance;
|
||||||
nearEdge = edge;
|
nearEdge = edge;
|
||||||
@ -85,47 +85,47 @@ void PseudoDistanceSelectorBase::addEdgeTrueDistance(const EdgeSegment *edge, co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PseudoDistanceSelectorBase::addEdgePseudoDistance(double distance) {
|
void PerpendicularDistanceSelectorBase::addEdgePerpendicularDistance(double distance) {
|
||||||
if (distance <= 0 && distance > minNegativePseudoDistance)
|
if (distance <= 0 && distance > minNegativePerpendicularDistance)
|
||||||
minNegativePseudoDistance = distance;
|
minNegativePerpendicularDistance = distance;
|
||||||
if (distance >= 0 && distance < minPositivePseudoDistance)
|
if (distance >= 0 && distance < minPositivePerpendicularDistance)
|
||||||
minPositivePseudoDistance = distance;
|
minPositivePerpendicularDistance = distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PseudoDistanceSelectorBase::merge(const PseudoDistanceSelectorBase &other) {
|
void PerpendicularDistanceSelectorBase::merge(const PerpendicularDistanceSelectorBase &other) {
|
||||||
if (other.minTrueDistance < minTrueDistance) {
|
if (other.minTrueDistance < minTrueDistance) {
|
||||||
minTrueDistance = other.minTrueDistance;
|
minTrueDistance = other.minTrueDistance;
|
||||||
nearEdge = other.nearEdge;
|
nearEdge = other.nearEdge;
|
||||||
nearEdgeParam = other.nearEdgeParam;
|
nearEdgeParam = other.nearEdgeParam;
|
||||||
}
|
}
|
||||||
if (other.minNegativePseudoDistance > minNegativePseudoDistance)
|
if (other.minNegativePerpendicularDistance > minNegativePerpendicularDistance)
|
||||||
minNegativePseudoDistance = other.minNegativePseudoDistance;
|
minNegativePerpendicularDistance = other.minNegativePerpendicularDistance;
|
||||||
if (other.minPositivePseudoDistance < minPositivePseudoDistance)
|
if (other.minPositivePerpendicularDistance < minPositivePerpendicularDistance)
|
||||||
minPositivePseudoDistance = other.minPositivePseudoDistance;
|
minPositivePerpendicularDistance = other.minPositivePerpendicularDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
double PseudoDistanceSelectorBase::computeDistance(const Point2 &p) const {
|
double PerpendicularDistanceSelectorBase::computeDistance(const Point2 &p) const {
|
||||||
double minDistance = minTrueDistance.distance < 0 ? minNegativePseudoDistance : minPositivePseudoDistance;
|
double minDistance = minTrueDistance.distance < 0 ? minNegativePerpendicularDistance : minPositivePerpendicularDistance;
|
||||||
if (nearEdge) {
|
if (nearEdge) {
|
||||||
SignedDistance distance = minTrueDistance;
|
SignedDistance distance = minTrueDistance;
|
||||||
nearEdge->distanceToPseudoDistance(distance, p, nearEdgeParam);
|
nearEdge->distanceToPerpendicularDistance(distance, p, nearEdgeParam);
|
||||||
if (fabs(distance.distance) < fabs(minDistance))
|
if (fabs(distance.distance) < fabs(minDistance))
|
||||||
minDistance = distance.distance;
|
minDistance = distance.distance;
|
||||||
}
|
}
|
||||||
return minDistance;
|
return minDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
SignedDistance PseudoDistanceSelectorBase::trueDistance() const {
|
SignedDistance PerpendicularDistanceSelectorBase::trueDistance() const {
|
||||||
return minTrueDistance;
|
return minTrueDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PseudoDistanceSelector::reset(const Point2 &p) {
|
void PerpendicularDistanceSelector::reset(const Point2 &p) {
|
||||||
double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
|
double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
|
||||||
PseudoDistanceSelectorBase::reset(delta);
|
PerpendicularDistanceSelectorBase::reset(delta);
|
||||||
this->p = p;
|
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)) {
|
if (isEdgeRelevant(cache, edge, p)) {
|
||||||
double param;
|
double param;
|
||||||
SignedDistance distance = edge->signedDistance(p, 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));
|
double bdd = -dotProduct(bp, (bDir+nextDir).normalize(true));
|
||||||
if (add > 0) {
|
if (add > 0) {
|
||||||
double pd = distance.distance;
|
double pd = distance.distance;
|
||||||
if (getPseudoDistance(pd, ap, -aDir))
|
if (getPerpendicularDistance(pd, ap, -aDir))
|
||||||
addEdgePseudoDistance(pd = -pd);
|
addEdgePerpendicularDistance(pd = -pd);
|
||||||
cache.aPseudoDistance = pd;
|
cache.aPerpendicularDistance = pd;
|
||||||
}
|
}
|
||||||
if (bdd > 0) {
|
if (bdd > 0) {
|
||||||
double pd = distance.distance;
|
double pd = distance.distance;
|
||||||
if (getPseudoDistance(pd, bp, bDir))
|
if (getPerpendicularDistance(pd, bp, bDir))
|
||||||
addEdgePseudoDistance(pd);
|
addEdgePerpendicularDistance(pd);
|
||||||
cache.bPseudoDistance = pd;
|
cache.bPerpendicularDistance = pd;
|
||||||
}
|
}
|
||||||
cache.aDomainDistance = add;
|
cache.aDomainDistance = add;
|
||||||
cache.bDomainDistance = bdd;
|
cache.bDomainDistance = bdd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PseudoDistanceSelector::DistanceType PseudoDistanceSelector::distance() const {
|
PerpendicularDistanceSelector::DistanceType PerpendicularDistanceSelector::distance() const {
|
||||||
return computeDistance(p);
|
return computeDistance(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,28 +197,28 @@ void MultiDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdg
|
|||||||
double bdd = -dotProduct(bp, (bDir+nextDir).normalize(true));
|
double bdd = -dotProduct(bp, (bDir+nextDir).normalize(true));
|
||||||
if (add > 0) {
|
if (add > 0) {
|
||||||
double pd = distance.distance;
|
double pd = distance.distance;
|
||||||
if (PseudoDistanceSelectorBase::getPseudoDistance(pd, ap, -aDir)) {
|
if (PerpendicularDistanceSelectorBase::getPerpendicularDistance(pd, ap, -aDir)) {
|
||||||
pd = -pd;
|
pd = -pd;
|
||||||
if (edge->color&RED)
|
if (edge->color&RED)
|
||||||
r.addEdgePseudoDistance(pd);
|
r.addEdgePerpendicularDistance(pd);
|
||||||
if (edge->color&GREEN)
|
if (edge->color&GREEN)
|
||||||
g.addEdgePseudoDistance(pd);
|
g.addEdgePerpendicularDistance(pd);
|
||||||
if (edge->color&BLUE)
|
if (edge->color&BLUE)
|
||||||
b.addEdgePseudoDistance(pd);
|
b.addEdgePerpendicularDistance(pd);
|
||||||
}
|
}
|
||||||
cache.aPseudoDistance = pd;
|
cache.aPerpendicularDistance = pd;
|
||||||
}
|
}
|
||||||
if (bdd > 0) {
|
if (bdd > 0) {
|
||||||
double pd = distance.distance;
|
double pd = distance.distance;
|
||||||
if (PseudoDistanceSelectorBase::getPseudoDistance(pd, bp, bDir)) {
|
if (PerpendicularDistanceSelectorBase::getPerpendicularDistance(pd, bp, bDir)) {
|
||||||
if (edge->color&RED)
|
if (edge->color&RED)
|
||||||
r.addEdgePseudoDistance(pd);
|
r.addEdgePerpendicularDistance(pd);
|
||||||
if (edge->color&GREEN)
|
if (edge->color&GREEN)
|
||||||
g.addEdgePseudoDistance(pd);
|
g.addEdgePerpendicularDistance(pd);
|
||||||
if (edge->color&BLUE)
|
if (edge->color&BLUE)
|
||||||
b.addEdgePseudoDistance(pd);
|
b.addEdgePerpendicularDistance(pd);
|
||||||
}
|
}
|
||||||
cache.bPseudoDistance = pd;
|
cache.bPerpendicularDistance = pd;
|
||||||
}
|
}
|
||||||
cache.aDomainDistance = add;
|
cache.aDomainDistance = add;
|
||||||
cache.bDomainDistance = bdd;
|
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:
|
public:
|
||||||
struct EdgeCache {
|
struct EdgeCache {
|
||||||
Point2 point;
|
Point2 point;
|
||||||
double absDistance;
|
double absDistance;
|
||||||
double aDomainDistance, bDomainDistance;
|
double aDomainDistance, bDomainDistance;
|
||||||
double aPseudoDistance, bPseudoDistance;
|
double aPerpendicularDistance, bPerpendicularDistance;
|
||||||
|
|
||||||
EdgeCache();
|
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);
|
void reset(double delta);
|
||||||
bool isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *edge, const Point2 &p) const;
|
bool isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *edge, const Point2 &p) const;
|
||||||
void addEdgeTrueDistance(const EdgeSegment *edge, const SignedDistance &distance, double param);
|
void addEdgeTrueDistance(const EdgeSegment *edge, const SignedDistance &distance, double param);
|
||||||
void addEdgePseudoDistance(double distance);
|
void addEdgePerpendicularDistance(double distance);
|
||||||
void merge(const PseudoDistanceSelectorBase &other);
|
void merge(const PerpendicularDistanceSelectorBase &other);
|
||||||
double computeDistance(const Point2 &p) const;
|
double computeDistance(const Point2 &p) const;
|
||||||
SignedDistance trueDistance() const;
|
SignedDistance trueDistance() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SignedDistance minTrueDistance;
|
SignedDistance minTrueDistance;
|
||||||
double minNegativePseudoDistance;
|
double minNegativePerpendicularDistance;
|
||||||
double minPositivePseudoDistance;
|
double minPositivePerpendicularDistance;
|
||||||
const EdgeSegment *nearEdge;
|
const EdgeSegment *nearEdge;
|
||||||
double nearEdgeParam;
|
double nearEdgeParam;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Selects the nearest edge by its pseudo-distance.
|
/// Selects the nearest edge by its perpendicular distance.
|
||||||
class PseudoDistanceSelector : public PseudoDistanceSelectorBase {
|
class PerpendicularDistanceSelector : public PerpendicularDistanceSelectorBase {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef double DistanceType;
|
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 {
|
class MultiDistanceSelector {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef MultiDistance DistanceType;
|
typedef MultiDistance DistanceType;
|
||||||
typedef PseudoDistanceSelectorBase::EdgeCache EdgeCache;
|
typedef PerpendicularDistanceSelectorBase::EdgeCache EdgeCache;
|
||||||
|
|
||||||
void reset(const Point2 &p);
|
void reset(const Point2 &p);
|
||||||
void addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge);
|
void addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge);
|
||||||
@ -100,11 +100,11 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Point2 p;
|
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 {
|
class MultiAndTrueDistanceSelector : public MultiDistanceSelector {
|
||||||
|
|
||||||
public:
|
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 {
|
namespace msdfgen {
|
||||||
|
|
||||||
template <int N>
|
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)
|
if (config.errorCorrection.mode == ErrorCorrectionConfig::DISABLED)
|
||||||
return;
|
return;
|
||||||
Bitmap<byte, 1> stencilBuffer;
|
Bitmap<byte, 1> stencilBuffer;
|
||||||
@ -19,7 +19,7 @@ static void msdfErrorCorrectionInner(const BitmapRef<float, N> &sdf, const Shape
|
|||||||
BitmapRef<byte, 1> stencil;
|
BitmapRef<byte, 1> stencil;
|
||||||
stencil.pixels = config.errorCorrection.buffer ? config.errorCorrection.buffer : (byte *) stencilBuffer;
|
stencil.pixels = config.errorCorrection.buffer ? config.errorCorrection.buffer : (byte *) stencilBuffer;
|
||||||
stencil.width = sdf.width, stencil.height = sdf.height;
|
stencil.width = sdf.width, stencil.height = sdf.height;
|
||||||
MSDFErrorCorrection ec(stencil, projection, range);
|
MSDFErrorCorrection ec(stencil, transformation);
|
||||||
ec.setMinDeviationRatio(config.errorCorrection.minDeviationRatio);
|
ec.setMinDeviationRatio(config.errorCorrection.minDeviationRatio);
|
||||||
ec.setMinImproveRatio(config.errorCorrection.minImproveRatio);
|
ec.setMinImproveRatio(config.errorCorrection.minImproveRatio);
|
||||||
switch (config.errorCorrection.mode) {
|
switch (config.errorCorrection.mode) {
|
||||||
@ -49,9 +49,9 @@ static void msdfErrorCorrectionInner(const BitmapRef<float, N> &sdf, const Shape
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <int N>
|
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);
|
Bitmap<byte, 1> stencilBuffer(sdf.width, sdf.height);
|
||||||
MSDFErrorCorrection ec(stencilBuffer, projection, range);
|
MSDFErrorCorrection ec(stencilBuffer, transformation);
|
||||||
ec.setMinDeviationRatio(minDeviationRatio);
|
ec.setMinDeviationRatio(minDeviationRatio);
|
||||||
if (protectAll)
|
if (protectAll)
|
||||||
ec.protectAll();
|
ec.protectAll();
|
||||||
@ -59,25 +59,43 @@ static void msdfErrorCorrectionShapeless(const BitmapRef<float, N> &sdf, const P
|
|||||||
ec.apply(sdf);
|
ec.apply(sdf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void msdfErrorCorrection(const BitmapRef<float, 3> &sdf, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config) {
|
void msdfErrorCorrection(const BitmapRef<float, 3> &sdf, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config) {
|
||||||
msdfErrorCorrectionInner(sdf, shape, projection, range, config);
|
msdfErrorCorrectionInner(sdf, shape, transformation, config);
|
||||||
}
|
}
|
||||||
void msdfErrorCorrection(const BitmapRef<float, 4> &sdf, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config) {
|
void msdfErrorCorrection(const BitmapRef<float, 4> &sdf, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config) {
|
||||||
msdfErrorCorrectionInner(sdf, shape, projection, range, 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) {
|
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 3> &sdf, const SDFTransformation &transformation, double minDeviationRatio) {
|
||||||
msdfErrorCorrectionShapeless(sdf, projection, range, minDeviationRatio, false);
|
msdfErrorCorrectionShapeless(sdf, transformation, minDeviationRatio, false);
|
||||||
}
|
}
|
||||||
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 4> &sdf, const Projection &projection, double range, double minDeviationRatio) {
|
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 4> &sdf, const SDFTransformation &transformation, double minDeviationRatio) {
|
||||||
msdfErrorCorrectionShapeless(sdf, projection, range, minDeviationRatio, false);
|
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) {
|
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 3> &sdf, const SDFTransformation &transformation, double minDeviationRatio) {
|
||||||
msdfErrorCorrectionShapeless(sdf, projection, range, minDeviationRatio, true);
|
msdfErrorCorrectionShapeless(sdf, transformation, minDeviationRatio, true);
|
||||||
}
|
}
|
||||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 4> &sdf, const Projection &projection, double range, double minDeviationRatio) {
|
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 4> &sdf, const SDFTransformation &transformation, double minDeviationRatio) {
|
||||||
msdfErrorCorrectionShapeless(sdf, projection, range, minDeviationRatio, true);
|
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
|
#pragma once
|
||||||
|
|
||||||
#include "Vector2.hpp"
|
#include "Vector2.hpp"
|
||||||
|
#include "Range.hpp"
|
||||||
#include "Projection.h"
|
#include "Projection.h"
|
||||||
|
#include "SDFTransformation.h"
|
||||||
#include "Shape.h"
|
#include "Shape.h"
|
||||||
#include "BitmapRef.hpp"
|
#include "BitmapRef.hpp"
|
||||||
#include "generator-config.h"
|
#include "generator-config.h"
|
||||||
@ -10,16 +12,22 @@
|
|||||||
namespace msdfgen {
|
namespace msdfgen {
|
||||||
|
|
||||||
/// Predicts potential artifacts caused by the interpolation of the MSDF and corrects them by converting nearby texels to single-channel.
|
/// 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, 3> &sdf, const Shape &shape, const SDFTransformation &transformation, 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, 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.
|
/// 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, 3> &sdf, const SDFTransformation &transformation, 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, 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.
|
/// 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, 3> &sdf, const SDFTransformation &transformation, 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, 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.
|
/// The original version of the error correction algorithm.
|
||||||
void msdfErrorCorrection_legacy(const BitmapRef<float, 3> &output, const Vector2 &threshold);
|
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 <>
|
template <>
|
||||||
class DistancePixelConversion<double> {
|
class DistancePixelConversion<double> {
|
||||||
double invRange;
|
DistanceMapping mapping;
|
||||||
public:
|
public:
|
||||||
typedef BitmapRef<float, 1> BitmapRefType;
|
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 {
|
inline void operator()(float *pixels, double distance) const {
|
||||||
*pixels = float(invRange*distance+.5);
|
*pixels = float(mapping(distance));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
class DistancePixelConversion<MultiDistance> {
|
class DistancePixelConversion<MultiDistance> {
|
||||||
double invRange;
|
DistanceMapping mapping;
|
||||||
public:
|
public:
|
||||||
typedef BitmapRef<float, 3> BitmapRefType;
|
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 {
|
inline void operator()(float *pixels, const MultiDistance &distance) const {
|
||||||
pixels[0] = float(invRange*distance.r+.5);
|
pixels[0] = float(mapping(distance.r));
|
||||||
pixels[1] = float(invRange*distance.g+.5);
|
pixels[1] = float(mapping(distance.g));
|
||||||
pixels[2] = float(invRange*distance.b+.5);
|
pixels[2] = float(mapping(distance.b));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
class DistancePixelConversion<MultiAndTrueDistance> {
|
class DistancePixelConversion<MultiAndTrueDistance> {
|
||||||
double invRange;
|
DistanceMapping mapping;
|
||||||
public:
|
public:
|
||||||
typedef BitmapRef<float, 4> BitmapRefType;
|
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 {
|
inline void operator()(float *pixels, const MultiAndTrueDistance &distance) const {
|
||||||
pixels[0] = float(invRange*distance.r+.5);
|
pixels[0] = float(mapping(distance.r));
|
||||||
pixels[1] = float(invRange*distance.g+.5);
|
pixels[1] = float(mapping(distance.g));
|
||||||
pixels[2] = float(invRange*distance.b+.5);
|
pixels[2] = float(mapping(distance.b));
|
||||||
pixels[3] = float(invRange*distance.a+.5);
|
pixels[3] = float(mapping(distance.a));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class ContourCombiner>
|
template <class ContourCombiner>
|
||||||
void generateDistanceField(const typename DistancePixelConversion<typename ContourCombiner::DistanceType>::BitmapRefType &output, const Shape &shape, const Projection &projection, double range) {
|
void generateDistanceField(const typename DistancePixelConversion<typename ContourCombiner::DistanceType>::BitmapRefType &output, const Shape &shape, const SDFTransformation &transformation) {
|
||||||
DistancePixelConversion<typename ContourCombiner::DistanceType> distancePixelConversion(range);
|
DistancePixelConversion<typename ContourCombiner::DistanceType> distancePixelConversion(transformation.distanceMapping);
|
||||||
#ifdef MSDFGEN_USE_OPENMP
|
#ifdef MSDFGEN_USE_OPENMP
|
||||||
#pragma omp parallel
|
#pragma omp parallel
|
||||||
#endif
|
#endif
|
||||||
@ -65,7 +65,7 @@ void generateDistanceField(const typename DistancePixelConversion<typename Conto
|
|||||||
int row = shape.inverseYAxis ? output.height-y-1 : y;
|
int row = shape.inverseYAxis ? output.height-y-1 : y;
|
||||||
for (int col = 0; col < output.width; ++col) {
|
for (int col = 0; col < output.width; ++col) {
|
||||||
int x = rightToLeft ? output.width-col-1 : 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);
|
typename ContourCombiner::DistanceType distance = distanceFinder.distance(p);
|
||||||
distancePixelConversion(output(x, row), distance);
|
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)
|
if (config.overlapSupport)
|
||||||
generateDistanceField<OverlappingContourCombiner<TrueDistanceSelector> >(output, shape, projection, range);
|
generateDistanceField<OverlappingContourCombiner<TrueDistanceSelector> >(output, shape, transformation);
|
||||||
else
|
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)
|
if (config.overlapSupport)
|
||||||
generateDistanceField<OverlappingContourCombiner<PseudoDistanceSelector> >(output, shape, projection, range);
|
generateDistanceField<OverlappingContourCombiner<PerpendicularDistanceSelector> >(output, shape, transformation);
|
||||||
else
|
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)
|
if (config.overlapSupport)
|
||||||
generateDistanceField<OverlappingContourCombiner<MultiDistanceSelector> >(output, shape, projection, range);
|
generateDistanceField<OverlappingContourCombiner<MultiDistanceSelector> >(output, shape, transformation);
|
||||||
else
|
else
|
||||||
generateDistanceField<SimpleContourCombiner<MultiDistanceSelector> >(output, shape, projection, range);
|
generateDistanceField<SimpleContourCombiner<MultiDistanceSelector> >(output, shape, transformation);
|
||||||
msdfErrorCorrection(output, shape, projection, range, config);
|
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)
|
if (config.overlapSupport)
|
||||||
generateDistanceField<OverlappingContourCombiner<MultiAndTrueDistanceSelector> >(output, shape, projection, range);
|
generateDistanceField<OverlappingContourCombiner<MultiAndTrueDistanceSelector> >(output, shape, transformation);
|
||||||
else
|
else
|
||||||
generateDistanceField<SimpleContourCombiner<MultiAndTrueDistanceSelector> >(output, shape, projection, range);
|
generateDistanceField<SimpleContourCombiner<MultiAndTrueDistanceSelector> >(output, shape, transformation);
|
||||||
msdfErrorCorrection(output, shape, projection, range, config);
|
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
|
// 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));
|
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) {
|
void generatePSDF(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
|
||||||
generatePseudoSDF(output, shape, Projection(scale, translate), range, GeneratorConfig(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));
|
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));
|
generateMTSDF(output, shape, Projection(scale, translate), range, MSDFGeneratorConfig(overlapSupport, errorCorrectionConfig));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Legacy version
|
// 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
|
#ifdef MSDFGEN_USE_OPENMP
|
||||||
#pragma omp parallel for
|
#pragma omp parallel for
|
||||||
#endif
|
#endif
|
||||||
@ -140,12 +179,13 @@ void generateSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, d
|
|||||||
if (distance < minDistance)
|
if (distance < minDistance)
|
||||||
minDistance = distance;
|
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
|
#ifdef MSDFGEN_USE_OPENMP
|
||||||
#pragma omp parallel for
|
#pragma omp parallel for
|
||||||
#endif
|
#endif
|
||||||
@ -167,13 +207,18 @@ void generatePseudoSDF_legacy(const BitmapRef<float, 1> &output, const Shape &sh
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nearEdge)
|
if (nearEdge)
|
||||||
(*nearEdge)->distanceToPseudoDistance(minDistance, p, nearParam);
|
(*nearEdge)->distanceToPerpendicularDistance(minDistance, p, nearParam);
|
||||||
*output(x, row) = float(minDistance.distance/range+.5);
|
*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
|
#ifdef MSDFGEN_USE_OPENMP
|
||||||
#pragma omp parallel for
|
#pragma omp parallel for
|
||||||
#endif
|
#endif
|
||||||
@ -212,14 +257,14 @@ void generateMSDF_legacy(const BitmapRef<float, 3> &output, const Shape &shape,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (r.nearEdge)
|
if (r.nearEdge)
|
||||||
(*r.nearEdge)->distanceToPseudoDistance(r.minDistance, p, r.nearParam);
|
(*r.nearEdge)->distanceToPerpendicularDistance(r.minDistance, p, r.nearParam);
|
||||||
if (g.nearEdge)
|
if (g.nearEdge)
|
||||||
(*g.nearEdge)->distanceToPseudoDistance(g.minDistance, p, g.nearParam);
|
(*g.nearEdge)->distanceToPerpendicularDistance(g.minDistance, p, g.nearParam);
|
||||||
if (b.nearEdge)
|
if (b.nearEdge)
|
||||||
(*b.nearEdge)->distanceToPseudoDistance(b.minDistance, p, b.nearParam);
|
(*b.nearEdge)->distanceToPerpendicularDistance(b.minDistance, p, b.nearParam);
|
||||||
output(x, row)[0] = float(r.minDistance.distance/range+.5);
|
output(x, row)[0] = float(distanceMapping(r.minDistance.distance));
|
||||||
output(x, row)[1] = float(g.minDistance.distance/range+.5);
|
output(x, row)[1] = float(distanceMapping(g.minDistance.distance));
|
||||||
output(x, row)[2] = float(b.minDistance.distance/range+.5);
|
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));
|
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
|
#ifdef MSDFGEN_USE_OPENMP
|
||||||
#pragma omp parallel for
|
#pragma omp parallel for
|
||||||
#endif
|
#endif
|
||||||
@ -269,15 +315,15 @@ void generateMTSDF_legacy(const BitmapRef<float, 4> &output, const Shape &shape,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (r.nearEdge)
|
if (r.nearEdge)
|
||||||
(*r.nearEdge)->distanceToPseudoDistance(r.minDistance, p, r.nearParam);
|
(*r.nearEdge)->distanceToPerpendicularDistance(r.minDistance, p, r.nearParam);
|
||||||
if (g.nearEdge)
|
if (g.nearEdge)
|
||||||
(*g.nearEdge)->distanceToPseudoDistance(g.minDistance, p, g.nearParam);
|
(*g.nearEdge)->distanceToPerpendicularDistance(g.minDistance, p, g.nearParam);
|
||||||
if (b.nearEdge)
|
if (b.nearEdge)
|
||||||
(*b.nearEdge)->distanceToPseudoDistance(b.minDistance, p, b.nearParam);
|
(*b.nearEdge)->distanceToPerpendicularDistance(b.minDistance, p, b.nearParam);
|
||||||
output(x, row)[0] = float(r.minDistance.distance/range+.5);
|
output(x, row)[0] = float(distanceMapping(r.minDistance.distance));
|
||||||
output(x, row)[1] = float(g.minDistance.distance/range+.5);
|
output(x, row)[1] = float(distanceMapping(g.minDistance.distance));
|
||||||
output(x, row)[2] = float(b.minDistance.distance/range+.5);
|
output(x, row)[2] = float(distanceMapping(b.minDistance.distance));
|
||||||
output(x, row)[3] = float(minDistance.distance/range+.5);
|
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 {
|
namespace msdfgen {
|
||||||
|
|
||||||
inline byte pixelFloatToByte(float x) {
|
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) {
|
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 "render-sdf.h"
|
||||||
|
|
||||||
#include "arithmetics.hpp"
|
#include "arithmetics.hpp"
|
||||||
|
#include "DistanceMapping.h"
|
||||||
#include "pixel-conversion.hpp"
|
#include "pixel-conversion.hpp"
|
||||||
#include "bitmap-interpolation.hpp"
|
#include "bitmap-interpolation.hpp"
|
||||||
|
|
||||||
namespace msdfgen {
|
namespace msdfgen {
|
||||||
|
|
||||||
static float distVal(float dist, double pxRange, float midValue) {
|
static float distVal(float dist, DistanceMapping mapping) {
|
||||||
if (!pxRange)
|
return (float) clamp(mapping(dist)+.5);
|
||||||
return (float) (dist > midValue);
|
|
||||||
return (float) clamp((dist-midValue)*pxRange+.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);
|
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||||
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
if (sdfPxRange.lower == sdfPxRange.upper) {
|
||||||
for (int y = 0; y < output.height; ++y)
|
for (int y = 0; y < output.height; ++y) {
|
||||||
for (int x = 0; x < output.width; ++x) {
|
for (int x = 0; x < output.width; ++x) {
|
||||||
float sd;
|
float sd;
|
||||||
interpolate(&sd, sdf, scale*Point2(x+.5, y+.5));
|
interpolate(&sd, sdf, scale*Point2(x+.5, y+.5));
|
||||||
*output(x, y) = distVal(sd, pxRange, midValue);
|
*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);
|
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||||
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
if (sdfPxRange.lower == sdfPxRange.upper) {
|
||||||
for (int y = 0; y < output.height; ++y)
|
for (int y = 0; y < output.height; ++y) {
|
||||||
for (int x = 0; x < output.width; ++x) {
|
for (int x = 0; x < output.width; ++x) {
|
||||||
float sd;
|
float sd;
|
||||||
interpolate(&sd, sdf, scale*Point2(x+.5, y+.5));
|
interpolate(&sd, sdf, scale*Point2(x+.5, y+.5));
|
||||||
float v = distVal(sd, pxRange, midValue);
|
float v = float(sd >= sdThreshold);
|
||||||
output(x, y)[0] = v;
|
output(x, y)[0] = v;
|
||||||
output(x, y)[1] = v;
|
output(x, y)[1] = v;
|
||||||
output(x, y)[2] = 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);
|
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||||
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
if (sdfPxRange.lower == sdfPxRange.upper) {
|
||||||
for (int y = 0; y < output.height; ++y)
|
for (int y = 0; y < output.height; ++y) {
|
||||||
for (int x = 0; x < output.width; ++x) {
|
for (int x = 0; x < output.width; ++x) {
|
||||||
float sd[3];
|
float sd[3];
|
||||||
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
||||||
*output(x, y) = distVal(median(sd[0], sd[1], sd[2]), pxRange, midValue);
|
*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);
|
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||||
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
if (sdfPxRange.lower == sdfPxRange.upper) {
|
||||||
for (int y = 0; y < output.height; ++y)
|
for (int y = 0; y < output.height; ++y) {
|
||||||
for (int x = 0; x < output.width; ++x) {
|
for (int x = 0; x < output.width; ++x) {
|
||||||
float sd[3];
|
float sd[3];
|
||||||
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
||||||
output(x, y)[0] = distVal(sd[0], pxRange, midValue);
|
output(x, y)[0] = float(sd[0] >= sdThreshold);
|
||||||
output(x, y)[1] = distVal(sd[1], pxRange, midValue);
|
output(x, y)[1] = float(sd[1] >= sdThreshold);
|
||||||
output(x, y)[2] = distVal(sd[2], pxRange, midValue);
|
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);
|
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||||
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
if (sdfPxRange.lower == sdfPxRange.upper) {
|
||||||
for (int y = 0; y < output.height; ++y)
|
for (int y = 0; y < output.height; ++y) {
|
||||||
for (int x = 0; x < output.width; ++x) {
|
for (int x = 0; x < output.width; ++x) {
|
||||||
float sd[4];
|
float sd[4];
|
||||||
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
||||||
*output(x, y) = distVal(median(sd[0], sd[1], sd[2]), pxRange, midValue);
|
*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);
|
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||||
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
if (sdfPxRange.lower == sdfPxRange.upper) {
|
||||||
for (int y = 0; y < output.height; ++y)
|
for (int y = 0; y < output.height; ++y) {
|
||||||
for (int x = 0; x < output.width; ++x) {
|
for (int x = 0; x < output.width; ++x) {
|
||||||
float sd[4];
|
float sd[4];
|
||||||
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
||||||
output(x, y)[0] = distVal(sd[0], pxRange, midValue);
|
output(x, y)[0] = float(sd[0] >= sdThreshold);
|
||||||
output(x, y)[1] = distVal(sd[1], pxRange, midValue);
|
output(x, y)[1] = float(sd[1] >= sdThreshold);
|
||||||
output(x, y)[2] = distVal(sd[2], pxRange, midValue);
|
output(x, y)[2] = float(sd[2] >= sdThreshold);
|
||||||
output(x, y)[3] = distVal(sd[3], pxRange, midValue);
|
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) {
|
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
|
#pragma once
|
||||||
|
|
||||||
#include "Vector2.hpp"
|
#include "Vector2.hpp"
|
||||||
|
#include "Range.hpp"
|
||||||
#include "BitmapRef.hpp"
|
#include "BitmapRef.hpp"
|
||||||
|
|
||||||
namespace msdfgen {
|
namespace msdfgen {
|
||||||
|
|
||||||
/// Reconstructs the shape's appearance into output from the distance field sdf.
|
/// 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, 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, double pxRange = 0, float midValue = .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, double pxRange = 0, float midValue = .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, double pxRange = 0, float midValue = .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, double pxRange = 0, float midValue = .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, double pxRange = 0, float midValue = .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.
|
/// 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);
|
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
|
#ifdef MSDFGEN_USE_CPP11
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#else
|
#else
|
||||||
|
namespace msdfgen {
|
||||||
typedef int int32_t;
|
typedef int int32_t;
|
||||||
typedef unsigned uint32_t;
|
typedef unsigned uint32_t;
|
||||||
typedef unsigned short uint16_t;
|
typedef unsigned short uint16_t;
|
||||||
typedef unsigned char uint8_t;
|
typedef unsigned char uint8_t;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "pixel-conversion.hpp"
|
#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
|
#ifdef MSDFGEN_USE_CPP11
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#else
|
#else
|
||||||
|
namespace msdfgen {
|
||||||
typedef int int32_t;
|
typedef int int32_t;
|
||||||
typedef unsigned uint32_t;
|
typedef unsigned uint32_t;
|
||||||
typedef unsigned short uint16_t;
|
typedef unsigned short uint16_t;
|
||||||
typedef unsigned char uint8_t;
|
typedef unsigned char uint8_t;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace msdfgen {
|
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
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
#include "shape-description.h"
|
#include "shape-description.h"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
namespace msdfgen {
|
namespace msdfgen {
|
||||||
|
|
||||||
int readCharF(FILE *input) {
|
int readCharF(FILE *input) {
|
||||||
@ -25,14 +27,25 @@ int readCharS(const char **input) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int readCoordF(FILE *input, Point2 &coord) {
|
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 readCoordS(const char **input, Point2 &coord) {
|
||||||
int read = 0;
|
char *end = NULL;
|
||||||
int result = sscanf(*input, "%lf,%lf%n", &coord.x, &coord.y, &read);
|
coord.x = strtod(*input, &end);
|
||||||
*input += read;
|
if (end <= *input)
|
||||||
return result;
|
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) {
|
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
|
* 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
|
* 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,
|
* has been developed by Viktor Chlumsky in 2014 for his master's thesis,
|
||||||
@ -18,7 +18,10 @@
|
|||||||
#include "core/base.h"
|
#include "core/base.h"
|
||||||
#include "core/arithmetics.hpp"
|
#include "core/arithmetics.hpp"
|
||||||
#include "core/Vector2.hpp"
|
#include "core/Vector2.hpp"
|
||||||
|
#include "core/Range.hpp"
|
||||||
#include "core/Projection.h"
|
#include "core/Projection.h"
|
||||||
|
#include "core/DistanceMapping.h"
|
||||||
|
#include "core/SDFTransformation.h"
|
||||||
#include "core/Scanline.h"
|
#include "core/Scanline.h"
|
||||||
#include "core/Shape.h"
|
#include "core/Shape.h"
|
||||||
#include "core/BitmapRef.hpp"
|
#include "core/BitmapRef.hpp"
|
||||||
@ -33,32 +36,43 @@
|
|||||||
#include "core/sdf-error-estimation.h"
|
#include "core/sdf-error-estimation.h"
|
||||||
#include "core/save-bmp.h"
|
#include "core/save-bmp.h"
|
||||||
#include "core/save-tiff.h"
|
#include "core/save-tiff.h"
|
||||||
|
#include "core/save-rgba.h"
|
||||||
|
#include "core/save-fl32.h"
|
||||||
#include "core/shape-description.h"
|
#include "core/shape-description.h"
|
||||||
|
#include "core/export-svg.h"
|
||||||
|
|
||||||
namespace msdfgen {
|
namespace msdfgen {
|
||||||
|
|
||||||
/// Generates a conventional single-channel signed distance field.
|
/// 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.
|
/// Generates a single-channel signed perpendicular distance field.
|
||||||
void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, double range, const GeneratorConfig &config = GeneratorConfig());
|
void generatePSDF(const BitmapRef<float, 1> &output, const Shape &shape, const SDFTransformation &transformation, const GeneratorConfig &config = GeneratorConfig());
|
||||||
|
|
||||||
/// Generates a multi-channel signed distance field. Edge colors must be assigned first! (See edgeColoringSimple)
|
/// 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.
|
/// 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
|
// 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 generateSDF(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, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport = true);
|
void generatePSDF(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, double range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig = ErrorCorrectionConfig(), bool overlapSupport = true);
|
void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config = GeneratorConfig());
|
||||||
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 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.
|
// 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 generateSDF_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, 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);
|
||||||
void generateMSDF_legacy(const BitmapRef<float, 3> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig = ErrorCorrectionConfig());
|
void generatePseudoSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate);
|
||||||
void generateMTSDF_legacy(const BitmapRef<float, 4> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig = ErrorCorrectionConfig());
|
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