mirror of https://github.com/godotengine/godot
Merge pull request #113965 from akien-mga/msdfgen-1.13
msdfgen: Update to 1.13
This commit is contained in:
commit
4d0ddafa21
|
|
@ -23,6 +23,7 @@ if env["builtin_msdfgen"]:
|
|||
"core/Scanline.cpp",
|
||||
"core/Shape.cpp",
|
||||
"core/contour-combiners.cpp",
|
||||
"core/convergent-curve-ordering.cpp",
|
||||
"core/edge-coloring.cpp",
|
||||
"core/edge-segments.cpp",
|
||||
"core/edge-selectors.cpp",
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ if env["msdfgen_enabled"] and env["freetype_enabled"]:
|
|||
"core/Scanline.cpp",
|
||||
"core/Shape.cpp",
|
||||
"core/contour-combiners.cpp",
|
||||
"core/convergent-curve-ordering.cpp",
|
||||
"core/edge-coloring.cpp",
|
||||
"core/edge-segments.cpp",
|
||||
"core/edge-selectors.cpp",
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ if env["msdfgen_enabled"] and env["freetype_enabled"]:
|
|||
"core/Scanline.cpp",
|
||||
"core/Shape.cpp",
|
||||
"core/contour-combiners.cpp",
|
||||
"core/convergent-curve-ordering.cpp",
|
||||
"core/edge-coloring.cpp",
|
||||
"core/edge-segments.cpp",
|
||||
"core/edge-selectors.cpp",
|
||||
|
|
|
|||
|
|
@ -850,15 +850,19 @@ Collection of single-file libraries used in Godot components.
|
|||
## msdfgen
|
||||
|
||||
- Upstream: https://github.com/Chlumsky/msdfgen
|
||||
- Version: 1.12.1 (6574da1310df433c97ca0fddcab7e463c31e58f8, 2025)
|
||||
- Version: 1.13 (1874bcf7d9624ccc85b4bc9a85d78116f690f35b, 2025)
|
||||
- License: MIT
|
||||
|
||||
Files extracted from the upstream source:
|
||||
|
||||
- `msdfgen.h`
|
||||
- Files in `core/` folder
|
||||
- Files in `core/` folder, minus `export-svg.*` and `save-*.*` files
|
||||
- `LICENSE.txt`
|
||||
|
||||
Patches:
|
||||
|
||||
- `0001-remove-unused-save-features.patch` ([GH-113965](https://github.com/godotengine/godot/issues/113965))
|
||||
|
||||
|
||||
## openxr
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "YAxisOrientation.h"
|
||||
#include "BitmapRef.hpp"
|
||||
|
||||
namespace msdfgen {
|
||||
|
|
@ -11,14 +12,16 @@ class Bitmap {
|
|||
|
||||
public:
|
||||
Bitmap();
|
||||
Bitmap(int width, int height);
|
||||
Bitmap(const BitmapConstRef<T, N> &orig);
|
||||
Bitmap(int width, int height, YAxisOrientation yOrientation = MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION);
|
||||
explicit Bitmap(const BitmapConstRef<T, N> &orig);
|
||||
explicit Bitmap(const BitmapConstSection<T, N> &orig);
|
||||
Bitmap(const Bitmap<T, N> &orig);
|
||||
#ifdef MSDFGEN_USE_CPP11
|
||||
Bitmap(Bitmap<T, N> &&orig);
|
||||
#endif
|
||||
~Bitmap();
|
||||
Bitmap<T, N> &operator=(const BitmapConstRef<T, N> &orig);
|
||||
Bitmap<T, N> &operator=(const BitmapConstSection<T, N> &orig);
|
||||
Bitmap<T, N> &operator=(const Bitmap<T, N> &orig);
|
||||
#ifdef MSDFGEN_USE_CPP11
|
||||
Bitmap<T, N> &operator=(Bitmap<T, N> &&orig);
|
||||
|
|
@ -38,10 +41,17 @@ public:
|
|||
#endif
|
||||
operator BitmapRef<T, N>();
|
||||
operator BitmapConstRef<T, N>() const;
|
||||
operator BitmapSection<T, N>();
|
||||
operator BitmapConstSection<T, N>() const;
|
||||
/// Returns a reference to a rectangular section of the bitmap specified by bounds (excluding xMax, yMax).
|
||||
BitmapSection<T, N> getSection(int xMin, int yMin, int xMax, int yMax);
|
||||
/// Returns a constant reference to a rectangular section of the bitmap specified by bounds (excluding xMax, yMax).
|
||||
BitmapConstSection<T, N> getConstSection(int xMin, int yMin, int xMax, int yMax) const;
|
||||
|
||||
private:
|
||||
T *pixels;
|
||||
int w, h;
|
||||
YAxisOrientation yOrientation;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -7,28 +7,41 @@
|
|||
namespace msdfgen {
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::Bitmap() : pixels(NULL), w(0), h(0) { }
|
||||
Bitmap<T, N>::Bitmap() : pixels(NULL), w(0), h(0), yOrientation(MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION) { }
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::Bitmap(int width, int height) : w(width), h(height) {
|
||||
Bitmap<T, N>::Bitmap(int width, int height, YAxisOrientation yOrientation) : w(width), h(height), yOrientation(yOrientation) {
|
||||
pixels = new T[N*w*h];
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::Bitmap(const BitmapConstRef<T, N> &orig) : w(orig.width), h(orig.height) {
|
||||
Bitmap<T, N>::Bitmap(const BitmapConstRef<T, N> &orig) : w(orig.width), h(orig.height), yOrientation(orig.yOrientation) {
|
||||
pixels = new T[N*w*h];
|
||||
memcpy(pixels, orig.pixels, sizeof(T)*N*w*h);
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::Bitmap(const Bitmap<T, N> &orig) : w(orig.w), h(orig.h) {
|
||||
Bitmap<T, N>::Bitmap(const BitmapConstSection<T, N> &orig) : w(orig.width), h(orig.height), yOrientation(orig.yOrientation) {
|
||||
pixels = new T[N*w*h];
|
||||
T *dst = pixels;
|
||||
const T *src = orig.pixels;
|
||||
int rowLength = N*w;
|
||||
for (int y = 0; y < h; ++y) {
|
||||
memcpy(dst, src, sizeof(T)*rowLength);
|
||||
dst += rowLength;
|
||||
src += orig.rowStride;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::Bitmap(const Bitmap<T, N> &orig) : w(orig.w), h(orig.h), yOrientation(orig.yOrientation) {
|
||||
pixels = new T[N*w*h];
|
||||
memcpy(pixels, orig.pixels, sizeof(T)*N*w*h);
|
||||
}
|
||||
|
||||
#ifdef MSDFGEN_USE_CPP11
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::Bitmap(Bitmap<T, N> &&orig) : pixels(orig.pixels), w(orig.w), h(orig.h) {
|
||||
Bitmap<T, N>::Bitmap(Bitmap<T, N> &&orig) : pixels(orig.pixels), w(orig.w), h(orig.h), yOrientation(orig.yOrientation) {
|
||||
orig.pixels = NULL;
|
||||
orig.w = 0, orig.h = 0;
|
||||
}
|
||||
|
|
@ -36,25 +49,46 @@ Bitmap<T, N>::Bitmap(Bitmap<T, N> &&orig) : pixels(orig.pixels), w(orig.w), h(or
|
|||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::~Bitmap() {
|
||||
delete [] pixels;
|
||||
delete[] pixels;
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N> &Bitmap<T, N>::operator=(const BitmapConstRef<T, N> &orig) {
|
||||
if (pixels != orig.pixels) {
|
||||
delete [] pixels;
|
||||
delete[] pixels;
|
||||
w = orig.width, h = orig.height;
|
||||
yOrientation = orig.yOrientation;
|
||||
pixels = new T[N*w*h];
|
||||
memcpy(pixels, orig.pixels, sizeof(T)*N*w*h);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N> &Bitmap<T, N>::operator=(const BitmapConstSection<T, N> &orig) {
|
||||
if (orig.pixels && orig.pixels >= pixels && orig.pixels < pixels+N*w*h)
|
||||
return *this = Bitmap<T, N>(orig);
|
||||
delete[] pixels;
|
||||
w = orig.width, h = orig.height;
|
||||
yOrientation = orig.yOrientation;
|
||||
pixels = new T[N*w*h];
|
||||
T *dst = pixels;
|
||||
const T *src = orig.pixels;
|
||||
int rowLength = N*w;
|
||||
for (int y = 0; y < h; ++y) {
|
||||
memcpy(dst, src, sizeof(T)*rowLength);
|
||||
dst += rowLength;
|
||||
src += orig.rowStride;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N> &Bitmap<T, N>::operator=(const Bitmap<T, N> &orig) {
|
||||
if (this != &orig) {
|
||||
delete [] pixels;
|
||||
delete[] pixels;
|
||||
w = orig.w, h = orig.h;
|
||||
yOrientation = orig.yOrientation;
|
||||
pixels = new T[N*w*h];
|
||||
memcpy(pixels, orig.pixels, sizeof(T)*N*w*h);
|
||||
}
|
||||
|
|
@ -65,9 +99,10 @@ Bitmap<T, N> &Bitmap<T, N>::operator=(const Bitmap<T, N> &orig) {
|
|||
template <typename T, int N>
|
||||
Bitmap<T, N> &Bitmap<T, N>::operator=(Bitmap<T, N> &&orig) {
|
||||
if (this != &orig) {
|
||||
delete [] pixels;
|
||||
delete[] pixels;
|
||||
pixels = orig.pixels;
|
||||
w = orig.w, h = orig.h;
|
||||
yOrientation = orig.yOrientation;
|
||||
orig.pixels = NULL;
|
||||
}
|
||||
return *this;
|
||||
|
|
@ -106,12 +141,32 @@ Bitmap<T, N>::operator const T *() const {
|
|||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::operator BitmapRef<T, N>() {
|
||||
return BitmapRef<T, N>(pixels, w, h);
|
||||
return BitmapRef<T, N>(pixels, w, h, yOrientation);
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::operator BitmapConstRef<T, N>() const {
|
||||
return BitmapConstRef<T, N>(pixels, w, h);
|
||||
return BitmapConstRef<T, N>(pixels, w, h, yOrientation);
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::operator BitmapSection<T, N>() {
|
||||
return BitmapSection<T, N>(pixels, w, h, yOrientation);
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
Bitmap<T, N>::operator BitmapConstSection<T, N>() const {
|
||||
return BitmapConstSection<T, N>(pixels, w, h, yOrientation);
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
BitmapSection<T, N> Bitmap<T, N>::getSection(int xMin, int yMin, int xMax, int yMax) {
|
||||
return BitmapSection<T, N>(pixels+N*(w*yMin+xMin), xMax-xMin, yMax-yMin, N*w, yOrientation);
|
||||
}
|
||||
|
||||
template <typename T, int N>
|
||||
BitmapConstSection<T, N> Bitmap<T, N>::getConstSection(int xMin, int yMin, int xMax, int yMax) const {
|
||||
return BitmapConstSection<T, N>(pixels+N*(w*yMin+xMin), xMax-xMin, yMax-yMin, N*w, yOrientation);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,41 +1,154 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "base.h"
|
||||
#include "YAxisOrientation.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Reference to a 2D image bitmap or a buffer acting as one. Pixel storage not owned or managed by the object.
|
||||
template <typename T, int N = 1>
|
||||
struct BitmapRef;
|
||||
/// Constant reference to a 2D image bitmap or a buffer acting as one. Pixel storage not owned or managed by the object.
|
||||
template <typename T, int N = 1>
|
||||
struct BitmapConstRef;
|
||||
/// Reference to a 2D image bitmap with non-contiguous rows of pixels. Pixel storage not owned or managed by the object. Can represent e.g. a section of a larger bitmap, bitmap with padded rows, or vertically flipped bitmap (rowStride can be negative).
|
||||
template <typename T, int N = 1>
|
||||
struct BitmapSection;
|
||||
/// Constant reference to a 2D image bitmap with non-contiguous rows of pixels. Pixel storage not owned or managed by the object. Can represent e.g. a section of a larger bitmap, bitmap with padded rows, or vertically flipped bitmap (rowStride can be negative).
|
||||
template <typename T, int N = 1>
|
||||
struct BitmapConstSection;
|
||||
|
||||
template <typename T, int N>
|
||||
struct BitmapRef {
|
||||
|
||||
T *pixels;
|
||||
int width, height;
|
||||
YAxisOrientation yOrientation;
|
||||
|
||||
inline BitmapRef() : pixels(NULL), width(0), height(0) { }
|
||||
inline BitmapRef(T *pixels, int width, int height) : pixels(pixels), width(width), height(height) { }
|
||||
inline BitmapRef() : pixels(NULL), width(0), height(0), yOrientation(MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION) { }
|
||||
inline BitmapRef(T *pixels, int width, int height, YAxisOrientation yOrientation = MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION) : pixels(pixels), width(width), height(height), yOrientation(yOrientation) { }
|
||||
|
||||
inline T *operator()(int x, int y) const {
|
||||
return pixels+N*(width*y+x);
|
||||
}
|
||||
|
||||
/// Returns a reference to a rectangular section of the bitmap specified by bounds (excluding xMax, yMax).
|
||||
inline BitmapSection<T, N> getSection(int xMin, int yMin, int xMax, int yMax) const {
|
||||
return BitmapSection<T, N>(pixels+N*(width*yMin+xMin), xMax-xMin, yMax-yMin, N*width, yOrientation);
|
||||
}
|
||||
|
||||
/// Returns a constant reference to a rectangular section of the bitmap specified by bounds (excluding xMax, yMax).
|
||||
inline BitmapConstSection<T, N> getConstSection(int xMin, int yMin, int xMax, int yMax) const {
|
||||
return BitmapConstSection<T, N>(pixels+N*(width*yMin+xMin), xMax-xMin, yMax-yMin, N*width, yOrientation);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/// Constant reference to a 2D image bitmap or a buffer acting as one. Pixel storage not owned or managed by the object.
|
||||
template <typename T, int N = 1>
|
||||
template <typename T, int N>
|
||||
struct BitmapConstRef {
|
||||
|
||||
const T *pixels;
|
||||
int width, height;
|
||||
YAxisOrientation yOrientation;
|
||||
|
||||
inline BitmapConstRef() : pixels(NULL), width(0), height(0) { }
|
||||
inline BitmapConstRef(const T *pixels, int width, int height) : pixels(pixels), width(width), height(height) { }
|
||||
inline BitmapConstRef(const BitmapRef<T, N> &orig) : pixels(orig.pixels), width(orig.width), height(orig.height) { }
|
||||
inline BitmapConstRef() : pixels(NULL), width(0), height(0), yOrientation(MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION) { }
|
||||
inline BitmapConstRef(const T *pixels, int width, int height, YAxisOrientation yOrientation = MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION) : pixels(pixels), width(width), height(height), yOrientation(yOrientation) { }
|
||||
inline BitmapConstRef(const BitmapRef<T, N> &orig) : pixels(orig.pixels), width(orig.width), height(orig.height), yOrientation(orig.yOrientation) { }
|
||||
|
||||
inline const T *operator()(int x, int y) const {
|
||||
return pixels+N*(width*y+x);
|
||||
}
|
||||
|
||||
/// Returns a constant reference to a rectangular section of the bitmap specified by bounds (excluding xMax, yMax).
|
||||
inline BitmapConstSection<T, N> getSection(int xMin, int yMin, int xMax, int yMax) const {
|
||||
return BitmapConstSection<T, N>(pixels+N*(width*yMin+xMin), xMax-xMin, yMax-yMin, N*width, yOrientation);
|
||||
}
|
||||
|
||||
/// Returns a constant reference to a rectangular section of the bitmap specified by bounds (excluding xMax, yMax).
|
||||
inline BitmapConstSection<T, N> getConstSection(int xMin, int yMin, int xMax, int yMax) const {
|
||||
return getSection(xMin, yMin, xMax, yMax);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <typename T, int N>
|
||||
struct BitmapSection {
|
||||
|
||||
T *pixels;
|
||||
int width, height;
|
||||
/// Specifies the difference between the beginnings of adjacent pixel rows as the number of T elements, can be negative.
|
||||
int rowStride;
|
||||
YAxisOrientation yOrientation;
|
||||
|
||||
inline BitmapSection() : pixels(NULL), width(0), height(0), rowStride(0), yOrientation(MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION) { }
|
||||
inline BitmapSection(T *pixels, int width, int height, YAxisOrientation yOrientation = MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION) : pixels(pixels), width(width), height(height), rowStride(N*width), yOrientation(yOrientation) { }
|
||||
inline BitmapSection(T *pixels, int width, int height, int rowStride, YAxisOrientation yOrientation = MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION) : pixels(pixels), width(width), height(height), rowStride(rowStride), yOrientation(yOrientation) { }
|
||||
inline BitmapSection(const BitmapRef<T, N> &orig) : pixels(orig.pixels), width(orig.width), height(orig.height), rowStride(N*orig.width), yOrientation(orig.yOrientation) { }
|
||||
|
||||
inline T *operator()(int x, int y) const {
|
||||
return pixels+rowStride*y+N*x;
|
||||
}
|
||||
|
||||
/// Returns a reference to a rectangular subsection of the bitmap specified by bounds (excluding xMax, yMax).
|
||||
inline BitmapSection<T, N> getSection(int xMin, int yMin, int xMax, int yMax) const {
|
||||
return BitmapSection<T, N>(pixels+rowStride*yMin+N*xMin, xMax-xMin, yMax-yMin, rowStride, yOrientation);
|
||||
}
|
||||
|
||||
/// Returns a constant reference to a rectangular subsection of the bitmap specified by bounds (excluding xMax, yMax).
|
||||
inline BitmapConstSection<T, N> getConstSection(int xMin, int yMin, int xMax, int yMax) const {
|
||||
return BitmapConstSection<T, N>(pixels+rowStride*yMin+N*xMin, xMax-xMin, yMax-yMin, rowStride, yOrientation);
|
||||
}
|
||||
|
||||
/// Makes sure that the section's Y-axis orientation matches the argument by potentially reordering its rows.
|
||||
inline void reorient(YAxisOrientation newYAxisOrientation) {
|
||||
if (yOrientation != newYAxisOrientation) {
|
||||
pixels += rowStride*(height-1);
|
||||
rowStride = -rowStride;
|
||||
yOrientation = newYAxisOrientation;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <typename T, int N>
|
||||
struct BitmapConstSection {
|
||||
|
||||
const T *pixels;
|
||||
int width, height;
|
||||
/// Specifies the difference between the beginnings of adjacent pixel rows as the number of T elements, can be negative.
|
||||
int rowStride;
|
||||
YAxisOrientation yOrientation;
|
||||
|
||||
inline BitmapConstSection() : pixels(NULL), width(0), height(0), rowStride(0), yOrientation(MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION) { }
|
||||
inline BitmapConstSection(const T *pixels, int width, int height, YAxisOrientation yOrientation = MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION) : pixels(pixels), width(width), height(height), rowStride(N*width), yOrientation(yOrientation) { }
|
||||
inline BitmapConstSection(const T *pixels, int width, int height, int rowStride, YAxisOrientation yOrientation = MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION) : pixels(pixels), width(width), height(height), rowStride(rowStride), yOrientation(yOrientation) { }
|
||||
inline BitmapConstSection(const BitmapRef<T, N> &orig) : pixels(orig.pixels), width(orig.width), height(orig.height), rowStride(N*orig.width), yOrientation(orig.yOrientation) { }
|
||||
inline BitmapConstSection(const BitmapConstRef<T, N> &orig) : pixels(orig.pixels), width(orig.width), height(orig.height), rowStride(N*orig.width), yOrientation(orig.yOrientation) { }
|
||||
inline BitmapConstSection(const BitmapSection<T, N> &orig) : pixels(orig.pixels), width(orig.width), height(orig.height), rowStride(orig.rowStride), yOrientation(orig.yOrientation) { }
|
||||
|
||||
inline const T *operator()(int x, int y) const {
|
||||
return pixels+rowStride*y+N*x;
|
||||
}
|
||||
|
||||
/// Returns a constant reference to a rectangular subsection of the bitmap specified by bounds (excluding xMax, yMax).
|
||||
inline BitmapConstSection<T, N> getSection(int xMin, int yMin, int xMax, int yMax) const {
|
||||
return BitmapConstSection<T, N>(pixels+rowStride*yMin+N*xMin, xMax-xMin, yMax-yMin, rowStride, yOrientation);
|
||||
}
|
||||
|
||||
/// Returns a constant reference to a rectangular subsection of the bitmap specified by bounds (excluding xMax, yMax).
|
||||
inline BitmapConstSection<T, N> getConstSection(int xMin, int yMin, int xMax, int yMax) const {
|
||||
return getSection(xMin, yMin, xMax, yMax);
|
||||
}
|
||||
|
||||
/// Makes sure that the section's Y-axis orientation matches the argument by potentially reordering its rows.
|
||||
inline void reorient(YAxisOrientation newYAxisOrientation) {
|
||||
if (yOrientation != newYAxisOrientation) {
|
||||
pixels += rowStride*(height-1);
|
||||
rowStride = -rowStride;
|
||||
yOrientation = newYAxisOrientation;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,19 +24,19 @@ EdgeHolder &Contour::addEdge() {
|
|||
return edges.back();
|
||||
}
|
||||
|
||||
static void boundPoint(double &l, double &b, double &r, double &t, Point2 p) {
|
||||
if (p.x < l) l = p.x;
|
||||
if (p.y < b) b = p.y;
|
||||
if (p.x > r) r = p.x;
|
||||
if (p.y > t) t = p.y;
|
||||
static void boundPoint(double &xMin, double &yMin, double &xMax, double &yMax, Point2 p) {
|
||||
if (p.x < xMin) xMin = p.x;
|
||||
if (p.y < yMin) yMin = p.y;
|
||||
if (p.x > xMax) xMax = p.x;
|
||||
if (p.y > yMax) yMax = p.y;
|
||||
}
|
||||
|
||||
void Contour::bound(double &l, double &b, double &r, double &t) const {
|
||||
void Contour::bound(double &xMin, double &yMin, double &xMax, double &yMax) const {
|
||||
for (std::vector<EdgeHolder>::const_iterator edge = edges.begin(); edge != edges.end(); ++edge)
|
||||
(*edge)->bound(l, b, r, t);
|
||||
(*edge)->bound(xMin, yMin, xMax, yMax);
|
||||
}
|
||||
|
||||
void Contour::boundMiters(double &l, double &b, double &r, double &t, double border, double miterLimit, int polarity) const {
|
||||
void Contour::boundMiters(double &xMin, double &yMin, double &xMax, double &yMax, double border, double miterLimit, int polarity) const {
|
||||
if (edges.empty())
|
||||
return;
|
||||
Vector2 prevDir = edges.back()->direction(1).normalize(true);
|
||||
|
|
@ -48,7 +48,7 @@ void Contour::boundMiters(double &l, double &b, double &r, double &t, double bor
|
|||
if (q > 0)
|
||||
miterLength = min(1/sqrt(q), miterLimit);
|
||||
Point2 miter = (*edge)->point(0)+border*miterLength*(prevDir+dir).normalize(true);
|
||||
boundPoint(l, b, r, t, miter);
|
||||
boundPoint(xMin, yMin, xMax, yMax, miter);
|
||||
}
|
||||
prevDir = (*edge)->direction(1).normalize(true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,9 +21,9 @@ public:
|
|||
/// Creates a new edge in the contour and returns its reference.
|
||||
EdgeHolder &addEdge();
|
||||
/// Adjusts the bounding box to fit the contour.
|
||||
void bound(double &l, double &b, double &r, double &t) const;
|
||||
void bound(double &xMin, double &yMin, double &xMax, double &yMax) const;
|
||||
/// Adjusts the bounding box to fit the contour border's mitered corners.
|
||||
void boundMiters(double &l, double &b, double &r, double &t, double border, double miterLimit, int polarity) const;
|
||||
void boundMiters(double &xMin, double &yMin, double &xMax, double &yMax, double border, double miterLimit, int polarity) const;
|
||||
/// Computes the winding of the contour. Returns 1 if positive, -1 if negative.
|
||||
int winding() const;
|
||||
/// Reverses the sequence of edges on the contour.
|
||||
|
|
|
|||
|
|
@ -87,17 +87,15 @@ public:
|
|||
Point2 shapeCoord, sdfCoord;
|
||||
const float *msd;
|
||||
bool protectedFlag;
|
||||
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) {
|
||||
inline ShapeDistanceChecker(const BitmapConstSection<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));
|
||||
if (shape.inverseYAxis)
|
||||
texelSize.y = -texelSize.y;
|
||||
}
|
||||
inline ArtifactClassifier classifier(const Vector2 &direction, double span) {
|
||||
return ArtifactClassifier(this, direction, span);
|
||||
}
|
||||
private:
|
||||
ShapeDistanceFinder<ContourCombiner<PerpendicularDistanceSelector> > distanceFinder;
|
||||
BitmapConstRef<float, N> sdf;
|
||||
BitmapConstSection<float, N> sdf;
|
||||
DistanceMapping distanceMapping;
|
||||
Vector2 texelSize;
|
||||
double minImproveRatio;
|
||||
|
|
@ -105,10 +103,11 @@ private:
|
|||
|
||||
MSDFErrorCorrection::MSDFErrorCorrection() { }
|
||||
|
||||
MSDFErrorCorrection::MSDFErrorCorrection(const BitmapRef<byte, 1> &stencil, const SDFTransformation &transformation) : stencil(stencil), transformation(transformation) {
|
||||
MSDFErrorCorrection::MSDFErrorCorrection(const BitmapSection<byte, 1> &stencil, const SDFTransformation &transformation) : stencil(stencil), transformation(transformation) {
|
||||
minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio;
|
||||
minImproveRatio = ErrorCorrectionConfig::defaultMinImproveRatio;
|
||||
memset(stencil.pixels, 0, sizeof(byte)*stencil.width*stencil.height);
|
||||
for (int y = 0; y < stencil.height; ++y)
|
||||
memset(stencil(0, y), 0, sizeof(byte)*stencil.width);
|
||||
}
|
||||
|
||||
void MSDFErrorCorrection::setMinDeviationRatio(double minDeviationRatio) {
|
||||
|
|
@ -120,6 +119,7 @@ void MSDFErrorCorrection::setMinImproveRatio(double minImproveRatio) {
|
|||
}
|
||||
|
||||
void MSDFErrorCorrection::protectCorners(const Shape &shape) {
|
||||
stencil.reorient(shape.getYAxisOrientation());
|
||||
for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour)
|
||||
if (!contour->edges.empty()) {
|
||||
const EdgeSegment *prevEdge = contour->edges.back();
|
||||
|
|
@ -131,8 +131,6 @@ void MSDFErrorCorrection::protectCorners(const Shape &shape) {
|
|||
Point2 p = transformation.project((*edge)->point(0));
|
||||
int l = (int) floor(p.x-.5);
|
||||
int b = (int) floor(p.y-.5);
|
||||
if (shape.inverseYAxis)
|
||||
b = stencil.height-b-2;
|
||||
int r = l+1;
|
||||
int t = b+1;
|
||||
// Check that the positions are within bounds.
|
||||
|
|
@ -189,8 +187,9 @@ static void protectExtremeChannels(byte *stencil, const float *msd, float m, int
|
|||
}
|
||||
|
||||
template <int N>
|
||||
void MSDFErrorCorrection::protectEdges(const BitmapConstRef<float, N> &sdf) {
|
||||
void MSDFErrorCorrection::protectEdges(const BitmapConstSection<float, N> &sdf) {
|
||||
float radius;
|
||||
stencil.reorient(sdf.yOrientation);
|
||||
// Horizontal texel pairs
|
||||
radius = float(PROTECTION_RADIUS_TOLERANCE*transformation.unprojectVector(Vector2(transformation.distanceMapping(DistanceMapping::Delta(1)), 0)).length());
|
||||
for (int y = 0; y < sdf.height; ++y) {
|
||||
|
|
@ -251,9 +250,11 @@ void MSDFErrorCorrection::protectEdges(const BitmapConstRef<float, N> &sdf) {
|
|||
}
|
||||
|
||||
void MSDFErrorCorrection::protectAll() {
|
||||
byte *end = stencil.pixels+stencil.width*stencil.height;
|
||||
for (byte *mask = stencil.pixels; mask < end; ++mask)
|
||||
*mask |= (byte) PROTECTED;
|
||||
for (int y = 0; y < stencil.height; ++y) {
|
||||
byte *mask = stencil(0, y);
|
||||
for (int x = 0; x < stencil.width; ++x)
|
||||
*mask++ |= (byte) PROTECTED;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the median of the linear interpolation of texels a, b at t.
|
||||
|
|
@ -273,16 +274,6 @@ static float interpolatedMedian(const float *a, const float *l, const float *q,
|
|||
));
|
||||
}
|
||||
|
||||
/// Determines if the interpolated median xm is an artifact.
|
||||
static bool isArtifact(bool isProtected, double axSpan, double bxSpan, float am, float bm, float xm) {
|
||||
return (
|
||||
// For protected texels, only report an artifact if it would cause fill inversion (change between positive and negative distance).
|
||||
(!isProtected || (am > .5f && bm > .5f && xm <= .5f) || (am < .5f && bm < .5f && xm >= .5f)) &&
|
||||
// This is an artifact if the interpolated median is outside the range of possible values based on its distance from a, b.
|
||||
!(xm >= am-axSpan && xm <= am+axSpan && xm >= bm-bxSpan && xm <= bm+bxSpan)
|
||||
);
|
||||
}
|
||||
|
||||
/// Checks if a linear interpolation artifact will occur at a point where two specific color channels are equal - such points have extreme median values.
|
||||
template <class ArtifactClassifier>
|
||||
static bool hasLinearArtifactInner(const ArtifactClassifier &artifactClassifier, float am, float bm, const float *a, const float *b, float dA, float dB) {
|
||||
|
|
@ -390,7 +381,8 @@ static bool hasDiagonalArtifact(const ArtifactClassifier &artifactClassifier, fl
|
|||
}
|
||||
|
||||
template <int N>
|
||||
void MSDFErrorCorrection::findErrors(const BitmapConstRef<float, N> &sdf) {
|
||||
void MSDFErrorCorrection::findErrors(const BitmapConstSection<float, N> &sdf) {
|
||||
stencil.reorient(sdf.yOrientation);
|
||||
// Compute the expected deltas between values of horizontally, vertically, and diagonally adjacent texels.
|
||||
double hSpan = minDeviationRatio*transformation.unprojectVector(Vector2(transformation.distanceMapping(DistanceMapping::Delta(1)), 0)).length();
|
||||
double vSpan = minDeviationRatio*transformation.unprojectVector(Vector2(0, transformation.distanceMapping(DistanceMapping::Delta(1)))).length();
|
||||
|
|
@ -418,7 +410,9 @@ void MSDFErrorCorrection::findErrors(const BitmapConstRef<float, N> &sdf) {
|
|||
}
|
||||
|
||||
template <template <typename> class ContourCombiner, int N>
|
||||
void MSDFErrorCorrection::findErrors(const BitmapConstRef<float, N> &sdf, const Shape &shape) {
|
||||
void MSDFErrorCorrection::findErrors(BitmapConstSection<float, N> sdf, const Shape &shape) {
|
||||
sdf.reorient(shape.getYAxisOrientation());
|
||||
stencil.reorient(sdf.yOrientation);
|
||||
// Compute the expected deltas between values of horizontally, vertically, and diagonally adjacent texels.
|
||||
double hSpan = minDeviationRatio*transformation.unprojectVector(Vector2(transformation.distanceMapping(DistanceMapping::Delta(1)), 0)).length();
|
||||
double vSpan = minDeviationRatio*transformation.unprojectVector(Vector2(0, transformation.distanceMapping(DistanceMapping::Delta(1)))).length();
|
||||
|
|
@ -428,69 +422,75 @@ void MSDFErrorCorrection::findErrors(const BitmapConstRef<float, N> &sdf, const
|
|||
#endif
|
||||
{
|
||||
ShapeDistanceChecker<ContourCombiner, N> shapeDistanceChecker(sdf, shape, transformation, transformation.distanceMapping, minImproveRatio);
|
||||
bool rightToLeft = false;
|
||||
int xDirection = 1;
|
||||
// Inspect all texels.
|
||||
#ifdef MSDFGEN_USE_OPENMP
|
||||
#pragma omp for
|
||||
#endif
|
||||
for (int y = 0; y < sdf.height; ++y) {
|
||||
int row = shape.inverseYAxis ? sdf.height-y-1 : y;
|
||||
for (int col = 0; col < sdf.width; ++col) {
|
||||
int x = rightToLeft ? sdf.width-col-1 : col;
|
||||
if ((*stencil(x, row)&ERROR))
|
||||
int x = xDirection < 0 ? sdf.width-1 : 0;
|
||||
for (int col = 0; col < sdf.width; ++col, x += xDirection) {
|
||||
if ((*stencil(x, y)&ERROR))
|
||||
continue;
|
||||
const float *c = sdf(x, row);
|
||||
const float *c = sdf(x, y);
|
||||
shapeDistanceChecker.shapeCoord = transformation.unproject(Point2(x+.5, y+.5));
|
||||
shapeDistanceChecker.sdfCoord = Point2(x+.5, row+.5);
|
||||
shapeDistanceChecker.sdfCoord = Point2(x+.5, y+.5);
|
||||
shapeDistanceChecker.msd = c;
|
||||
shapeDistanceChecker.protectedFlag = (*stencil(x, row)&PROTECTED) != 0;
|
||||
shapeDistanceChecker.protectedFlag = (*stencil(x, y)&PROTECTED) != 0;
|
||||
float cm = median(c[0], c[1], c[2]);
|
||||
const float *l = NULL, *b = NULL, *r = NULL, *t = NULL;
|
||||
// Mark current texel c with the error flag if an artifact occurs when it's interpolated with any of its 8 neighbors.
|
||||
*stencil(x, row) |= (byte) (ERROR*(
|
||||
(x > 0 && ((l = sdf(x-1, row)), hasLinearArtifact(shapeDistanceChecker.classifier(Vector2(-1, 0), hSpan), cm, c, l))) ||
|
||||
(row > 0 && ((b = sdf(x, row-1)), hasLinearArtifact(shapeDistanceChecker.classifier(Vector2(0, -1), vSpan), cm, c, b))) ||
|
||||
(x < sdf.width-1 && ((r = sdf(x+1, row)), hasLinearArtifact(shapeDistanceChecker.classifier(Vector2(+1, 0), hSpan), cm, c, r))) ||
|
||||
(row < sdf.height-1 && ((t = sdf(x, row+1)), hasLinearArtifact(shapeDistanceChecker.classifier(Vector2(0, +1), vSpan), cm, c, t))) ||
|
||||
(x > 0 && row > 0 && hasDiagonalArtifact(shapeDistanceChecker.classifier(Vector2(-1, -1), dSpan), cm, c, l, b, sdf(x-1, row-1))) ||
|
||||
(x < sdf.width-1 && row > 0 && hasDiagonalArtifact(shapeDistanceChecker.classifier(Vector2(+1, -1), dSpan), cm, c, r, b, sdf(x+1, row-1))) ||
|
||||
(x > 0 && row < sdf.height-1 && hasDiagonalArtifact(shapeDistanceChecker.classifier(Vector2(-1, +1), dSpan), cm, c, l, t, sdf(x-1, row+1))) ||
|
||||
(x < sdf.width-1 && row < sdf.height-1 && hasDiagonalArtifact(shapeDistanceChecker.classifier(Vector2(+1, +1), dSpan), cm, c, r, t, sdf(x+1, row+1)))
|
||||
*stencil(x, y) |= (byte) (ERROR*(
|
||||
(x > 0 && ((l = sdf(x-1, y)), hasLinearArtifact(shapeDistanceChecker.classifier(Vector2(-1, 0), hSpan), cm, c, l))) ||
|
||||
(y > 0 && ((b = sdf(x, y-1)), hasLinearArtifact(shapeDistanceChecker.classifier(Vector2(0, -1), vSpan), cm, c, b))) ||
|
||||
(x < sdf.width-1 && ((r = sdf(x+1, y)), hasLinearArtifact(shapeDistanceChecker.classifier(Vector2(+1, 0), hSpan), cm, c, r))) ||
|
||||
(y < sdf.height-1 && ((t = sdf(x, y+1)), hasLinearArtifact(shapeDistanceChecker.classifier(Vector2(0, +1), vSpan), cm, c, t))) ||
|
||||
(x > 0 && y > 0 && hasDiagonalArtifact(shapeDistanceChecker.classifier(Vector2(-1, -1), dSpan), cm, c, l, b, sdf(x-1, y-1))) ||
|
||||
(x < sdf.width-1 && y > 0 && hasDiagonalArtifact(shapeDistanceChecker.classifier(Vector2(+1, -1), dSpan), cm, c, r, b, sdf(x+1, y-1))) ||
|
||||
(x > 0 && y < sdf.height-1 && hasDiagonalArtifact(shapeDistanceChecker.classifier(Vector2(-1, +1), dSpan), cm, c, l, t, sdf(x-1, y+1))) ||
|
||||
(x < sdf.width-1 && y < sdf.height-1 && hasDiagonalArtifact(shapeDistanceChecker.classifier(Vector2(+1, +1), dSpan), cm, c, r, t, sdf(x+1, y+1)))
|
||||
));
|
||||
}
|
||||
xDirection = -xDirection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <int N>
|
||||
void MSDFErrorCorrection::apply(const BitmapRef<float, N> &sdf) const {
|
||||
int texelCount = sdf.width*sdf.height;
|
||||
const byte *mask = stencil.pixels;
|
||||
float *texel = sdf.pixels;
|
||||
for (int i = 0; i < texelCount; ++i) {
|
||||
if (*mask&ERROR) {
|
||||
// Set all color channels to the median.
|
||||
float m = median(texel[0], texel[1], texel[2]);
|
||||
texel[0] = m, texel[1] = m, texel[2] = m;
|
||||
void MSDFErrorCorrection::apply(BitmapSection<float, N> sdf) const {
|
||||
sdf.reorient(stencil.yOrientation);
|
||||
const byte *stencilRow = stencil.pixels;
|
||||
float *rowStart = sdf.pixels;
|
||||
for (int y = 0; y < sdf.height; ++y) {
|
||||
const byte *mask = stencilRow;
|
||||
float *pixel = rowStart;
|
||||
for (int x = 0; x < sdf.width; ++x) {
|
||||
if (*mask&ERROR) {
|
||||
// Set all color channels to the median.
|
||||
float m = median(pixel[0], pixel[1], pixel[2]);
|
||||
pixel[0] = m, pixel[1] = m, pixel[2] = m;
|
||||
}
|
||||
++mask;
|
||||
pixel += N;
|
||||
}
|
||||
++mask;
|
||||
texel += N;
|
||||
stencilRow += stencil.rowStride;
|
||||
rowStart += sdf.rowStride;
|
||||
}
|
||||
}
|
||||
|
||||
BitmapConstRef<byte, 1> MSDFErrorCorrection::getStencil() const {
|
||||
BitmapConstSection<byte, 1> MSDFErrorCorrection::getStencil() const {
|
||||
return stencil;
|
||||
}
|
||||
|
||||
template void MSDFErrorCorrection::protectEdges(const BitmapConstRef<float, 3> &sdf);
|
||||
template void MSDFErrorCorrection::protectEdges(const BitmapConstRef<float, 4> &sdf);
|
||||
template void MSDFErrorCorrection::findErrors(const BitmapConstRef<float, 3> &sdf);
|
||||
template void MSDFErrorCorrection::findErrors(const BitmapConstRef<float, 4> &sdf);
|
||||
template void MSDFErrorCorrection::findErrors<SimpleContourCombiner>(const BitmapConstRef<float, 3> &sdf, const Shape &shape);
|
||||
template void MSDFErrorCorrection::findErrors<SimpleContourCombiner>(const BitmapConstRef<float, 4> &sdf, const Shape &shape);
|
||||
template void MSDFErrorCorrection::findErrors<OverlappingContourCombiner>(const BitmapConstRef<float, 3> &sdf, const Shape &shape);
|
||||
template void MSDFErrorCorrection::findErrors<OverlappingContourCombiner>(const BitmapConstRef<float, 4> &sdf, const Shape &shape);
|
||||
template void MSDFErrorCorrection::apply(const BitmapRef<float, 3> &sdf) const;
|
||||
template void MSDFErrorCorrection::apply(const BitmapRef<float, 4> &sdf) const;
|
||||
template void MSDFErrorCorrection::protectEdges(const BitmapConstSection<float, 3> &sdf);
|
||||
template void MSDFErrorCorrection::protectEdges(const BitmapConstSection<float, 4> &sdf);
|
||||
template void MSDFErrorCorrection::findErrors(const BitmapConstSection<float, 3> &sdf);
|
||||
template void MSDFErrorCorrection::findErrors(const BitmapConstSection<float, 4> &sdf);
|
||||
template void MSDFErrorCorrection::findErrors<SimpleContourCombiner>(BitmapConstSection<float, 3> sdf, const Shape &shape);
|
||||
template void MSDFErrorCorrection::findErrors<SimpleContourCombiner>(BitmapConstSection<float, 4> sdf, const Shape &shape);
|
||||
template void MSDFErrorCorrection::findErrors<OverlappingContourCombiner>(BitmapConstSection<float, 3> sdf, const Shape &shape);
|
||||
template void MSDFErrorCorrection::findErrors<OverlappingContourCombiner>(BitmapConstSection<float, 4> sdf, const Shape &shape);
|
||||
template void MSDFErrorCorrection::apply(BitmapSection<float, 3> sdf) const;
|
||||
template void MSDFErrorCorrection::apply(BitmapSection<float, 4> sdf) const;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public:
|
|||
};
|
||||
|
||||
MSDFErrorCorrection();
|
||||
explicit MSDFErrorCorrection(const BitmapRef<byte, 1> &stencil, const SDFTransformation &transformation);
|
||||
explicit MSDFErrorCorrection(const BitmapSection<byte, 1> &stencil, const SDFTransformation &transformation);
|
||||
/// Sets the minimum ratio between the actual and maximum expected distance delta to be considered an error.
|
||||
void setMinDeviationRatio(double minDeviationRatio);
|
||||
/// Sets the minimum ratio between the pre-correction distance error and the post-correction distance error.
|
||||
|
|
@ -29,23 +29,23 @@ public:
|
|||
void protectCorners(const Shape &shape);
|
||||
/// Flags all texels that contribute to edges as protected.
|
||||
template <int N>
|
||||
void protectEdges(const BitmapConstRef<float, N> &sdf);
|
||||
void protectEdges(const BitmapConstSection<float, N> &sdf);
|
||||
/// Flags all texels as protected.
|
||||
void protectAll();
|
||||
/// Flags texels that are expected to cause interpolation artifacts based on analysis of the SDF only.
|
||||
template <int N>
|
||||
void findErrors(const BitmapConstRef<float, N> &sdf);
|
||||
void findErrors(const BitmapConstSection<float, N> &sdf);
|
||||
/// Flags texels that are expected to cause interpolation artifacts based on analysis of the SDF and comparison with the exact shape distance.
|
||||
template <template <typename> class ContourCombiner, int N>
|
||||
void findErrors(const BitmapConstRef<float, N> &sdf, const Shape &shape);
|
||||
void findErrors(BitmapConstSection<float, N> sdf, const Shape &shape);
|
||||
/// Modifies the MSDF so that all texels with the error flag are converted to single-channel.
|
||||
template <int N>
|
||||
void apply(const BitmapRef<float, N> &sdf) const;
|
||||
void apply(BitmapSection<float, N> sdf) const;
|
||||
/// Returns the stencil in its current state (see Flags).
|
||||
BitmapConstRef<byte, 1> getStencil() const;
|
||||
BitmapConstSection<byte, 1> getStencil() const;
|
||||
|
||||
private:
|
||||
BitmapRef<byte, 1> stencil;
|
||||
BitmapSection<byte, 1> stencil;
|
||||
SDFTransformation transformation;
|
||||
double minDeviationRatio;
|
||||
double minImproveRatio;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <cstdlib>
|
||||
#include "arithmetics.hpp"
|
||||
#include "convergent-curve-ordering.h"
|
||||
|
||||
#define DECONVERGE_OVERSHOOT 1.11111111111111111 // moves control points slightly more than necessary to account for floating-point errors
|
||||
|
||||
|
|
@ -70,7 +71,7 @@ void Shape::normalize() {
|
|||
contour->edges.push_back(EdgeHolder(parts[0]));
|
||||
contour->edges.push_back(EdgeHolder(parts[1]));
|
||||
contour->edges.push_back(EdgeHolder(parts[2]));
|
||||
} else {
|
||||
} else if (!contour->edges.empty()) {
|
||||
// Push apart convergent edge segments
|
||||
EdgeHolder *prevEdge = &contour->edges.back();
|
||||
for (std::vector<EdgeHolder>::iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
|
||||
|
|
@ -79,8 +80,7 @@ void Shape::normalize() {
|
|||
if (dotProduct(prevDir, curDir) < MSDFGEN_CORNER_DOT_EPSILON-1) {
|
||||
double factor = DECONVERGE_OVERSHOOT*sqrt(1-(MSDFGEN_CORNER_DOT_EPSILON-1)*(MSDFGEN_CORNER_DOT_EPSILON-1))/(MSDFGEN_CORNER_DOT_EPSILON-1);
|
||||
Vector2 axis = factor*(curDir-prevDir).normalize();
|
||||
// Determine curve ordering using third-order derivative (t = 0) of crossProduct((*prevEdge)->point(1-t)-p0, (*edge)->point(t)-p0) where p0 is the corner (*edge)->point(0)
|
||||
if (crossProduct((*prevEdge)->directionChange(1), (*edge)->direction(0))+crossProduct((*edge)->directionChange(0), (*prevEdge)->direction(1)) < 0)
|
||||
if (convergentCurveOrdering(*prevEdge, *edge) < 0)
|
||||
axis = -axis;
|
||||
deconvergeEdge(*prevEdge, 1, axis.getOrthogonal(true));
|
||||
deconvergeEdge(*edge, 0, axis.getOrthogonal(false));
|
||||
|
|
@ -91,14 +91,14 @@ void Shape::normalize() {
|
|||
}
|
||||
}
|
||||
|
||||
void Shape::bound(double &l, double &b, double &r, double &t) const {
|
||||
void Shape::bound(double &xMin, double &yMin, double &xMax, double &yMax) const {
|
||||
for (std::vector<Contour>::const_iterator contour = contours.begin(); contour != contours.end(); ++contour)
|
||||
contour->bound(l, b, r, t);
|
||||
contour->bound(xMin, yMin, xMax, yMax);
|
||||
}
|
||||
|
||||
void Shape::boundMiters(double &l, double &b, double &r, double &t, double border, double miterLimit, int polarity) const {
|
||||
void Shape::boundMiters(double &xMin, double &yMin, double &xMax, double &yMax, double border, double miterLimit, int polarity) const {
|
||||
for (std::vector<Contour>::const_iterator contour = contours.begin(); contour != contours.end(); ++contour)
|
||||
contour->boundMiters(l, b, r, t, border, miterLimit, polarity);
|
||||
contour->boundMiters(xMin, yMin, xMax, yMax, border, miterLimit, polarity);
|
||||
}
|
||||
|
||||
Shape::Bounds Shape::getBounds(double border, double miterLimit, int polarity) const {
|
||||
|
|
@ -197,4 +197,12 @@ void Shape::orientContours() {
|
|||
contours[i].reverse();
|
||||
}
|
||||
|
||||
YAxisOrientation Shape::getYAxisOrientation() const {
|
||||
return inverseYAxis ? MSDFGEN_Y_AXIS_NONDEFAULT_ORIENTATION : MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION;
|
||||
}
|
||||
|
||||
void Shape::setYAxisOrientation(YAxisOrientation yAxisOrientation) {
|
||||
inverseYAxis = yAxisOrientation != MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <vector>
|
||||
#include "Contour.h"
|
||||
#include "YAxisOrientation.h"
|
||||
#include "Scanline.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
|
@ -15,12 +16,14 @@ class Shape {
|
|||
|
||||
public:
|
||||
struct Bounds {
|
||||
// NOTE: b is actually the lower Y-coordinate and t the higher Y-coordinate. For Y_DOWNWARD orientation, b is actually the top and t the bottom. May be renamed in a future version.
|
||||
double l, b, r, t;
|
||||
};
|
||||
|
||||
/// The list of contours the shape consists of.
|
||||
std::vector<Contour> contours;
|
||||
/// Specifies whether the shape uses bottom-to-top (false) or top-to-bottom (true) Y coordinates.
|
||||
/// DEPRECATED - use getYAxisOrientation / setYAxisOrientation instead.
|
||||
bool inverseYAxis;
|
||||
|
||||
Shape();
|
||||
|
|
@ -36,9 +39,9 @@ public:
|
|||
/// Performs basic checks to determine if the object represents a valid shape.
|
||||
bool validate() const;
|
||||
/// Adjusts the bounding box to fit the shape.
|
||||
void bound(double &l, double &b, double &r, double &t) const;
|
||||
void bound(double &xMin, double &yMin, double &xMax, double &yMax) const;
|
||||
/// Adjusts the bounding box to fit the shape border's mitered corners.
|
||||
void boundMiters(double &l, double &b, double &r, double &t, double border, double miterLimit, int polarity) const;
|
||||
void boundMiters(double &xMin, double &yMin, double &xMax, double &yMax, double border, double miterLimit, int polarity) const;
|
||||
/// Computes the minimum bounding box that fits the shape, optionally with a (mitered) border.
|
||||
Bounds getBounds(double border = 0, double miterLimit = 0, int polarity = 0) const;
|
||||
/// Outputs the scanline that intersects the shape at y.
|
||||
|
|
@ -47,6 +50,10 @@ public:
|
|||
int edgeCount() const;
|
||||
/// Assumes its contours are unoriented (even-odd fill rule). Attempts to orient them to conform to the non-zero winding rule.
|
||||
void orientContours();
|
||||
/// Returns the orientation of the axis of the shape's Y coordinates.
|
||||
YAxisOrientation getYAxisOrientation() const;
|
||||
/// Sets the orientation of the axis of the shape's Y coordinates.
|
||||
void setYAxisOrientation(YAxisOrientation yAxisOrientation);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "base.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Specifies whether the Y component of the coordinate system increases in the upward or downward direction.
|
||||
enum YAxisOrientation {
|
||||
Y_UPWARD,
|
||||
Y_DOWNWARD
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#define MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION msdfgen::Y_UPWARD
|
||||
#define MSDFGEN_Y_AXIS_NONDEFAULT_ORIENTATION (MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION == msdfgen::Y_DOWNWARD ? msdfgen::Y_UPWARD : msdfgen::Y_DOWNWARD)
|
||||
|
|
@ -8,7 +8,9 @@
|
|||
namespace msdfgen {
|
||||
|
||||
template <typename T, int N>
|
||||
static void interpolate(T *output, const BitmapConstRef<T, N> &bitmap, Point2 pos) {
|
||||
inline void interpolate(T *output, const BitmapConstSection<T, N> &bitmap, Point2 pos) {
|
||||
pos.x = clamp(pos.x, double(bitmap.width));
|
||||
pos.y = clamp(pos.y, double(bitmap.height));
|
||||
pos -= .5;
|
||||
int l = (int) floor(pos.x);
|
||||
int b = (int) floor(pos.y);
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ static double resolveDistance(const MultiDistance &distance) {
|
|||
}
|
||||
|
||||
template <class EdgeSelector>
|
||||
SimpleContourCombiner<EdgeSelector>::SimpleContourCombiner(const Shape &shape) { }
|
||||
SimpleContourCombiner<EdgeSelector>::SimpleContourCombiner(const Shape &) { }
|
||||
|
||||
template <class EdgeSelector>
|
||||
void SimpleContourCombiner<EdgeSelector>::reset(const Point2 &p) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,140 @@
|
|||
|
||||
#include "convergent-curve-ordering.h"
|
||||
|
||||
#include "arithmetics.hpp"
|
||||
#include "Vector2.hpp"
|
||||
|
||||
/*
|
||||
* For non-degenerate curves A(t), B(t) (ones where all control points are distinct) both originating at P = A(0) = B(0) = *corner,
|
||||
* we are computing the limit of
|
||||
*
|
||||
* sign(crossProduct( A(t / |A'(0)|) - P, B(t / |B'(0)|) - P ))
|
||||
*
|
||||
* for t -> 0 from 1. Of note is that the curves' parameter has to be normed by the first derivative at P,
|
||||
* which ensures that the limit approaches P at the same rate along both curves - omitting this was the main error of earlier versions of deconverge.
|
||||
*
|
||||
* For degenerate cubic curves (ones where the first control point equals the origin point), the denominator |A'(0)| is zero,
|
||||
* so to address that, we approach with the square root of t and use the derivative of A(sqrt(t)), which at t = 0 equals A''(0)/2
|
||||
* Therefore, in these cases, we replace one factor of the cross product with A(sqrt(2*t / |A''(0)|)) - P
|
||||
*
|
||||
* The cross product results in a polynomial (in respect to t or t^2 in the degenerate case),
|
||||
* the limit of sign of which at zero can be determined by the lowest order non-zero derivative,
|
||||
* which equals to the sign of the first non-zero polynomial coefficient in the order of increasing exponents.
|
||||
*
|
||||
* The polynomial's constant and linear terms are zero, so the first derivative is definitely zero as well.
|
||||
* The second derivative is assumed to be zero (or near zero) due to the curves being convergent - this is an input requirement
|
||||
* (otherwise the correct result is the sign of the cross product of their directions at t = 0).
|
||||
* Therefore, we skip the first and second derivatives.
|
||||
*/
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
static void simplifyDegenerateCurve(Point2 *controlPoints, int &order) {
|
||||
if (order == 3 && (controlPoints[1] == controlPoints[0] || controlPoints[1] == controlPoints[3]) && (controlPoints[2] == controlPoints[0] || controlPoints[2] == controlPoints[3])) {
|
||||
controlPoints[1] = controlPoints[3];
|
||||
order = 1;
|
||||
}
|
||||
if (order == 2 && (controlPoints[1] == controlPoints[0] || controlPoints[1] == controlPoints[2])) {
|
||||
controlPoints[1] = controlPoints[2];
|
||||
order = 1;
|
||||
}
|
||||
if (order == 1 && controlPoints[0] == controlPoints[1])
|
||||
order = 0;
|
||||
}
|
||||
|
||||
int convergentCurveOrdering(const Point2 *corner, int controlPointsBefore, int controlPointsAfter) {
|
||||
if (!(controlPointsBefore > 0 && controlPointsAfter > 0))
|
||||
return 0;
|
||||
Vector2 a1, a2, a3, b1, b2, b3;
|
||||
a1 = *(corner-1)-*corner;
|
||||
b1 = *(corner+1)-*corner;
|
||||
if (controlPointsBefore >= 2)
|
||||
a2 = *(corner-2)-*(corner-1)-a1;
|
||||
if (controlPointsAfter >= 2)
|
||||
b2 = *(corner+2)-*(corner+1)-b1;
|
||||
if (controlPointsBefore >= 3) {
|
||||
a3 = *(corner-3)-*(corner-2)-(*(corner-2)-*(corner-1))-a2;
|
||||
a2 *= 3;
|
||||
}
|
||||
if (controlPointsAfter >= 3) {
|
||||
b3 = *(corner+3)-*(corner+2)-(*(corner+2)-*(corner+1))-b2;
|
||||
b2 *= 3;
|
||||
}
|
||||
a1 *= controlPointsBefore;
|
||||
b1 *= controlPointsAfter;
|
||||
// Non-degenerate case
|
||||
if (a1 && b1) {
|
||||
double as = a1.length();
|
||||
double bs = b1.length();
|
||||
// Third derivative
|
||||
if (double d = as*crossProduct(a1, b2) + bs*crossProduct(a2, b1))
|
||||
return sign(d);
|
||||
// Fourth derivative
|
||||
if (double d = as*as*crossProduct(a1, b3) + as*bs*crossProduct(a2, b2) + bs*bs*crossProduct(a3, b1))
|
||||
return sign(d);
|
||||
// Fifth derivative
|
||||
if (double d = as*crossProduct(a2, b3) + bs*crossProduct(a3, b2))
|
||||
return sign(d);
|
||||
// Sixth derivative
|
||||
return sign(crossProduct(a3, b3));
|
||||
}
|
||||
// Degenerate curve after corner (control point after corner equals corner)
|
||||
int s = 1;
|
||||
if (a1) { // !b1
|
||||
// Swap aN <-> bN and handle in if (b1)
|
||||
b1 = a1;
|
||||
a1 = b2, b2 = a2, a2 = a1;
|
||||
a1 = b3, b3 = a3, a3 = a1;
|
||||
s = -1; // make sure to also flip output
|
||||
}
|
||||
// Degenerate curve before corner (control point before corner equals corner)
|
||||
if (b1) { // !a1
|
||||
// Two-and-a-half-th derivative
|
||||
if (double d = crossProduct(a3, b1))
|
||||
return s*sign(d);
|
||||
// Third derivative
|
||||
if (double d = crossProduct(a2, b2))
|
||||
return s*sign(d);
|
||||
// Three-and-a-half-th derivative
|
||||
if (double d = crossProduct(a3, b2))
|
||||
return s*sign(d);
|
||||
// Fourth derivative
|
||||
if (double d = crossProduct(a2, b3))
|
||||
return s*sign(d);
|
||||
// Four-and-a-half-th derivative
|
||||
return s*sign(crossProduct(a3, b3));
|
||||
}
|
||||
// Degenerate curves on both sides of the corner (control point before and after corner equals corner)
|
||||
{ // !a1 && !b1
|
||||
// Two-and-a-half-th derivative
|
||||
if (double d = sqrt(a2.length())*crossProduct(a2, b3) + sqrt(b2.length())*crossProduct(a3, b2))
|
||||
return sign(d);
|
||||
// Third derivative
|
||||
return sign(crossProduct(a3, b3));
|
||||
}
|
||||
}
|
||||
|
||||
int convergentCurveOrdering(const EdgeSegment *a, const EdgeSegment *b) {
|
||||
Point2 controlPoints[12];
|
||||
Point2 *corner = controlPoints+4;
|
||||
Point2 *aCpTmp = controlPoints+8;
|
||||
int aOrder = int(a->type());
|
||||
int bOrder = int(b->type());
|
||||
if (!(aOrder >= 1 && aOrder <= 3 && bOrder >= 1 && bOrder <= 3)) {
|
||||
// Not implemented - only linear, quadratic, and cubic curves supported
|
||||
return 0;
|
||||
}
|
||||
for (int i = 0; i <= aOrder; ++i)
|
||||
aCpTmp[i] = a->controlPoints()[i];
|
||||
for (int i = 0; i <= bOrder; ++i)
|
||||
corner[i] = b->controlPoints()[i];
|
||||
if (aCpTmp[aOrder] != *corner)
|
||||
return 0;
|
||||
simplifyDegenerateCurve(aCpTmp, aOrder);
|
||||
simplifyDegenerateCurve(corner, bOrder);
|
||||
for (int i = 0; i < aOrder; ++i)
|
||||
corner[i-aOrder] = aCpTmp[i];
|
||||
return convergentCurveOrdering(corner, aOrder, bOrder);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "edge-segments.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// For curves a, b converging at P = a->point(1) = b->point(0) with the same (opposite) direction, determines the relative ordering in which they exit P (i.e. whether a is to the left or right of b at the smallest positive radius around P)
|
||||
int convergentCurveOrdering(const EdgeSegment *a, const EdgeSegment *b);
|
||||
|
||||
}
|
||||
|
|
@ -199,9 +199,9 @@ SignedDistance QuadraticSegment::signedDistance(Point2 origin, double ¶m) co
|
|||
double minDistance = nonZeroSign(crossProduct(epDir, qa))*qa.length(); // distance from A
|
||||
param = -dotProduct(qa, epDir)/dotProduct(epDir, epDir);
|
||||
{
|
||||
epDir = direction(1);
|
||||
double distance = (p[2]-origin).length(); // distance from B
|
||||
if (distance < fabs(minDistance)) {
|
||||
epDir = direction(1);
|
||||
minDistance = nonZeroSign(crossProduct(epDir, p[2]-origin))*distance;
|
||||
param = dotProduct(origin-p[1], epDir)/dotProduct(epDir, epDir);
|
||||
}
|
||||
|
|
@ -235,25 +235,31 @@ SignedDistance CubicSegment::signedDistance(Point2 origin, double ¶m) const
|
|||
double minDistance = nonZeroSign(crossProduct(epDir, qa))*qa.length(); // distance from A
|
||||
param = -dotProduct(qa, epDir)/dotProduct(epDir, epDir);
|
||||
{
|
||||
epDir = direction(1);
|
||||
double distance = (p[3]-origin).length(); // distance from B
|
||||
if (distance < fabs(minDistance)) {
|
||||
epDir = direction(1);
|
||||
minDistance = nonZeroSign(crossProduct(epDir, p[3]-origin))*distance;
|
||||
param = dotProduct(epDir-(p[3]-origin), epDir)/dotProduct(epDir, epDir);
|
||||
}
|
||||
}
|
||||
// Iterative minimum distance search
|
||||
for (int i = 0; i <= MSDFGEN_CUBIC_SEARCH_STARTS; ++i) {
|
||||
double t = (double) i/MSDFGEN_CUBIC_SEARCH_STARTS;
|
||||
double t = 1./MSDFGEN_CUBIC_SEARCH_STARTS*i;
|
||||
Vector2 qe = qa+3*t*ab+3*t*t*br+t*t*t*as;
|
||||
for (int step = 0; step < MSDFGEN_CUBIC_SEARCH_STEPS; ++step) {
|
||||
// Improve t
|
||||
Vector2 d1 = 3*ab+6*t*br+3*t*t*as;
|
||||
Vector2 d2 = 6*br+6*t*as;
|
||||
t -= dotProduct(qe, d1)/(dotProduct(d1, d1)+dotProduct(qe, d2));
|
||||
if (t <= 0 || t >= 1)
|
||||
break;
|
||||
qe = qa+3*t*ab+3*t*t*br+t*t*t*as;
|
||||
Vector2 d1 = 3*ab+6*t*br+3*t*t*as;
|
||||
Vector2 d2 = 6*br+6*t*as;
|
||||
double improvedT = t-dotProduct(qe, d1)/(dotProduct(d1, d1)+dotProduct(qe, d2));
|
||||
if (improvedT > 0 && improvedT < 1) {
|
||||
int remainingSteps = MSDFGEN_CUBIC_SEARCH_STEPS;
|
||||
do {
|
||||
t = improvedT;
|
||||
qe = qa+3*t*ab+3*t*t*br+t*t*t*as;
|
||||
d1 = 3*ab+6*t*br+3*t*t*as;
|
||||
if (!--remainingSteps)
|
||||
break;
|
||||
d2 = 6*br+6*t*as;
|
||||
improvedT = t-dotProduct(qe, d1)/(dotProduct(d1, d1)+dotProduct(qe, d2));
|
||||
} while (improvedT > 0 && improvedT < 1);
|
||||
double distance = qe.length();
|
||||
if (distance < fabs(minDistance)) {
|
||||
minDistance = nonZeroSign(crossProduct(d1, qe))*distance;
|
||||
|
|
@ -396,37 +402,37 @@ int CubicSegment::scanlineIntersections(double x[3], int dy[3], double y) const
|
|||
return total;
|
||||
}
|
||||
|
||||
static void pointBounds(Point2 p, double &l, double &b, double &r, double &t) {
|
||||
if (p.x < l) l = p.x;
|
||||
if (p.y < b) b = p.y;
|
||||
if (p.x > r) r = p.x;
|
||||
if (p.y > t) t = p.y;
|
||||
static void pointBounds(Point2 p, double &xMin, double &yMin, double &xMax, double &yMax) {
|
||||
if (p.x < xMin) xMin = p.x;
|
||||
if (p.y < yMin) yMin = p.y;
|
||||
if (p.x > xMax) xMax = p.x;
|
||||
if (p.y > yMax) yMax = p.y;
|
||||
}
|
||||
|
||||
void LinearSegment::bound(double &l, double &b, double &r, double &t) const {
|
||||
pointBounds(p[0], l, b, r, t);
|
||||
pointBounds(p[1], l, b, r, t);
|
||||
void LinearSegment::bound(double &xMin, double &yMin, double &xMax, double &yMax) const {
|
||||
pointBounds(p[0], xMin, yMin, xMax, yMax);
|
||||
pointBounds(p[1], xMin, yMin, xMax, yMax);
|
||||
}
|
||||
|
||||
void QuadraticSegment::bound(double &l, double &b, double &r, double &t) const {
|
||||
pointBounds(p[0], l, b, r, t);
|
||||
pointBounds(p[2], l, b, r, t);
|
||||
void QuadraticSegment::bound(double &xMin, double &yMin, double &xMax, double &yMax) const {
|
||||
pointBounds(p[0], xMin, yMin, xMax, yMax);
|
||||
pointBounds(p[2], xMin, yMin, xMax, yMax);
|
||||
Vector2 bot = (p[1]-p[0])-(p[2]-p[1]);
|
||||
if (bot.x) {
|
||||
double param = (p[1].x-p[0].x)/bot.x;
|
||||
if (param > 0 && param < 1)
|
||||
pointBounds(point(param), l, b, r, t);
|
||||
pointBounds(point(param), xMin, yMin, xMax, yMax);
|
||||
}
|
||||
if (bot.y) {
|
||||
double param = (p[1].y-p[0].y)/bot.y;
|
||||
if (param > 0 && param < 1)
|
||||
pointBounds(point(param), l, b, r, t);
|
||||
pointBounds(point(param), xMin, yMin, xMax, yMax);
|
||||
}
|
||||
}
|
||||
|
||||
void CubicSegment::bound(double &l, double &b, double &r, double &t) const {
|
||||
pointBounds(p[0], l, b, r, t);
|
||||
pointBounds(p[3], l, b, r, t);
|
||||
void CubicSegment::bound(double &xMin, double &yMin, double &xMax, double &yMax) const {
|
||||
pointBounds(p[0], xMin, yMin, xMax, yMax);
|
||||
pointBounds(p[3], xMin, yMin, xMax, yMax);
|
||||
Vector2 a0 = p[1]-p[0];
|
||||
Vector2 a1 = 2*(p[2]-p[1]-a0);
|
||||
Vector2 a2 = p[3]-3*p[2]+3*p[1]-p[0];
|
||||
|
|
@ -435,11 +441,11 @@ void CubicSegment::bound(double &l, double &b, double &r, double &t) const {
|
|||
solutions = solveQuadratic(params, a2.x, a1.x, a0.x);
|
||||
for (int i = 0; i < solutions; ++i)
|
||||
if (params[i] > 0 && params[i] < 1)
|
||||
pointBounds(point(params[i]), l, b, r, t);
|
||||
pointBounds(point(params[i]), xMin, yMin, xMax, yMax);
|
||||
solutions = solveQuadratic(params, a2.y, a1.y, a0.y);
|
||||
for (int i = 0; i < solutions; ++i)
|
||||
if (params[i] > 0 && params[i] < 1)
|
||||
pointBounds(point(params[i]), l, b, r, t);
|
||||
pointBounds(point(params[i]), xMin, yMin, xMax, yMax);
|
||||
}
|
||||
|
||||
void LinearSegment::reverse() {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ public:
|
|||
/// Outputs a list of (at most three) intersections (their X coordinates) with an infinite horizontal scanline at y and returns how many there are.
|
||||
virtual int scanlineIntersections(double x[3], int dy[3], double y) const = 0;
|
||||
/// Adjusts the bounding box to fit the edge segment.
|
||||
virtual void bound(double &l, double &b, double &r, double &t) const = 0;
|
||||
virtual void bound(double &xMin, double &yMin, double &xMax, double &yMax) const = 0;
|
||||
|
||||
/// Reverses the edge (swaps its start point and end point).
|
||||
virtual void reverse() = 0;
|
||||
|
|
@ -75,7 +75,7 @@ public:
|
|||
double length() const;
|
||||
SignedDistance signedDistance(Point2 origin, double ¶m) const;
|
||||
int scanlineIntersections(double x[3], int dy[3], double y) const;
|
||||
void bound(double &l, double &b, double &r, double &t) const;
|
||||
void bound(double &xMin, double &yMin, double &xMax, double &yMax) const;
|
||||
|
||||
void reverse();
|
||||
void moveStartPoint(Point2 to);
|
||||
|
|
@ -104,7 +104,7 @@ public:
|
|||
double length() const;
|
||||
SignedDistance signedDistance(Point2 origin, double ¶m) const;
|
||||
int scanlineIntersections(double x[3], int dy[3], double y) const;
|
||||
void bound(double &l, double &b, double &r, double &t) const;
|
||||
void bound(double &xMin, double &yMin, double &xMax, double &yMax) const;
|
||||
|
||||
void reverse();
|
||||
void moveStartPoint(Point2 to);
|
||||
|
|
@ -134,7 +134,7 @@ public:
|
|||
Vector2 directionChange(double param) const;
|
||||
SignedDistance signedDistance(Point2 origin, double ¶m) const;
|
||||
int scanlineIntersections(double x[3], int dy[3], double y) const;
|
||||
void bound(double &l, double &b, double &r, double &t) const;
|
||||
void bound(double &xMin, double &yMin, double &xMax, double &yMax) const;
|
||||
|
||||
void reverse();
|
||||
void moveStartPoint(Point2 to);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ TrueDistanceSelector::EdgeCache::EdgeCache() : absDistance(0) { }
|
|||
|
||||
void TrueDistanceSelector::reset(const Point2 &p) {
|
||||
double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
|
||||
// Since minDistance.distance is initialized to -DBL_MAX, at first glance this seems like it could make it underflow to -infinity, but in practice delta would have to be extremely high for this to happen (above 9e291)
|
||||
minDistance.distance += nonZeroSign(minDistance.distance)*delta;
|
||||
this->p = p;
|
||||
}
|
||||
|
|
@ -60,7 +61,7 @@ void PerpendicularDistanceSelectorBase::reset(double delta) {
|
|||
nearEdgeParam = 0;
|
||||
}
|
||||
|
||||
bool PerpendicularDistanceSelectorBase::isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *edge, const Point2 &p) const {
|
||||
bool PerpendicularDistanceSelectorBase::isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *, const Point2 &p) const {
|
||||
double delta = DISTANCE_DELTA_FACTOR*(p-cache.point).length();
|
||||
return (
|
||||
cache.absDistance-delta <= fabs(minTrueDistance.distance) ||
|
||||
|
|
|
|||
|
|
@ -1,79 +0,0 @@
|
|||
|
||||
#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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
|
||||
#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,15 +10,14 @@
|
|||
namespace msdfgen {
|
||||
|
||||
template <int N>
|
||||
static void msdfErrorCorrectionInner(const BitmapRef<float, N> &sdf, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config) {
|
||||
static void msdfErrorCorrectionInner(const BitmapSection<float, N> &sdf, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config) {
|
||||
if (config.errorCorrection.mode == ErrorCorrectionConfig::DISABLED)
|
||||
return;
|
||||
Bitmap<byte, 1> stencilBuffer;
|
||||
if (!config.errorCorrection.buffer)
|
||||
stencilBuffer = Bitmap<byte, 1>(sdf.width, sdf.height);
|
||||
BitmapRef<byte, 1> stencil;
|
||||
BitmapSection<byte, 1> stencil(NULL, sdf.width, sdf.height);
|
||||
stencil.pixels = config.errorCorrection.buffer ? config.errorCorrection.buffer : (byte *) stencilBuffer;
|
||||
stencil.width = sdf.width, stencil.height = sdf.height;
|
||||
MSDFErrorCorrection ec(stencil, transformation);
|
||||
ec.setMinDeviationRatio(config.errorCorrection.minDeviationRatio);
|
||||
ec.setMinImproveRatio(config.errorCorrection.minImproveRatio);
|
||||
|
|
@ -49,7 +48,7 @@ static void msdfErrorCorrectionInner(const BitmapRef<float, N> &sdf, const Shape
|
|||
}
|
||||
|
||||
template <int N>
|
||||
static void msdfErrorCorrectionShapeless(const BitmapRef<float, N> &sdf, const SDFTransformation &transformation, double minDeviationRatio, bool protectAll) {
|
||||
static void msdfErrorCorrectionShapeless(const BitmapSection<float, N> &sdf, const SDFTransformation &transformation, double minDeviationRatio, bool protectAll) {
|
||||
Bitmap<byte, 1> stencilBuffer(sdf.width, sdf.height);
|
||||
MSDFErrorCorrection ec(stencilBuffer, transformation);
|
||||
ec.setMinDeviationRatio(minDeviationRatio);
|
||||
|
|
@ -59,54 +58,54 @@ static void msdfErrorCorrectionShapeless(const BitmapRef<float, N> &sdf, const S
|
|||
ec.apply(sdf);
|
||||
}
|
||||
|
||||
void msdfErrorCorrection(const BitmapRef<float, 3> &sdf, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config) {
|
||||
void msdfErrorCorrection(const BitmapSection<float, 3> &sdf, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config) {
|
||||
msdfErrorCorrectionInner(sdf, shape, transformation, config);
|
||||
}
|
||||
void msdfErrorCorrection(const BitmapRef<float, 4> &sdf, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config) {
|
||||
void msdfErrorCorrection(const BitmapSection<float, 4> &sdf, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config) {
|
||||
msdfErrorCorrectionInner(sdf, shape, transformation, config);
|
||||
}
|
||||
void msdfErrorCorrection(const BitmapRef<float, 3> &sdf, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config) {
|
||||
void msdfErrorCorrection(const BitmapSection<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) {
|
||||
void msdfErrorCorrection(const BitmapSection<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 SDFTransformation &transformation, double minDeviationRatio) {
|
||||
void msdfFastDistanceErrorCorrection(const BitmapSection<float, 3> &sdf, const SDFTransformation &transformation, double minDeviationRatio) {
|
||||
msdfErrorCorrectionShapeless(sdf, transformation, minDeviationRatio, false);
|
||||
}
|
||||
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 4> &sdf, const SDFTransformation &transformation, double minDeviationRatio) {
|
||||
void msdfFastDistanceErrorCorrection(const BitmapSection<float, 4> &sdf, const SDFTransformation &transformation, double minDeviationRatio) {
|
||||
msdfErrorCorrectionShapeless(sdf, transformation, minDeviationRatio, false);
|
||||
}
|
||||
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 3> &sdf, const Projection &projection, Range range, double minDeviationRatio) {
|
||||
void msdfFastDistanceErrorCorrection(const BitmapSection<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) {
|
||||
void msdfFastDistanceErrorCorrection(const BitmapSection<float, 4> &sdf, const Projection &projection, Range range, double minDeviationRatio) {
|
||||
msdfErrorCorrectionShapeless(sdf, SDFTransformation(projection, range), minDeviationRatio, false);
|
||||
}
|
||||
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 3> &sdf, Range pxRange, double minDeviationRatio) {
|
||||
void msdfFastDistanceErrorCorrection(const BitmapSection<float, 3> &sdf, Range pxRange, double minDeviationRatio) {
|
||||
msdfErrorCorrectionShapeless(sdf, SDFTransformation(Projection(), pxRange), minDeviationRatio, false);
|
||||
}
|
||||
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 4> &sdf, Range pxRange, double minDeviationRatio) {
|
||||
void msdfFastDistanceErrorCorrection(const BitmapSection<float, 4> &sdf, Range pxRange, double minDeviationRatio) {
|
||||
msdfErrorCorrectionShapeless(sdf, SDFTransformation(Projection(), pxRange), minDeviationRatio, false);
|
||||
}
|
||||
|
||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 3> &sdf, const SDFTransformation &transformation, double minDeviationRatio) {
|
||||
void msdfFastEdgeErrorCorrection(const BitmapSection<float, 3> &sdf, const SDFTransformation &transformation, double minDeviationRatio) {
|
||||
msdfErrorCorrectionShapeless(sdf, transformation, minDeviationRatio, true);
|
||||
}
|
||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 4> &sdf, const SDFTransformation &transformation, double minDeviationRatio) {
|
||||
void msdfFastEdgeErrorCorrection(const BitmapSection<float, 4> &sdf, const SDFTransformation &transformation, double minDeviationRatio) {
|
||||
msdfErrorCorrectionShapeless(sdf, transformation, minDeviationRatio, true);
|
||||
}
|
||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 3> &sdf, const Projection &projection, Range range, double minDeviationRatio) {
|
||||
void msdfFastEdgeErrorCorrection(const BitmapSection<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) {
|
||||
void msdfFastEdgeErrorCorrection(const BitmapSection<float, 4> &sdf, const Projection &projection, Range range, double minDeviationRatio) {
|
||||
msdfErrorCorrectionShapeless(sdf, SDFTransformation(projection, range), minDeviationRatio, true);
|
||||
}
|
||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 3> &sdf, Range pxRange, double minDeviationRatio) {
|
||||
void msdfFastEdgeErrorCorrection(const BitmapSection<float, 3> &sdf, Range pxRange, double minDeviationRatio) {
|
||||
msdfErrorCorrectionShapeless(sdf, SDFTransformation(Projection(), pxRange), minDeviationRatio, true);
|
||||
}
|
||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 4> &sdf, Range pxRange, double minDeviationRatio) {
|
||||
void msdfFastEdgeErrorCorrection(const BitmapSection<float, 4> &sdf, Range pxRange, double minDeviationRatio) {
|
||||
msdfErrorCorrectionShapeless(sdf, SDFTransformation(Projection(), pxRange), minDeviationRatio, true);
|
||||
}
|
||||
|
||||
|
|
@ -136,7 +135,7 @@ inline static bool detectClash(const float *a, const float *b, double threshold)
|
|||
}
|
||||
|
||||
template <int N>
|
||||
static void msdfErrorCorrectionInner_legacy(const BitmapRef<float, N> &output, const Vector2 &threshold) {
|
||||
static void msdfErrorCorrectionInner_legacy(const BitmapSection<float, N> &output, const Vector2 &threshold) {
|
||||
std::vector<std::pair<int, int> > clashes;
|
||||
int w = output.width, h = output.height;
|
||||
for (int y = 0; y < h; ++y)
|
||||
|
|
@ -174,10 +173,10 @@ static void msdfErrorCorrectionInner_legacy(const BitmapRef<float, N> &output, c
|
|||
#endif
|
||||
}
|
||||
|
||||
void msdfErrorCorrection_legacy(const BitmapRef<float, 3> &output, const Vector2 &threshold) {
|
||||
void msdfErrorCorrection_legacy(const BitmapSection<float, 3> &output, const Vector2 &threshold) {
|
||||
msdfErrorCorrectionInner_legacy(output, threshold);
|
||||
}
|
||||
void msdfErrorCorrection_legacy(const BitmapRef<float, 4> &output, const Vector2 &threshold) {
|
||||
void msdfErrorCorrection_legacy(const BitmapSection<float, 4> &output, const Vector2 &threshold) {
|
||||
msdfErrorCorrectionInner_legacy(output, threshold);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,29 +12,29 @@
|
|||
namespace msdfgen {
|
||||
|
||||
/// Predicts potential artifacts caused by the interpolation of the MSDF and corrects them by converting nearby texels to single-channel.
|
||||
void msdfErrorCorrection(const BitmapRef<float, 3> &sdf, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void msdfErrorCorrection(const BitmapRef<float, 4> &sdf, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void msdfErrorCorrection(const BitmapRef<float, 3> &sdf, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void msdfErrorCorrection(const BitmapRef<float, 4> &sdf, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void msdfErrorCorrection(const BitmapSection<float, 3> &sdf, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void msdfErrorCorrection(const BitmapSection<float, 4> &sdf, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void msdfErrorCorrection(const BitmapSection<float, 3> &sdf, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void msdfErrorCorrection(const BitmapSection<float, 4> &sdf, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
|
||||
/// Applies the simplified error correction to all discontiunous distances (INDISCRIMINATE mode). Does not need shape or translation.
|
||||
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 3> &sdf, const SDFTransformation &transformation, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 4> &sdf, const SDFTransformation &transformation, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 3> &sdf, const Projection &projection, Range range, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 4> &sdf, const Projection &projection, Range range, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 3> &sdf, Range pxRange, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastDistanceErrorCorrection(const BitmapRef<float, 4> &sdf, Range pxRange, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastDistanceErrorCorrection(const BitmapSection<float, 3> &sdf, const SDFTransformation &transformation, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastDistanceErrorCorrection(const BitmapSection<float, 4> &sdf, const SDFTransformation &transformation, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastDistanceErrorCorrection(const BitmapSection<float, 3> &sdf, const Projection &projection, Range range, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastDistanceErrorCorrection(const BitmapSection<float, 4> &sdf, const Projection &projection, Range range, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastDistanceErrorCorrection(const BitmapSection<float, 3> &sdf, Range pxRange, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastDistanceErrorCorrection(const BitmapSection<float, 4> &sdf, Range pxRange, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
|
||||
/// Applies the simplified error correction to edges only (EDGE_ONLY mode). Does not need shape or translation.
|
||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 3> &sdf, const SDFTransformation &transformation, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 4> &sdf, const SDFTransformation &transformation, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 3> &sdf, const Projection &projection, Range range, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 4> &sdf, const Projection &projection, Range range, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 3> &sdf, Range pxRange, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastEdgeErrorCorrection(const BitmapRef<float, 4> &sdf, Range pxRange, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastEdgeErrorCorrection(const BitmapSection<float, 3> &sdf, const SDFTransformation &transformation, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastEdgeErrorCorrection(const BitmapSection<float, 4> &sdf, const SDFTransformation &transformation, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastEdgeErrorCorrection(const BitmapSection<float, 3> &sdf, const Projection &projection, Range range, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastEdgeErrorCorrection(const BitmapSection<float, 4> &sdf, const Projection &projection, Range range, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastEdgeErrorCorrection(const BitmapSection<float, 3> &sdf, Range pxRange, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
void msdfFastEdgeErrorCorrection(const BitmapSection<float, 4> &sdf, Range pxRange, double minDeviationRatio = ErrorCorrectionConfig::defaultMinDeviationRatio);
|
||||
|
||||
/// 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, 4> &output, const Vector2 &threshold);
|
||||
void msdfErrorCorrection_legacy(const BitmapSection<float, 3> &output, const Vector2 &threshold);
|
||||
void msdfErrorCorrection_legacy(const BitmapSection<float, 4> &output, const Vector2 &threshold);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ template <>
|
|||
class DistancePixelConversion<double> {
|
||||
DistanceMapping mapping;
|
||||
public:
|
||||
typedef BitmapRef<float, 1> BitmapRefType;
|
||||
typedef BitmapSection<float, 1> BitmapSectionType;
|
||||
inline explicit DistancePixelConversion(DistanceMapping mapping) : mapping(mapping) { }
|
||||
inline void operator()(float *pixels, double distance) const {
|
||||
*pixels = float(mapping(distance));
|
||||
|
|
@ -26,7 +26,7 @@ template <>
|
|||
class DistancePixelConversion<MultiDistance> {
|
||||
DistanceMapping mapping;
|
||||
public:
|
||||
typedef BitmapRef<float, 3> BitmapRefType;
|
||||
typedef BitmapSection<float, 3> BitmapSectionType;
|
||||
inline explicit DistancePixelConversion(DistanceMapping mapping) : mapping(mapping) { }
|
||||
inline void operator()(float *pixels, const MultiDistance &distance) const {
|
||||
pixels[0] = float(mapping(distance.r));
|
||||
|
|
@ -39,7 +39,7 @@ template <>
|
|||
class DistancePixelConversion<MultiAndTrueDistance> {
|
||||
DistanceMapping mapping;
|
||||
public:
|
||||
typedef BitmapRef<float, 4> BitmapRefType;
|
||||
typedef BitmapSection<float, 4> BitmapSectionType;
|
||||
inline explicit DistancePixelConversion(DistanceMapping mapping) : mapping(mapping) { }
|
||||
inline void operator()(float *pixels, const MultiAndTrueDistance &distance) const {
|
||||
pixels[0] = float(mapping(distance.r));
|
||||
|
|
@ -50,45 +50,46 @@ public:
|
|||
};
|
||||
|
||||
template <class ContourCombiner>
|
||||
void generateDistanceField(const typename DistancePixelConversion<typename ContourCombiner::DistanceType>::BitmapRefType &output, const Shape &shape, const SDFTransformation &transformation) {
|
||||
void generateDistanceField(typename DistancePixelConversion<typename ContourCombiner::DistanceType>::BitmapSectionType output, const Shape &shape, const SDFTransformation &transformation) {
|
||||
DistancePixelConversion<typename ContourCombiner::DistanceType> distancePixelConversion(transformation.distanceMapping);
|
||||
output.reorient(shape.getYAxisOrientation());
|
||||
#ifdef MSDFGEN_USE_OPENMP
|
||||
#pragma omp parallel
|
||||
#endif
|
||||
{
|
||||
ShapeDistanceFinder<ContourCombiner> distanceFinder(shape);
|
||||
bool rightToLeft = false;
|
||||
int xDirection = 1;
|
||||
#ifdef MSDFGEN_USE_OPENMP
|
||||
#pragma omp for
|
||||
#endif
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
int row = shape.inverseYAxis ? output.height-y-1 : y;
|
||||
int x = xDirection < 0 ? output.width-1 : 0;
|
||||
for (int col = 0; col < output.width; ++col) {
|
||||
int x = rightToLeft ? output.width-col-1 : col;
|
||||
Point2 p = transformation.unproject(Point2(x+.5, y+.5));
|
||||
typename ContourCombiner::DistanceType distance = distanceFinder.distance(p);
|
||||
distancePixelConversion(output(x, row), distance);
|
||||
distancePixelConversion(output(x, y), distance);
|
||||
x += xDirection;
|
||||
}
|
||||
rightToLeft = !rightToLeft;
|
||||
xDirection = -xDirection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, const SDFTransformation &transformation, const GeneratorConfig &config) {
|
||||
void generateSDF(const BitmapSection<float, 1> &output, const Shape &shape, const SDFTransformation &transformation, const GeneratorConfig &config) {
|
||||
if (config.overlapSupport)
|
||||
generateDistanceField<OverlappingContourCombiner<TrueDistanceSelector> >(output, shape, transformation);
|
||||
else
|
||||
generateDistanceField<SimpleContourCombiner<TrueDistanceSelector> >(output, shape, transformation);
|
||||
}
|
||||
|
||||
void generatePSDF(const BitmapRef<float, 1> &output, const Shape &shape, const SDFTransformation &transformation, const GeneratorConfig &config) {
|
||||
void generatePSDF(const BitmapSection<float, 1> &output, const Shape &shape, const SDFTransformation &transformation, const GeneratorConfig &config) {
|
||||
if (config.overlapSupport)
|
||||
generateDistanceField<OverlappingContourCombiner<PerpendicularDistanceSelector> >(output, shape, transformation);
|
||||
else
|
||||
generateDistanceField<SimpleContourCombiner<PerpendicularDistanceSelector> >(output, shape, transformation);
|
||||
}
|
||||
|
||||
void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config) {
|
||||
void generateMSDF(const BitmapSection<float, 3> &output, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config) {
|
||||
if (config.overlapSupport)
|
||||
generateDistanceField<OverlappingContourCombiner<MultiDistanceSelector> >(output, shape, transformation);
|
||||
else
|
||||
|
|
@ -96,7 +97,7 @@ void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, const S
|
|||
msdfErrorCorrection(output, shape, transformation, config);
|
||||
}
|
||||
|
||||
void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config) {
|
||||
void generateMTSDF(const BitmapSection<float, 4> &output, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config) {
|
||||
if (config.overlapSupport)
|
||||
generateDistanceField<OverlappingContourCombiner<MultiAndTrueDistanceSelector> >(output, shape, transformation);
|
||||
else
|
||||
|
|
@ -104,21 +105,21 @@ void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, const
|
|||
msdfErrorCorrection(output, shape, transformation, config);
|
||||
}
|
||||
|
||||
void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config) {
|
||||
void generateSDF(const BitmapSection<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) {
|
||||
void generatePSDF(const BitmapSection<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) {
|
||||
void generateMSDF(const BitmapSection<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
|
||||
|
|
@ -126,7 +127,7 @@ void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, const P
|
|||
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) {
|
||||
void generateMTSDF(const BitmapSection<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
|
||||
|
|
@ -136,39 +137,39 @@ void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, const
|
|||
|
||||
// Legacy API
|
||||
|
||||
void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config) {
|
||||
void generatePseudoSDF(const BitmapSection<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) {
|
||||
void generateSDF(const BitmapSection<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
|
||||
generateSDF(output, shape, Projection(scale, translate), range, GeneratorConfig(overlapSupport));
|
||||
}
|
||||
|
||||
void generatePSDF(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
|
||||
void generatePSDF(const BitmapSection<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
|
||||
generatePSDF(output, shape, Projection(scale, translate), range, GeneratorConfig(overlapSupport));
|
||||
}
|
||||
|
||||
void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
|
||||
void generatePseudoSDF(const BitmapSection<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) {
|
||||
void generateMSDF(const BitmapSection<float, 3> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig, bool overlapSupport) {
|
||||
generateMSDF(output, shape, Projection(scale, translate), range, MSDFGeneratorConfig(overlapSupport, errorCorrectionConfig));
|
||||
}
|
||||
|
||||
void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig, bool overlapSupport) {
|
||||
void generateMTSDF(const BitmapSection<float, 4> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig, bool overlapSupport) {
|
||||
generateMTSDF(output, shape, Projection(scale, translate), range, MSDFGeneratorConfig(overlapSupport, errorCorrectionConfig));
|
||||
}
|
||||
|
||||
// Legacy version
|
||||
|
||||
void generateSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate) {
|
||||
void generateSDF_legacy(BitmapSection<float, 1> output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate) {
|
||||
DistanceMapping distanceMapping(range);
|
||||
output.reorient(shape.getYAxisOrientation());
|
||||
#ifdef MSDFGEN_USE_OPENMP
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
int row = shape.inverseYAxis ? output.height-y-1 : y;
|
||||
for (int x = 0; x < output.width; ++x) {
|
||||
double dummy;
|
||||
Point2 p = Vector2(x+.5, y+.5)/scale-translate;
|
||||
|
|
@ -179,18 +180,18 @@ void generateSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, R
|
|||
if (distance < minDistance)
|
||||
minDistance = distance;
|
||||
}
|
||||
*output(x, row) = float(distanceMapping(minDistance.distance));
|
||||
*output(x, y) = float(distanceMapping(minDistance.distance));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void generatePSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate) {
|
||||
void generatePSDF_legacy(BitmapSection<float, 1> output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate) {
|
||||
DistanceMapping distanceMapping(range);
|
||||
output.reorient(shape.getYAxisOrientation());
|
||||
#ifdef MSDFGEN_USE_OPENMP
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
int row = shape.inverseYAxis ? output.height-y-1 : y;
|
||||
for (int x = 0; x < output.width; ++x) {
|
||||
Point2 p = Vector2(x+.5, y+.5)/scale-translate;
|
||||
SignedDistance minDistance;
|
||||
|
|
@ -208,22 +209,22 @@ void generatePSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape,
|
|||
}
|
||||
if (nearEdge)
|
||||
(*nearEdge)->distanceToPerpendicularDistance(minDistance, p, nearParam);
|
||||
*output(x, row) = float(distanceMapping(minDistance.distance));
|
||||
*output(x, y) = float(distanceMapping(minDistance.distance));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void generatePseudoSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate) {
|
||||
void generatePseudoSDF_legacy(BitmapSection<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) {
|
||||
void generateMSDF_legacy(BitmapSection<float, 3> output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig) {
|
||||
DistanceMapping distanceMapping(range);
|
||||
output.reorient(shape.getYAxisOrientation());
|
||||
#ifdef MSDFGEN_USE_OPENMP
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
int row = shape.inverseYAxis ? output.height-y-1 : y;
|
||||
for (int x = 0; x < output.width; ++x) {
|
||||
Point2 p = Vector2(x+.5, y+.5)/scale-translate;
|
||||
|
||||
|
|
@ -262,9 +263,9 @@ void generateMSDF_legacy(const BitmapRef<float, 3> &output, const Shape &shape,
|
|||
(*g.nearEdge)->distanceToPerpendicularDistance(g.minDistance, p, g.nearParam);
|
||||
if (b.nearEdge)
|
||||
(*b.nearEdge)->distanceToPerpendicularDistance(b.minDistance, p, b.nearParam);
|
||||
output(x, row)[0] = float(distanceMapping(r.minDistance.distance));
|
||||
output(x, row)[1] = float(distanceMapping(g.minDistance.distance));
|
||||
output(x, row)[2] = float(distanceMapping(b.minDistance.distance));
|
||||
output(x, y)[0] = float(distanceMapping(r.minDistance.distance));
|
||||
output(x, y)[1] = float(distanceMapping(g.minDistance.distance));
|
||||
output(x, y)[2] = float(distanceMapping(b.minDistance.distance));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -272,13 +273,13 @@ void generateMSDF_legacy(const BitmapRef<float, 3> &output, const Shape &shape,
|
|||
msdfErrorCorrection(output, shape, Projection(scale, translate), range, MSDFGeneratorConfig(false, errorCorrectionConfig));
|
||||
}
|
||||
|
||||
void generateMTSDF_legacy(const BitmapRef<float, 4> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig) {
|
||||
void generateMTSDF_legacy(BitmapSection<float, 4> output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig) {
|
||||
DistanceMapping distanceMapping(range);
|
||||
output.reorient(shape.getYAxisOrientation());
|
||||
#ifdef MSDFGEN_USE_OPENMP
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
int row = shape.inverseYAxis ? output.height-y-1 : y;
|
||||
for (int x = 0; x < output.width; ++x) {
|
||||
Point2 p = Vector2(x+.5, y+.5)/scale-translate;
|
||||
|
||||
|
|
@ -320,10 +321,10 @@ void generateMTSDF_legacy(const BitmapRef<float, 4> &output, const Shape &shape,
|
|||
(*g.nearEdge)->distanceToPerpendicularDistance(g.minDistance, p, g.nearParam);
|
||||
if (b.nearEdge)
|
||||
(*b.nearEdge)->distanceToPerpendicularDistance(b.minDistance, p, b.nearParam);
|
||||
output(x, row)[0] = float(distanceMapping(r.minDistance.distance));
|
||||
output(x, row)[1] = float(distanceMapping(g.minDistance.distance));
|
||||
output(x, row)[2] = float(distanceMapping(b.minDistance.distance));
|
||||
output(x, row)[3] = float(distanceMapping(minDistance.distance));
|
||||
output(x, y)[0] = float(distanceMapping(r.minDistance.distance));
|
||||
output(x, y)[1] = float(distanceMapping(g.minDistance.distance));
|
||||
output(x, y)[2] = float(distanceMapping(b.minDistance.distance));
|
||||
output(x, y)[3] = float(distanceMapping(minDistance.distance));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,58 +6,60 @@
|
|||
|
||||
namespace msdfgen {
|
||||
|
||||
void rasterize(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, FillRule fillRule) {
|
||||
void rasterize(BitmapSection<float, 1> output, const Shape &shape, const Projection &projection, FillRule fillRule) {
|
||||
output.reorient(shape.getYAxisOrientation());
|
||||
Scanline scanline;
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
int row = shape.inverseYAxis ? output.height-y-1 : y;
|
||||
shape.scanline(scanline, projection.unprojectY(y+.5));
|
||||
for (int x = 0; x < output.width; ++x)
|
||||
*output(x, row) = (float) scanline.filled(projection.unprojectX(x+.5), fillRule);
|
||||
*output(x, y) = (float) scanline.filled(projection.unprojectX(x+.5), fillRule);
|
||||
}
|
||||
}
|
||||
|
||||
void distanceSignCorrection(const BitmapRef<float, 1> &sdf, const Shape &shape, const Projection &projection, FillRule fillRule) {
|
||||
void distanceSignCorrection(BitmapSection<float, 1> sdf, const Shape &shape, const Projection &projection, float sdfZeroValue, FillRule fillRule) {
|
||||
sdf.reorient(shape.getYAxisOrientation());
|
||||
float doubleSdfZeroValue = sdfZeroValue+sdfZeroValue;
|
||||
Scanline scanline;
|
||||
for (int y = 0; y < sdf.height; ++y) {
|
||||
int row = shape.inverseYAxis ? sdf.height-y-1 : y;
|
||||
shape.scanline(scanline, projection.unprojectY(y+.5));
|
||||
for (int x = 0; x < sdf.width; ++x) {
|
||||
bool fill = scanline.filled(projection.unprojectX(x+.5), fillRule);
|
||||
float &sd = *sdf(x, row);
|
||||
if ((sd > .5f) != fill)
|
||||
sd = 1.f-sd;
|
||||
float &sd = *sdf(x, y);
|
||||
if ((sd > sdfZeroValue) != fill)
|
||||
sd = doubleSdfZeroValue-sd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <int N>
|
||||
static void multiDistanceSignCorrection(const BitmapRef<float, N> &sdf, const Shape &shape, const Projection &projection, FillRule fillRule) {
|
||||
static void multiDistanceSignCorrection(BitmapSection<float, N> sdf, const Shape &shape, const Projection &projection, float sdfZeroValue, FillRule fillRule) {
|
||||
int w = sdf.width, h = sdf.height;
|
||||
if (!(w && h))
|
||||
return;
|
||||
sdf.reorient(shape.getYAxisOrientation());
|
||||
float doubleSdfZeroValue = sdfZeroValue+sdfZeroValue;
|
||||
Scanline scanline;
|
||||
bool ambiguous = false;
|
||||
std::vector<char> matchMap;
|
||||
matchMap.resize(w*h);
|
||||
char *match = &matchMap[0];
|
||||
for (int y = 0; y < h; ++y) {
|
||||
int row = shape.inverseYAxis ? h-y-1 : y;
|
||||
shape.scanline(scanline, projection.unprojectY(y+.5));
|
||||
for (int x = 0; x < w; ++x) {
|
||||
bool fill = scanline.filled(projection.unprojectX(x+.5), fillRule);
|
||||
float *msd = sdf(x, row);
|
||||
float *msd = sdf(x, y);
|
||||
float sd = median(msd[0], msd[1], msd[2]);
|
||||
if (sd == .5f)
|
||||
if (sd == sdfZeroValue)
|
||||
ambiguous = true;
|
||||
else if ((sd > .5f) != fill) {
|
||||
msd[0] = 1.f-msd[0];
|
||||
msd[1] = 1.f-msd[1];
|
||||
msd[2] = 1.f-msd[2];
|
||||
else if ((sd > sdfZeroValue) != fill) {
|
||||
msd[0] = doubleSdfZeroValue-msd[0];
|
||||
msd[1] = doubleSdfZeroValue-msd[1];
|
||||
msd[2] = doubleSdfZeroValue-msd[2];
|
||||
*match = -1;
|
||||
} else
|
||||
*match = 1;
|
||||
if (N >= 4 && (msd[3] > .5f) != fill)
|
||||
msd[3] = 1.f-msd[3];
|
||||
if (N >= 4 && (msd[3] > sdfZeroValue) != fill)
|
||||
msd[3] = doubleSdfZeroValue-msd[3];
|
||||
++match;
|
||||
}
|
||||
}
|
||||
|
|
@ -65,7 +67,6 @@ static void multiDistanceSignCorrection(const BitmapRef<float, N> &sdf, const Sh
|
|||
if (ambiguous) {
|
||||
match = &matchMap[0];
|
||||
for (int y = 0; y < h; ++y) {
|
||||
int row = shape.inverseYAxis ? h-y-1 : y;
|
||||
for (int x = 0; x < w; ++x) {
|
||||
if (!*match) {
|
||||
int neighborMatch = 0;
|
||||
|
|
@ -74,10 +75,10 @@ static void multiDistanceSignCorrection(const BitmapRef<float, N> &sdf, const Sh
|
|||
if (y > 0) neighborMatch += *(match-w);
|
||||
if (y < h-1) neighborMatch += *(match+w);
|
||||
if (neighborMatch < 0) {
|
||||
float *msd = sdf(x, row);
|
||||
msd[0] = 1.f-msd[0];
|
||||
msd[1] = 1.f-msd[1];
|
||||
msd[2] = 1.f-msd[2];
|
||||
float *msd = sdf(x, y);
|
||||
msd[0] = doubleSdfZeroValue-msd[0];
|
||||
msd[1] = doubleSdfZeroValue-msd[1];
|
||||
msd[2] = doubleSdfZeroValue-msd[2];
|
||||
}
|
||||
}
|
||||
++match;
|
||||
|
|
@ -86,29 +87,41 @@ static void multiDistanceSignCorrection(const BitmapRef<float, N> &sdf, const Sh
|
|||
}
|
||||
}
|
||||
|
||||
void distanceSignCorrection(const BitmapRef<float, 3> &sdf, const Shape &shape, const Projection &projection, FillRule fillRule) {
|
||||
multiDistanceSignCorrection(sdf, shape, projection, fillRule);
|
||||
void distanceSignCorrection(BitmapSection<float, 3> sdf, const Shape &shape, const Projection &projection, float sdfZeroValue, FillRule fillRule) {
|
||||
multiDistanceSignCorrection(sdf, shape, projection, sdfZeroValue, fillRule);
|
||||
}
|
||||
|
||||
void distanceSignCorrection(const BitmapRef<float, 4> &sdf, const Shape &shape, const Projection &projection, FillRule fillRule) {
|
||||
multiDistanceSignCorrection(sdf, shape, projection, fillRule);
|
||||
void distanceSignCorrection(BitmapSection<float, 4> sdf, const Shape &shape, const Projection &projection, float sdfZeroValue, FillRule fillRule) {
|
||||
multiDistanceSignCorrection(sdf, shape, projection, sdfZeroValue, fillRule);
|
||||
}
|
||||
|
||||
// Legacy API
|
||||
|
||||
void rasterize(const BitmapRef<float, 1> &output, const Shape &shape, const Vector2 &scale, const Vector2 &translate, FillRule fillRule) {
|
||||
void rasterize(const BitmapSection<float, 1> &output, const Shape &shape, const Vector2 &scale, const Vector2 &translate, FillRule fillRule) {
|
||||
rasterize(output, shape, Projection(scale, translate), fillRule);
|
||||
}
|
||||
|
||||
void distanceSignCorrection(const BitmapRef<float, 1> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, FillRule fillRule) {
|
||||
void distanceSignCorrection(BitmapSection<float, 1> sdf, const Shape &shape, const Projection &projection, FillRule fillRule) {
|
||||
distanceSignCorrection(sdf, shape, projection, .5f, fillRule);
|
||||
}
|
||||
|
||||
void distanceSignCorrection(BitmapSection<float, 3> sdf, const Shape &shape, const Projection &projection, FillRule fillRule) {
|
||||
distanceSignCorrection(sdf, shape, projection, .5f, fillRule);
|
||||
}
|
||||
|
||||
void distanceSignCorrection(BitmapSection<float, 4> sdf, const Shape &shape, const Projection &projection, FillRule fillRule) {
|
||||
distanceSignCorrection(sdf, shape, projection, .5f, fillRule);
|
||||
}
|
||||
|
||||
void distanceSignCorrection(const BitmapSection<float, 1> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, FillRule fillRule) {
|
||||
distanceSignCorrection(sdf, shape, Projection(scale, translate), fillRule);
|
||||
}
|
||||
|
||||
void distanceSignCorrection(const BitmapRef<float, 3> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, FillRule fillRule) {
|
||||
void distanceSignCorrection(const BitmapSection<float, 3> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, FillRule fillRule) {
|
||||
distanceSignCorrection(sdf, shape, Projection(scale, translate), fillRule);
|
||||
}
|
||||
|
||||
void distanceSignCorrection(const BitmapRef<float, 4> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, FillRule fillRule) {
|
||||
void distanceSignCorrection(const BitmapSection<float, 4> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, FillRule fillRule) {
|
||||
distanceSignCorrection(sdf, shape, Projection(scale, translate), fillRule);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,16 +10,19 @@
|
|||
namespace msdfgen {
|
||||
|
||||
/// Rasterizes the shape into a monochrome bitmap.
|
||||
void rasterize(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, FillRule fillRule = FILL_NONZERO);
|
||||
void rasterize(BitmapSection<float, 1> output, const Shape &shape, const Projection &projection, FillRule fillRule = FILL_NONZERO);
|
||||
/// Fixes the sign of the input signed distance field, so that it matches the shape's rasterized fill.
|
||||
void distanceSignCorrection(const BitmapRef<float, 1> &sdf, const Shape &shape, const Projection &projection, FillRule fillRule = FILL_NONZERO);
|
||||
void distanceSignCorrection(const BitmapRef<float, 3> &sdf, const Shape &shape, const Projection &projection, FillRule fillRule = FILL_NONZERO);
|
||||
void distanceSignCorrection(const BitmapRef<float, 4> &sdf, const Shape &shape, const Projection &projection, FillRule fillRule = FILL_NONZERO);
|
||||
void distanceSignCorrection(BitmapSection<float, 1> sdf, const Shape &shape, const Projection &projection, float sdfZeroValue = .5f, FillRule fillRule = FILL_NONZERO);
|
||||
void distanceSignCorrection(BitmapSection<float, 3> sdf, const Shape &shape, const Projection &projection, float sdfZeroValue = .5f, FillRule fillRule = FILL_NONZERO);
|
||||
void distanceSignCorrection(BitmapSection<float, 4> sdf, const Shape &shape, const Projection &projection, float sdfZeroValue = .5f, FillRule fillRule = FILL_NONZERO);
|
||||
|
||||
// Old version of the function API's kept for backwards compatibility
|
||||
void rasterize(const BitmapRef<float, 1> &output, const Shape &shape, const Vector2 &scale, const Vector2 &translate, FillRule fillRule = FILL_NONZERO);
|
||||
void distanceSignCorrection(const BitmapRef<float, 1> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, FillRule fillRule = FILL_NONZERO);
|
||||
void distanceSignCorrection(const BitmapRef<float, 3> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, FillRule fillRule = FILL_NONZERO);
|
||||
void distanceSignCorrection(const BitmapRef<float, 4> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, FillRule fillRule = FILL_NONZERO);
|
||||
// Old versions of the function API's kept for backwards compatibility
|
||||
void rasterize(const BitmapSection<float, 1> &output, const Shape &shape, const Vector2 &scale, const Vector2 &translate, FillRule fillRule = FILL_NONZERO);
|
||||
void distanceSignCorrection(BitmapSection<float, 1> sdf, const Shape &shape, const Projection &projection, FillRule fillRule);
|
||||
void distanceSignCorrection(BitmapSection<float, 3> sdf, const Shape &shape, const Projection &projection, FillRule fillRule);
|
||||
void distanceSignCorrection(BitmapSection<float, 4> sdf, const Shape &shape, const Projection &projection, FillRule fillRule);
|
||||
void distanceSignCorrection(const BitmapSection<float, 1> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, FillRule fillRule = FILL_NONZERO);
|
||||
void distanceSignCorrection(const BitmapSection<float, 3> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, FillRule fillRule = FILL_NONZERO);
|
||||
void distanceSignCorrection(const BitmapSection<float, 4> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, FillRule fillRule = FILL_NONZERO);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ static float distVal(float dist, DistanceMapping mapping) {
|
|||
return (float) clamp(mapping(dist)+.5);
|
||||
}
|
||||
|
||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 1> &sdf, Range sdfPxRange, float sdThreshold) {
|
||||
void renderSDF(const BitmapSection<float, 1> &output, const BitmapConstSection<float, 1> &sdf, Range sdfPxRange, float sdThreshold) {
|
||||
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||
if (sdfPxRange.lower == sdfPxRange.upper) {
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
|
|
@ -37,7 +37,7 @@ void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 1>
|
|||
|
||||
}
|
||||
|
||||
void renderSDF(const BitmapRef<float, 3> &output, const BitmapConstRef<float, 1> &sdf, Range sdfPxRange, float sdThreshold) {
|
||||
void renderSDF(const BitmapSection<float, 3> &output, const BitmapConstSection<float, 1> &sdf, Range sdfPxRange, float sdThreshold) {
|
||||
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||
if (sdfPxRange.lower == sdfPxRange.upper) {
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
|
|
@ -67,7 +67,7 @@ void renderSDF(const BitmapRef<float, 3> &output, const BitmapConstRef<float, 1>
|
|||
}
|
||||
}
|
||||
|
||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 3> &sdf, Range sdfPxRange, float sdThreshold) {
|
||||
void renderSDF(const BitmapSection<float, 1> &output, const BitmapConstSection<float, 3> &sdf, Range sdfPxRange, float sdThreshold) {
|
||||
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||
if (sdfPxRange.lower == sdfPxRange.upper) {
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
|
|
@ -91,7 +91,7 @@ void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 3>
|
|||
}
|
||||
}
|
||||
|
||||
void renderSDF(const BitmapRef<float, 3> &output, const BitmapConstRef<float, 3> &sdf, Range sdfPxRange, float sdThreshold) {
|
||||
void renderSDF(const BitmapSection<float, 3> &output, const BitmapConstSection<float, 3> &sdf, Range sdfPxRange, float sdThreshold) {
|
||||
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||
if (sdfPxRange.lower == sdfPxRange.upper) {
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
|
|
@ -119,7 +119,7 @@ void renderSDF(const BitmapRef<float, 3> &output, const BitmapConstRef<float, 3>
|
|||
}
|
||||
}
|
||||
|
||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 4> &sdf, Range sdfPxRange, float sdThreshold) {
|
||||
void renderSDF(const BitmapSection<float, 1> &output, const BitmapConstSection<float, 4> &sdf, Range sdfPxRange, float sdThreshold) {
|
||||
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||
if (sdfPxRange.lower == sdfPxRange.upper) {
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
|
|
@ -143,7 +143,7 @@ void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 4>
|
|||
}
|
||||
}
|
||||
|
||||
void renderSDF(const BitmapRef<float, 4> &output, const BitmapConstRef<float, 4> &sdf, Range sdfPxRange, float sdThreshold) {
|
||||
void renderSDF(const BitmapSection<float, 4> &output, const BitmapConstSection<float, 4> &sdf, Range sdfPxRange, float sdThreshold) {
|
||||
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||
if (sdfPxRange.lower == sdfPxRange.upper) {
|
||||
for (int y = 0; y < output.height; ++y) {
|
||||
|
|
@ -173,19 +173,19 @@ void renderSDF(const BitmapRef<float, 4> &output, const BitmapConstRef<float, 4>
|
|||
}
|
||||
}
|
||||
|
||||
void simulate8bit(const BitmapRef<float, 1> &bitmap) {
|
||||
void simulate8bit(const BitmapSection<float, 1> &bitmap) {
|
||||
const float *end = bitmap.pixels+1*bitmap.width*bitmap.height;
|
||||
for (float *p = bitmap.pixels; p < end; ++p)
|
||||
*p = pixelByteToFloat(pixelFloatToByte(*p));
|
||||
}
|
||||
|
||||
void simulate8bit(const BitmapRef<float, 3> &bitmap) {
|
||||
void simulate8bit(const BitmapSection<float, 3> &bitmap) {
|
||||
const float *end = bitmap.pixels+3*bitmap.width*bitmap.height;
|
||||
for (float *p = bitmap.pixels; p < end; ++p)
|
||||
*p = pixelByteToFloat(pixelFloatToByte(*p));
|
||||
}
|
||||
|
||||
void simulate8bit(const BitmapRef<float, 4> &bitmap) {
|
||||
void simulate8bit(const BitmapSection<float, 4> &bitmap) {
|
||||
const float *end = bitmap.pixels+4*bitmap.width*bitmap.height;
|
||||
for (float *p = bitmap.pixels; p < end; ++p)
|
||||
*p = pixelByteToFloat(pixelFloatToByte(*p));
|
||||
|
|
|
|||
|
|
@ -8,16 +8,16 @@
|
|||
namespace msdfgen {
|
||||
|
||||
/// Reconstructs the shape's appearance into output from the distance field sdf.
|
||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 1> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
void renderSDF(const BitmapRef<float, 3> &output, const BitmapConstRef<float, 1> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 3> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
void renderSDF(const BitmapRef<float, 3> &output, const BitmapConstRef<float, 3> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 4> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
void renderSDF(const BitmapRef<float, 4> &output, const BitmapConstRef<float, 4> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
void renderSDF(const BitmapSection<float, 1> &output, const BitmapConstSection<float, 1> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
void renderSDF(const BitmapSection<float, 3> &output, const BitmapConstSection<float, 1> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
void renderSDF(const BitmapSection<float, 1> &output, const BitmapConstSection<float, 3> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
void renderSDF(const BitmapSection<float, 3> &output, const BitmapConstSection<float, 3> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
void renderSDF(const BitmapSection<float, 1> &output, const BitmapConstSection<float, 4> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
void renderSDF(const BitmapSection<float, 4> &output, const BitmapConstSection<float, 4> &sdf, Range sdfPxRange = 0, float sdThreshold = .5f);
|
||||
|
||||
/// Snaps the values of the floating-point bitmaps into one of the 256 values representable in a standard 8-bit bitmap.
|
||||
void simulate8bit(const BitmapRef<float, 1> &bitmap);
|
||||
void simulate8bit(const BitmapRef<float, 3> &bitmap);
|
||||
void simulate8bit(const BitmapRef<float, 4> &bitmap);
|
||||
void simulate8bit(const BitmapSection<float, 1> &bitmap);
|
||||
void simulate8bit(const BitmapSection<float, 3> &bitmap);
|
||||
void simulate8bit(const BitmapSection<float, 4> &bitmap);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,173 +0,0 @@
|
|||
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "save-bmp.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef MSDFGEN_USE_CPP11
|
||||
#include <cstdint>
|
||||
#else
|
||||
namespace msdfgen {
|
||||
typedef int int32_t;
|
||||
typedef unsigned uint32_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned char uint8_t;
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "pixel-conversion.hpp"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
template <typename T>
|
||||
static bool writeValue(FILE *file, T value) {
|
||||
#ifdef __BIG_ENDIAN__
|
||||
T reverse = 0;
|
||||
for (int i = 0; i < sizeof(T); ++i) {
|
||||
reverse <<= 8;
|
||||
reverse |= value&T(0xff);
|
||||
value >>= 8;
|
||||
}
|
||||
return fwrite(&reverse, sizeof(T), 1, file) == 1;
|
||||
#else
|
||||
return fwrite(&value, sizeof(T), 1, file) == 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool writeBmpHeader(FILE *file, int width, int height, int &paddedWidth) {
|
||||
paddedWidth = (3*width+3)&~3;
|
||||
const uint32_t bitmapStart = 54;
|
||||
const uint32_t bitmapSize = paddedWidth*height;
|
||||
const uint32_t fileSize = bitmapStart+bitmapSize;
|
||||
|
||||
writeValue<uint16_t>(file, 0x4d42u);
|
||||
writeValue<uint32_t>(file, fileSize);
|
||||
writeValue<uint16_t>(file, 0);
|
||||
writeValue<uint16_t>(file, 0);
|
||||
writeValue<uint32_t>(file, bitmapStart);
|
||||
|
||||
writeValue<uint32_t>(file, 40);
|
||||
writeValue<int32_t>(file, width);
|
||||
writeValue<int32_t>(file, height);
|
||||
writeValue<uint16_t>(file, 1);
|
||||
writeValue<uint16_t>(file, 24);
|
||||
writeValue<uint32_t>(file, 0);
|
||||
writeValue<uint32_t>(file, bitmapSize);
|
||||
writeValue<uint32_t>(file, 2835);
|
||||
writeValue<uint32_t>(file, 2835);
|
||||
writeValue<uint32_t>(file, 0);
|
||||
writeValue<uint32_t>(file, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool saveBmp(const BitmapConstRef<byte, 1> &bitmap, const char *filename) {
|
||||
FILE *file = fopen(filename, "wb");
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
int paddedWidth;
|
||||
writeBmpHeader(file, bitmap.width, bitmap.height, paddedWidth);
|
||||
|
||||
const uint8_t padding[4] = { };
|
||||
int padLength = paddedWidth-3*bitmap.width;
|
||||
for (int y = 0; y < bitmap.height; ++y) {
|
||||
for (int x = 0; x < bitmap.width; ++x) {
|
||||
uint8_t px = (uint8_t) *bitmap(x, y);
|
||||
fwrite(&px, sizeof(uint8_t), 1, file);
|
||||
fwrite(&px, sizeof(uint8_t), 1, file);
|
||||
fwrite(&px, sizeof(uint8_t), 1, file);
|
||||
}
|
||||
fwrite(padding, 1, padLength, file);
|
||||
}
|
||||
|
||||
return !fclose(file);
|
||||
}
|
||||
|
||||
bool saveBmp(const BitmapConstRef<byte, 3> &bitmap, const char *filename) {
|
||||
FILE *file = fopen(filename, "wb");
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
int paddedWidth;
|
||||
writeBmpHeader(file, bitmap.width, bitmap.height, paddedWidth);
|
||||
|
||||
const uint8_t padding[4] = { };
|
||||
int padLength = paddedWidth-3*bitmap.width;
|
||||
for (int y = 0; y < bitmap.height; ++y) {
|
||||
for (int x = 0; x < bitmap.width; ++x) {
|
||||
uint8_t bgr[3] = {
|
||||
(uint8_t) bitmap(x, y)[2],
|
||||
(uint8_t) bitmap(x, y)[1],
|
||||
(uint8_t) bitmap(x, y)[0]
|
||||
};
|
||||
fwrite(bgr, sizeof(uint8_t), 3, file);
|
||||
}
|
||||
fwrite(padding, 1, padLength, file);
|
||||
}
|
||||
|
||||
return !fclose(file);
|
||||
}
|
||||
|
||||
bool saveBmp(const BitmapConstRef<byte, 4> &bitmap, const char *filename) {
|
||||
// RGBA not supported by the BMP format
|
||||
return false;
|
||||
}
|
||||
|
||||
bool saveBmp(const BitmapConstRef<float, 1> &bitmap, const char *filename) {
|
||||
FILE *file = fopen(filename, "wb");
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
int paddedWidth;
|
||||
writeBmpHeader(file, bitmap.width, bitmap.height, paddedWidth);
|
||||
|
||||
const uint8_t padding[4] = { };
|
||||
int padLength = paddedWidth-3*bitmap.width;
|
||||
for (int y = 0; y < bitmap.height; ++y) {
|
||||
for (int x = 0; x < bitmap.width; ++x) {
|
||||
uint8_t px = (uint8_t) pixelFloatToByte(*bitmap(x, y));
|
||||
fwrite(&px, sizeof(uint8_t), 1, file);
|
||||
fwrite(&px, sizeof(uint8_t), 1, file);
|
||||
fwrite(&px, sizeof(uint8_t), 1, file);
|
||||
}
|
||||
fwrite(padding, 1, padLength, file);
|
||||
}
|
||||
|
||||
return !fclose(file);
|
||||
}
|
||||
|
||||
bool saveBmp(const BitmapConstRef<float, 3> &bitmap, const char *filename) {
|
||||
FILE *file = fopen(filename, "wb");
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
int paddedWidth;
|
||||
writeBmpHeader(file, bitmap.width, bitmap.height, paddedWidth);
|
||||
|
||||
const uint8_t padding[4] = { };
|
||||
int padLength = paddedWidth-3*bitmap.width;
|
||||
for (int y = 0; y < bitmap.height; ++y) {
|
||||
for (int x = 0; x < bitmap.width; ++x) {
|
||||
uint8_t bgr[3] = {
|
||||
(uint8_t) pixelFloatToByte(bitmap(x, y)[2]),
|
||||
(uint8_t) pixelFloatToByte(bitmap(x, y)[1]),
|
||||
(uint8_t) pixelFloatToByte(bitmap(x, y)[0])
|
||||
};
|
||||
fwrite(bgr, sizeof(uint8_t), 3, file);
|
||||
}
|
||||
fwrite(padding, 1, padLength, file);
|
||||
}
|
||||
|
||||
return !fclose(file);
|
||||
}
|
||||
|
||||
bool saveBmp(const BitmapConstRef<float, 4> &bitmap, const char *filename) {
|
||||
// RGBA not supported by the BMP format
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BitmapRef.hpp"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Saves the bitmap as a BMP file.
|
||||
bool saveBmp(const BitmapConstRef<byte, 1> &bitmap, const char *filename);
|
||||
bool saveBmp(const BitmapConstRef<byte, 3> &bitmap, const char *filename);
|
||||
bool saveBmp(const BitmapConstRef<byte, 4> &bitmap, const char *filename);
|
||||
bool saveBmp(const BitmapConstRef<float, 1> &bitmap, const char *filename);
|
||||
bool saveBmp(const BitmapConstRef<float, 3> &bitmap, const char *filename);
|
||||
bool saveBmp(const BitmapConstRef<float, 4> &bitmap, const char *filename);
|
||||
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
|
||||
#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
|
||||
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
|
||||
#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);
|
||||
|
||||
}
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
|
||||
#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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
|
||||
#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);
|
||||
|
||||
}
|
||||
|
|
@ -1,194 +0,0 @@
|
|||
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include "save-tiff.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef MSDFGEN_USE_CPP11
|
||||
#include <cstdint>
|
||||
#else
|
||||
namespace msdfgen {
|
||||
typedef int int32_t;
|
||||
typedef unsigned uint32_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned char uint8_t;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
template <typename T>
|
||||
static bool writeValue(FILE *file, T value) {
|
||||
return fwrite(&value, sizeof(T), 1, file) == 1;
|
||||
}
|
||||
template <typename T>
|
||||
static void writeValueRepeated(FILE *file, T value, int times) {
|
||||
for (int i = 0; i < times; ++i)
|
||||
writeValue(file, value);
|
||||
}
|
||||
|
||||
static bool writeTiffHeader(FILE *file, int width, int height, int channels) {
|
||||
#ifdef __BIG_ENDIAN__
|
||||
writeValue<uint16_t>(file, 0x4d4du);
|
||||
#else
|
||||
writeValue<uint16_t>(file, 0x4949u);
|
||||
#endif
|
||||
writeValue<uint16_t>(file, 42);
|
||||
writeValue<uint32_t>(file, 0x0008u); // Offset of first IFD
|
||||
// Offset = 0x0008
|
||||
|
||||
writeValue<uint16_t>(file, 15); // Number of IFD entries
|
||||
|
||||
// ImageWidth
|
||||
writeValue<uint16_t>(file, 0x0100u);
|
||||
writeValue<uint16_t>(file, 0x0004u);
|
||||
writeValue<uint32_t>(file, 1);
|
||||
writeValue<int32_t>(file, width);
|
||||
// ImageLength
|
||||
writeValue<uint16_t>(file, 0x0101u);
|
||||
writeValue<uint16_t>(file, 0x0004u);
|
||||
writeValue<uint32_t>(file, 1);
|
||||
writeValue<int32_t>(file, height);
|
||||
// BitsPerSample
|
||||
writeValue<uint16_t>(file, 0x0102u);
|
||||
writeValue<uint16_t>(file, 0x0003u);
|
||||
writeValue<uint32_t>(file, channels);
|
||||
if (channels > 1)
|
||||
writeValue<uint32_t>(file, 0x00c2u); // Offset of 32, 32, ...
|
||||
else {
|
||||
writeValue<uint16_t>(file, 32);
|
||||
writeValue<uint16_t>(file, 0);
|
||||
}
|
||||
// Compression
|
||||
writeValue<uint16_t>(file, 0x0103u);
|
||||
writeValue<uint16_t>(file, 0x0003u);
|
||||
writeValue<uint32_t>(file, 1);
|
||||
writeValue<uint16_t>(file, 1);
|
||||
writeValue<uint16_t>(file, 0);
|
||||
// PhotometricInterpretation
|
||||
writeValue<uint16_t>(file, 0x0106u);
|
||||
writeValue<uint16_t>(file, 0x0003u);
|
||||
writeValue<uint32_t>(file, 1);
|
||||
writeValue<uint16_t>(file, channels >= 3 ? 2 : 1);
|
||||
writeValue<uint16_t>(file, 0);
|
||||
// StripOffsets
|
||||
writeValue<uint16_t>(file, 0x0111u);
|
||||
writeValue<uint16_t>(file, 0x0004u);
|
||||
writeValue<uint32_t>(file, 1);
|
||||
writeValue<uint32_t>(file, 0x00d2u+(channels > 1)*channels*12); // Offset of pixel data
|
||||
// SamplesPerPixel
|
||||
writeValue<uint16_t>(file, 0x0115u);
|
||||
writeValue<uint16_t>(file, 0x0003u);
|
||||
writeValue<uint32_t>(file, 1);
|
||||
writeValue<uint16_t>(file, channels);
|
||||
writeValue<uint16_t>(file, 0);
|
||||
// RowsPerStrip
|
||||
writeValue<uint16_t>(file, 0x0116u);
|
||||
writeValue<uint16_t>(file, 0x0004u);
|
||||
writeValue<uint32_t>(file, 1);
|
||||
writeValue<int32_t>(file, height);
|
||||
// StripByteCounts
|
||||
writeValue<uint16_t>(file, 0x0117u);
|
||||
writeValue<uint16_t>(file, 0x0004u);
|
||||
writeValue<uint32_t>(file, 1);
|
||||
writeValue<int32_t>(file, sizeof(float)*channels*width*height);
|
||||
// XResolution
|
||||
writeValue<uint16_t>(file, 0x011au);
|
||||
writeValue<uint16_t>(file, 0x0005u);
|
||||
writeValue<uint32_t>(file, 1);
|
||||
writeValue<uint32_t>(file, 0x00c2u+(channels > 1)*channels*2); // Offset of 300, 1
|
||||
// YResolution
|
||||
writeValue<uint16_t>(file, 0x011bu);
|
||||
writeValue<uint16_t>(file, 0x0005u);
|
||||
writeValue<uint32_t>(file, 1);
|
||||
writeValue<uint32_t>(file, 0x00cau+(channels > 1)*channels*2); // Offset of 300, 1
|
||||
// ResolutionUnit
|
||||
writeValue<uint16_t>(file, 0x0128u);
|
||||
writeValue<uint16_t>(file, 0x0003u);
|
||||
writeValue<uint32_t>(file, 1);
|
||||
writeValue<uint16_t>(file, 2);
|
||||
writeValue<uint16_t>(file, 0);
|
||||
// SampleFormat
|
||||
writeValue<uint16_t>(file, 0x0153u);
|
||||
writeValue<uint16_t>(file, 0x0003u);
|
||||
writeValue<uint32_t>(file, channels);
|
||||
if (channels > 1)
|
||||
writeValue<uint32_t>(file, 0x00d2u+channels*2); // Offset of 3, 3, ...
|
||||
else {
|
||||
writeValue<uint16_t>(file, 3);
|
||||
writeValue<uint16_t>(file, 0);
|
||||
}
|
||||
// SMinSampleValue
|
||||
writeValue<uint16_t>(file, 0x0154u);
|
||||
writeValue<uint16_t>(file, 0x000bu);
|
||||
writeValue<uint32_t>(file, channels);
|
||||
if (channels > 1)
|
||||
writeValue<uint32_t>(file, 0x00d2u+channels*4); // Offset of 0.f, 0.f, ...
|
||||
else
|
||||
writeValue<float>(file, 0.f);
|
||||
// SMaxSampleValue
|
||||
writeValue<uint16_t>(file, 0x0155u);
|
||||
writeValue<uint16_t>(file, 0x000bu);
|
||||
writeValue<uint32_t>(file, channels);
|
||||
if (channels > 1)
|
||||
writeValue<uint32_t>(file, 0x00d2u+channels*8); // Offset of 1.f, 1.f, ...
|
||||
else
|
||||
writeValue<float>(file, 1.f);
|
||||
// Offset = 0x00be
|
||||
|
||||
writeValue<uint32_t>(file, 0);
|
||||
|
||||
if (channels > 1) {
|
||||
// 0x00c2 BitsPerSample data
|
||||
writeValueRepeated<uint16_t>(file, 32, channels);
|
||||
// 0x00c2 + 2*N XResolution data
|
||||
writeValue<uint32_t>(file, 300);
|
||||
writeValue<uint32_t>(file, 1);
|
||||
// 0x00ca + 2*N YResolution data
|
||||
writeValue<uint32_t>(file, 300);
|
||||
writeValue<uint32_t>(file, 1);
|
||||
// 0x00d2 + 2*N SampleFormat data
|
||||
writeValueRepeated<uint16_t>(file, 3, channels);
|
||||
// 0x00d2 + 4*N SMinSampleValue data
|
||||
writeValueRepeated<float>(file, 0.f, channels);
|
||||
// 0x00d2 + 8*N SMaxSampleValue data
|
||||
writeValueRepeated<float>(file, 1.f, channels);
|
||||
// Offset = 0x00d2 + 12*N
|
||||
} else {
|
||||
// 0x00c2 XResolution data
|
||||
writeValue<uint32_t>(file, 300);
|
||||
writeValue<uint32_t>(file, 1);
|
||||
// 0x00ca YResolution data
|
||||
writeValue<uint32_t>(file, 300);
|
||||
writeValue<uint32_t>(file, 1);
|
||||
// Offset = 0x00d2
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <int N>
|
||||
bool saveTiffFloat(const BitmapConstRef<float, N> &bitmap, const char *filename) {
|
||||
FILE *file = fopen(filename, "wb");
|
||||
if (!file)
|
||||
return false;
|
||||
writeTiffHeader(file, bitmap.width, bitmap.height, N);
|
||||
for (int y = bitmap.height-1; y >= 0; --y)
|
||||
fwrite(bitmap(0, y), sizeof(float), N*bitmap.width, file);
|
||||
return !fclose(file);
|
||||
}
|
||||
|
||||
bool saveTiff(const BitmapConstRef<float, 1> &bitmap, const char *filename) {
|
||||
return saveTiffFloat(bitmap, filename);
|
||||
}
|
||||
bool saveTiff(const BitmapConstRef<float, 3> &bitmap, const char *filename) {
|
||||
return saveTiffFloat(bitmap, filename);
|
||||
}
|
||||
bool saveTiff(const BitmapConstRef<float, 4> &bitmap, const char *filename) {
|
||||
return saveTiffFloat(bitmap, filename);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BitmapRef.hpp"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Saves the bitmap as an uncompressed floating-point TIFF file.
|
||||
bool saveTiff(const BitmapConstRef<float, 1> &bitmap, const char *filename);
|
||||
bool saveTiff(const BitmapConstRef<float, 3> &bitmap, const char *filename);
|
||||
bool saveTiff(const BitmapConstRef<float, 4> &bitmap, const char *filename);
|
||||
|
||||
}
|
||||
|
|
@ -6,11 +6,11 @@
|
|||
|
||||
namespace msdfgen {
|
||||
|
||||
void scanlineSDF(Scanline &line, const BitmapConstRef<float, 1> &sdf, const Projection &projection, double y, bool inverseYAxis) {
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 1> &sdf, const Projection &projection, double y, YAxisOrientation yAxisOrientation) {
|
||||
if (!(sdf.width > 0 && sdf.height > 0))
|
||||
return line.setIntersections(std::vector<Scanline::Intersection>());
|
||||
double pixelY = clamp(projection.projectY(y)-.5, double(sdf.height-1));
|
||||
if (inverseYAxis)
|
||||
if (yAxisOrientation == Y_DOWNWARD)
|
||||
pixelY = sdf.height-1-pixelY;
|
||||
int b = (int) floor(pixelY);
|
||||
int t = b+1;
|
||||
|
|
@ -46,11 +46,11 @@ void scanlineSDF(Scanline &line, const BitmapConstRef<float, 1> &sdf, const Proj
|
|||
}
|
||||
|
||||
template <int N>
|
||||
void scanlineMSDF(Scanline &line, const BitmapConstRef<float, N> &sdf, const Projection &projection, double y, bool inverseYAxis) {
|
||||
void scanlineMSDF(Scanline &line, const BitmapConstSection<float, N> &sdf, const Projection &projection, double y, YAxisOrientation yAxisOrientation) {
|
||||
if (!(sdf.width > 0 && sdf.height > 0))
|
||||
return line.setIntersections(std::vector<Scanline::Intersection>());
|
||||
double pixelY = clamp(projection.projectY(y)-.5, double(sdf.height-1));
|
||||
if (inverseYAxis)
|
||||
if (yAxisOrientation == Y_DOWNWARD)
|
||||
pixelY = sdf.height-1-pixelY;
|
||||
int b = (int) floor(pixelY);
|
||||
int t = b+1;
|
||||
|
|
@ -124,15 +124,15 @@ void scanlineMSDF(Scanline &line, const BitmapConstRef<float, N> &sdf, const Pro
|
|||
#endif
|
||||
}
|
||||
|
||||
void scanlineSDF(Scanline &line, const BitmapConstRef<float, 3> &sdf, const Projection &projection, double y, bool inverseYAxis) {
|
||||
scanlineMSDF(line, sdf, projection, y, inverseYAxis);
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 3> &sdf, const Projection &projection, double y, YAxisOrientation yAxisOrientation) {
|
||||
scanlineMSDF(line, sdf, projection, y, yAxisOrientation);
|
||||
}
|
||||
void scanlineSDF(Scanline &line, const BitmapConstRef<float, 4> &sdf, const Projection &projection, double y, bool inverseYAxis) {
|
||||
scanlineMSDF(line, sdf, projection, y, inverseYAxis);
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 4> &sdf, const Projection &projection, double y, YAxisOrientation yAxisOrientation) {
|
||||
scanlineMSDF(line, sdf, projection, y, yAxisOrientation);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
double estimateSDFErrorInner(const BitmapConstRef<float, N> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule) {
|
||||
double estimateSDFErrorInner(const BitmapConstSection<float, N> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule) {
|
||||
if (sdf.width <= 1 || sdf.height <= 1 || scanlinesPerRow < 1)
|
||||
return 0;
|
||||
double subRowSize = 1./scanlinesPerRow;
|
||||
|
|
@ -146,46 +146,58 @@ double estimateSDFErrorInner(const BitmapConstRef<float, N> &sdf, const Shape &s
|
|||
double bt = (subRow+.5)*subRowSize;
|
||||
double y = projection.unprojectY(row+bt+.5);
|
||||
shape.scanline(refScanline, y);
|
||||
scanlineSDF(sdfScanline, sdf, projection, y, shape.inverseYAxis);
|
||||
scanlineSDF(sdfScanline, sdf, projection, y, shape.getYAxisOrientation());
|
||||
error += 1-overlapFactor*Scanline::overlap(refScanline, sdfScanline, xFrom, xTo, fillRule);
|
||||
}
|
||||
}
|
||||
return error/((sdf.height-1)*scanlinesPerRow);
|
||||
}
|
||||
|
||||
double estimateSDFError(const BitmapConstRef<float, 1> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule) {
|
||||
double estimateSDFError(const BitmapConstSection<float, 1> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule) {
|
||||
return estimateSDFErrorInner(sdf, shape, projection, scanlinesPerRow, fillRule);
|
||||
}
|
||||
double estimateSDFError(const BitmapConstRef<float, 3> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule) {
|
||||
double estimateSDFError(const BitmapConstSection<float, 3> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule) {
|
||||
return estimateSDFErrorInner(sdf, shape, projection, scanlinesPerRow, fillRule);
|
||||
}
|
||||
double estimateSDFError(const BitmapConstRef<float, 4> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule) {
|
||||
double estimateSDFError(const BitmapConstSection<float, 4> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule) {
|
||||
return estimateSDFErrorInner(sdf, shape, projection, scanlinesPerRow, fillRule);
|
||||
}
|
||||
|
||||
// Legacy API
|
||||
|
||||
void scanlineSDF(Scanline &line, const BitmapConstRef<float, 1> &sdf, const Vector2 &scale, const Vector2 &translate, bool inverseYAxis, double y) {
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 1> &sdf, const Projection &projection, double y, bool inverseYAxis) {
|
||||
scanlineSDF(line, sdf, projection, y, inverseYAxis ? MSDFGEN_Y_AXIS_NONDEFAULT_ORIENTATION : MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION);
|
||||
}
|
||||
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 3> &sdf, const Projection &projection, double y, bool inverseYAxis) {
|
||||
scanlineSDF(line, sdf, projection, y, inverseYAxis ? MSDFGEN_Y_AXIS_NONDEFAULT_ORIENTATION : MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION);
|
||||
}
|
||||
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 4> &sdf, const Projection &projection, double y, bool inverseYAxis) {
|
||||
scanlineSDF(line, sdf, projection, y, inverseYAxis ? MSDFGEN_Y_AXIS_NONDEFAULT_ORIENTATION : MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION);
|
||||
}
|
||||
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 1> &sdf, const Vector2 &scale, const Vector2 &translate, bool inverseYAxis, double y) {
|
||||
scanlineSDF(line, sdf, Projection(scale, translate), y, inverseYAxis);
|
||||
}
|
||||
|
||||
void scanlineSDF(Scanline &line, const BitmapConstRef<float, 3> &sdf, const Vector2 &scale, const Vector2 &translate, bool inverseYAxis, double y) {
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 3> &sdf, const Vector2 &scale, const Vector2 &translate, bool inverseYAxis, double y) {
|
||||
scanlineSDF(line, sdf, Projection(scale, translate), y, inverseYAxis);
|
||||
}
|
||||
|
||||
void scanlineSDF(Scanline &line, const BitmapConstRef<float, 4> &sdf, const Vector2 &scale, const Vector2 &translate, bool inverseYAxis, double y) {
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 4> &sdf, const Vector2 &scale, const Vector2 &translate, bool inverseYAxis, double y) {
|
||||
scanlineSDF(line, sdf, Projection(scale, translate), y, inverseYAxis);
|
||||
}
|
||||
|
||||
double estimateSDFError(const BitmapConstRef<float, 1> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, int scanlinesPerRow, FillRule fillRule) {
|
||||
double estimateSDFError(const BitmapConstSection<float, 1> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, int scanlinesPerRow, FillRule fillRule) {
|
||||
return estimateSDFError(sdf, shape, Projection(scale, translate), scanlinesPerRow, fillRule);
|
||||
}
|
||||
|
||||
double estimateSDFError(const BitmapConstRef<float, 3> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, int scanlinesPerRow, FillRule fillRule) {
|
||||
double estimateSDFError(const BitmapConstSection<float, 3> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, int scanlinesPerRow, FillRule fillRule) {
|
||||
return estimateSDFError(sdf, shape, Projection(scale, translate), scanlinesPerRow, fillRule);
|
||||
}
|
||||
|
||||
double estimateSDFError(const BitmapConstRef<float, 4> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, int scanlinesPerRow, FillRule fillRule) {
|
||||
double estimateSDFError(const BitmapConstSection<float, 4> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, int scanlinesPerRow, FillRule fillRule) {
|
||||
return estimateSDFError(sdf, shape, Projection(scale, translate), scanlinesPerRow, fillRule);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,21 +10,24 @@
|
|||
namespace msdfgen {
|
||||
|
||||
/// Analytically constructs a scanline at y evaluating fill by linear interpolation of the SDF.
|
||||
void scanlineSDF(Scanline &line, const BitmapConstRef<float, 1> &sdf, const Projection &projection, double y, bool inverseYAxis = false);
|
||||
void scanlineSDF(Scanline &line, const BitmapConstRef<float, 3> &sdf, const Projection &projection, double y, bool inverseYAxis = false);
|
||||
void scanlineSDF(Scanline &line, const BitmapConstRef<float, 4> &sdf, const Projection &projection, double y, bool inverseYAxis = false);
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 1> &sdf, const Projection &projection, double y, YAxisOrientation yAxisOrientation = MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION);
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 3> &sdf, const Projection &projection, double y, YAxisOrientation yAxisOrientation = MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION);
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 4> &sdf, const Projection &projection, double y, YAxisOrientation yAxisOrientation = MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION);
|
||||
|
||||
/// Estimates the portion of the area that will be filled incorrectly when rendering using the SDF.
|
||||
double estimateSDFError(const BitmapConstRef<float, 1> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule = FILL_NONZERO);
|
||||
double estimateSDFError(const BitmapConstRef<float, 3> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule = FILL_NONZERO);
|
||||
double estimateSDFError(const BitmapConstRef<float, 4> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule = FILL_NONZERO);
|
||||
double estimateSDFError(const BitmapConstSection<float, 1> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule = FILL_NONZERO);
|
||||
double estimateSDFError(const BitmapConstSection<float, 3> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule = FILL_NONZERO);
|
||||
double estimateSDFError(const BitmapConstSection<float, 4> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule = FILL_NONZERO);
|
||||
|
||||
// Old version of the function API's kept for backwards compatibility
|
||||
void scanlineSDF(Scanline &line, const BitmapConstRef<float, 1> &sdf, const Vector2 &scale, const Vector2 &translate, bool inverseYAxis, double y);
|
||||
void scanlineSDF(Scanline &line, const BitmapConstRef<float, 3> &sdf, const Vector2 &scale, const Vector2 &translate, bool inverseYAxis, double y);
|
||||
void scanlineSDF(Scanline &line, const BitmapConstRef<float, 4> &sdf, const Vector2 &scale, const Vector2 &translate, bool inverseYAxis, double y);
|
||||
double estimateSDFError(const BitmapConstRef<float, 1> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, int scanlinesPerRow, FillRule fillRule = FILL_NONZERO);
|
||||
double estimateSDFError(const BitmapConstRef<float, 3> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, int scanlinesPerRow, FillRule fillRule = FILL_NONZERO);
|
||||
double estimateSDFError(const BitmapConstRef<float, 4> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, int scanlinesPerRow, FillRule fillRule = FILL_NONZERO);
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 1> &sdf, const Projection &projection, double y, bool inverseYAxis);
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 3> &sdf, const Projection &projection, double y, bool inverseYAxis);
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 4> &sdf, const Projection &projection, double y, bool inverseYAxis);
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 1> &sdf, const Vector2 &scale, const Vector2 &translate, bool inverseYAxis, double y);
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 3> &sdf, const Vector2 &scale, const Vector2 &translate, bool inverseYAxis, double y);
|
||||
void scanlineSDF(Scanline &line, const BitmapConstSection<float, 4> &sdf, const Vector2 &scale, const Vector2 &translate, bool inverseYAxis, double y);
|
||||
double estimateSDFError(const BitmapConstSection<float, 1> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, int scanlinesPerRow, FillRule fillRule = FILL_NONZERO);
|
||||
double estimateSDFError(const BitmapConstSection<float, 3> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, int scanlinesPerRow, FillRule fillRule = FILL_NONZERO);
|
||||
double estimateSDFError(const BitmapConstSection<float, 4> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, int scanlinesPerRow, FillRule fillRule = FILL_NONZERO);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,17 @@ int readCoordS(const char **input, Point2 &coord) {
|
|||
return 2;
|
||||
}
|
||||
|
||||
bool matchStringS(const char **input, const char *str) {
|
||||
const char *cur = *input;
|
||||
while (*cur && *str && *cur == *str)
|
||||
++cur, ++str;
|
||||
if (!*str) {
|
||||
*input = cur;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool writeCoord(FILE *output, Point2 coord) {
|
||||
fprintf(output, "%.12g, %.12g", coord.x, coord.y);
|
||||
return true;
|
||||
|
|
@ -176,7 +187,7 @@ static bool readContour(T *input, Contour &output, const Point2 *first, int term
|
|||
bool readShapeDescription(FILE *input, Shape &output, bool *colorsSpecified) {
|
||||
bool locColorsSpec = false;
|
||||
output.contours.clear();
|
||||
output.inverseYAxis = false;
|
||||
output.setYAxisOrientation(MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION);
|
||||
Point2 p;
|
||||
int result = readCoordF(input, p);
|
||||
if (result == 2) {
|
||||
|
|
@ -187,9 +198,21 @@ bool readShapeDescription(FILE *input, Shape &output, bool *colorsSpecified) {
|
|||
int c = readCharF(input);
|
||||
if (c == '@') {
|
||||
char after = '\0';
|
||||
if (fscanf(input, "invert-y%c", &after) != 1)
|
||||
if (fscanf(input, "y-%c", &after) == 1 && (after == 'u' || after == 'd')) {
|
||||
switch (after) {
|
||||
case 'u':
|
||||
output.setYAxisOrientation(Y_UPWARD);
|
||||
break;
|
||||
case 'd':
|
||||
output.setYAxisOrientation(Y_DOWNWARD);
|
||||
break;
|
||||
}
|
||||
if (fscanf(input, after == 'u' ? "p%c" : "own%c", &after) != 1)
|
||||
return feof(input) != 0;
|
||||
} else if (fscanf(input, "invert-y%c", &after) == 1)
|
||||
output.inverseYAxis = true;
|
||||
else
|
||||
return feof(input) != 0;
|
||||
output.inverseYAxis = true;
|
||||
c = after;
|
||||
if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
|
||||
c = readCharF(input);
|
||||
|
|
@ -206,7 +229,7 @@ bool readShapeDescription(FILE *input, Shape &output, bool *colorsSpecified) {
|
|||
bool readShapeDescription(const char *input, Shape &output, bool *colorsSpecified) {
|
||||
bool locColorsSpec = false;
|
||||
output.contours.clear();
|
||||
output.inverseYAxis = false;
|
||||
output.setYAxisOrientation(MSDFGEN_Y_AXIS_DEFAULT_ORIENTATION);
|
||||
Point2 p;
|
||||
int result = readCoordS(&input, p);
|
||||
if (result == 2) {
|
||||
|
|
@ -216,11 +239,14 @@ bool readShapeDescription(const char *input, Shape &output, bool *colorsSpecifie
|
|||
else {
|
||||
int c = readCharS(&input);
|
||||
if (c == '@') {
|
||||
for (int i = 0; i < (int) sizeof("invert-y")-1; ++i)
|
||||
if (input[i] != "invert-y"[i])
|
||||
return false;
|
||||
output.inverseYAxis = true;
|
||||
input += sizeof("invert-y")-1;
|
||||
if (matchStringS(&input, "y-down"))
|
||||
output.setYAxisOrientation(Y_DOWNWARD);
|
||||
else if (matchStringS(&input, "y-up"))
|
||||
output.setYAxisOrientation(Y_UPWARD);
|
||||
else if (matchStringS(&input, "invert-y"))
|
||||
output.inverseYAxis = true;
|
||||
else
|
||||
return false;
|
||||
c = readCharS(&input);
|
||||
}
|
||||
for (; c == '{'; c = readCharS(&input))
|
||||
|
|
@ -244,8 +270,14 @@ bool writeShapeDescription(FILE *output, const Shape &shape) {
|
|||
if (!shape.validate())
|
||||
return false;
|
||||
bool writeColors = isColored(shape);
|
||||
if (shape.inverseYAxis)
|
||||
fprintf(output, "@invert-y\n");
|
||||
switch (shape.getYAxisOrientation()) {
|
||||
case Y_UPWARD:
|
||||
fprintf(output, "@y-up\n");
|
||||
break;
|
||||
case Y_DOWNWARD:
|
||||
fprintf(output, "@y-down\n");
|
||||
break;
|
||||
}
|
||||
for (std::vector<Contour>::const_iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
|
||||
fprintf(output, "{\n");
|
||||
if (!contour->edges.empty()) {
|
||||
|
|
|
|||
|
|
@ -34,45 +34,40 @@
|
|||
#include "core/render-sdf.h"
|
||||
#include "core/rasterization.h"
|
||||
#include "core/sdf-error-estimation.h"
|
||||
#include "core/save-bmp.h"
|
||||
#include "core/save-tiff.h"
|
||||
#include "core/save-rgba.h"
|
||||
#include "core/save-fl32.h"
|
||||
#include "core/shape-description.h"
|
||||
#include "core/export-svg.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
/// Generates a conventional single-channel signed distance field.
|
||||
void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, const SDFTransformation &transformation, const GeneratorConfig &config = GeneratorConfig());
|
||||
void generateSDF(const BitmapSection<float, 1> &output, const Shape &shape, const SDFTransformation &transformation, const GeneratorConfig &config = GeneratorConfig());
|
||||
|
||||
/// Generates a single-channel signed perpendicular distance field.
|
||||
void generatePSDF(const BitmapRef<float, 1> &output, const Shape &shape, const SDFTransformation &transformation, const GeneratorConfig &config = GeneratorConfig());
|
||||
void generatePSDF(const BitmapSection<float, 1> &output, const Shape &shape, const SDFTransformation &transformation, const GeneratorConfig &config = GeneratorConfig());
|
||||
|
||||
/// Generates a multi-channel signed distance field. Edge colors must be assigned first! (See edgeColoringSimple)
|
||||
void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void generateMSDF(const BitmapSection<float, 3> &output, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
|
||||
/// Generates a multi-channel signed distance field with true distance in the alpha channel. Edge colors must be assigned first.
|
||||
void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void generateMTSDF(const BitmapSection<float, 4> &output, const Shape &shape, const SDFTransformation &transformation, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
|
||||
// Old version of the function API's kept for backwards compatibility
|
||||
void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config = GeneratorConfig());
|
||||
void generatePSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config = GeneratorConfig());
|
||||
void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config = GeneratorConfig());
|
||||
void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void generateSDF(const BitmapSection<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config = GeneratorConfig());
|
||||
void generatePSDF(const BitmapSection<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config = GeneratorConfig());
|
||||
void generatePseudoSDF(const BitmapSection<float, 1> &output, const Shape &shape, const Projection &projection, Range range, const GeneratorConfig &config = GeneratorConfig());
|
||||
void generateMSDF(const BitmapSection<float, 3> &output, const Shape &shape, const Projection &projection, Range range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
void generateMTSDF(const BitmapSection<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);
|
||||
void generateSDF(const BitmapSection<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport = true);
|
||||
void generatePSDF(const BitmapSection<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport = true);
|
||||
void generatePseudoSDF(const BitmapSection<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport = true);
|
||||
void generateMSDF(const BitmapSection<float, 3> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig = ErrorCorrectionConfig(), bool overlapSupport = true);
|
||||
void generateMTSDF(const BitmapSection<float, 4> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig = ErrorCorrectionConfig(), bool overlapSupport = true);
|
||||
|
||||
// Original simpler versions of the previous functions, which work well under normal circumstances, but cannot deal with overlapping contours.
|
||||
void generateSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate);
|
||||
void generatePSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate);
|
||||
void generatePseudoSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate);
|
||||
void generateMSDF_legacy(const BitmapRef<float, 3> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig = ErrorCorrectionConfig());
|
||||
void generateMTSDF_legacy(const BitmapRef<float, 4> &output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig = ErrorCorrectionConfig());
|
||||
void generateSDF_legacy(BitmapSection<float, 1> output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate);
|
||||
void generatePSDF_legacy(BitmapSection<float, 1> output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate);
|
||||
void generatePseudoSDF_legacy(BitmapSection<float, 1> output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate);
|
||||
void generateMSDF_legacy(BitmapSection<float, 3> output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig = ErrorCorrectionConfig());
|
||||
void generateMTSDF_legacy(BitmapSection<float, 4> output, const Shape &shape, Range range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig = ErrorCorrectionConfig());
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
diff --git a/thirdparty/msdfgen/msdfgen.h b/thirdparty/msdfgen/msdfgen.h
|
||||
index bf0ae2badc..d2c9a2fc8f 100644
|
||||
--- a/thirdparty/msdfgen/msdfgen.h
|
||||
+++ b/thirdparty/msdfgen/msdfgen.h
|
||||
@@ -34,12 +34,7 @@
|
||||
#include "core/render-sdf.h"
|
||||
#include "core/rasterization.h"
|
||||
#include "core/sdf-error-estimation.h"
|
||||
-#include "core/save-bmp.h"
|
||||
-#include "core/save-tiff.h"
|
||||
-#include "core/save-rgba.h"
|
||||
-#include "core/save-fl32.h"
|
||||
#include "core/shape-description.h"
|
||||
-#include "core/export-svg.h"
|
||||
|
||||
namespace msdfgen {
|
||||
|
||||
Loading…
Reference in New Issue