mirror of https://github.com/Chlumsky/msdfgen.git
Experimental version of 7TSDF mode
This commit is contained in:
parent
682381a03c
commit
7f6a8aebba
|
|
@ -16,6 +16,17 @@ static void initDistance(MultiDistance &distance) {
|
|||
distance.b = -DBL_MAX;
|
||||
}
|
||||
|
||||
static void initDistance(M7AndTrueDistanceSelector::DistanceType &distance) {
|
||||
distance.p[0] = -DBL_MAX;
|
||||
distance.p[1] = -DBL_MAX;
|
||||
distance.p[2] = -DBL_MAX;
|
||||
distance.p[3] = -DBL_MAX;
|
||||
distance.p[4] = -DBL_MAX;
|
||||
distance.p[5] = -DBL_MAX;
|
||||
distance.p[6] = -DBL_MAX;
|
||||
distance.t = -DBL_MAX;
|
||||
}
|
||||
|
||||
static double resolveDistance(double distance) {
|
||||
return distance;
|
||||
}
|
||||
|
|
@ -24,6 +35,15 @@ static double resolveDistance(const MultiDistance &distance) {
|
|||
return median(distance.r, distance.g, distance.b);
|
||||
}
|
||||
|
||||
static int cmpDbl(const void *a, const void *b) {
|
||||
return *reinterpret_cast<const double *>(a) < *reinterpret_cast<const double *>(b);
|
||||
}
|
||||
|
||||
static double resolveDistance(M7AndTrueDistanceSelector::DistanceType distance) {
|
||||
qsort(distance.p, 7, sizeof(*distance.p), &cmpDbl);
|
||||
return distance.p[3];
|
||||
}
|
||||
|
||||
template <class EdgeSelector>
|
||||
SimpleContourCombiner<EdgeSelector>::SimpleContourCombiner(const Shape &shape) { }
|
||||
|
||||
|
|
@ -46,6 +66,7 @@ template class SimpleContourCombiner<TrueDistanceSelector>;
|
|||
template class SimpleContourCombiner<PseudoDistanceSelector>;
|
||||
template class SimpleContourCombiner<MultiDistanceSelector>;
|
||||
template class SimpleContourCombiner<MultiAndTrueDistanceSelector>;
|
||||
template class SimpleContourCombiner<M7AndTrueDistanceSelector>;
|
||||
|
||||
template <class EdgeSelector>
|
||||
OverlappingContourCombiner<EdgeSelector>::OverlappingContourCombiner(const Shape &shape) {
|
||||
|
|
@ -130,5 +151,6 @@ template class OverlappingContourCombiner<TrueDistanceSelector>;
|
|||
template class OverlappingContourCombiner<PseudoDistanceSelector>;
|
||||
template class OverlappingContourCombiner<MultiDistanceSelector>;
|
||||
template class OverlappingContourCombiner<MultiAndTrueDistanceSelector>;
|
||||
template class OverlappingContourCombiner<M7AndTrueDistanceSelector>;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -498,4 +498,140 @@ void edgeColoringByDistance(Shape &shape, double angleThreshold, unsigned long l
|
|||
}
|
||||
}
|
||||
|
||||
void edgeColoring7Random(Shape &shape, double angleThreshold, unsigned long long seed) {
|
||||
/*int colorPool[] = {
|
||||
0b00001111,
|
||||
0b00010111,
|
||||
0b00011011,
|
||||
0b00011101,
|
||||
0b00011110,
|
||||
0b00100111,
|
||||
0b00101011,
|
||||
0b00101101,
|
||||
0b00101110,
|
||||
0b00110011,
|
||||
0b00110101,
|
||||
0b00110110,
|
||||
0b00111001,
|
||||
0b00111010,
|
||||
0b00111100,
|
||||
0b01000111,
|
||||
0b01001011,
|
||||
0b01001101,
|
||||
0b01001110,
|
||||
0b01010011,
|
||||
0b01010101,
|
||||
0b01010110,
|
||||
0b01011001,
|
||||
0b01011010,
|
||||
0b01011100,
|
||||
0b01100011,
|
||||
0b01100101,
|
||||
0b01100110,
|
||||
0b01101001,
|
||||
0b01101010,
|
||||
0b01101100,
|
||||
0b01110001,
|
||||
0b01110010,
|
||||
0b01110100,
|
||||
0b01111000,
|
||||
};
|
||||
static_assert(sizeof(colorPool) == 35*sizeof(*colorPool), "Expected 35 colors in color pool");*/
|
||||
int colorPool[] = {
|
||||
// All pairs share exactly 2 set bits
|
||||
0b00001111,
|
||||
0b00111100,
|
||||
0b00110011,
|
||||
0b01010101,
|
||||
0b01011010,
|
||||
0b01100110,
|
||||
0b01101001,
|
||||
};
|
||||
|
||||
int colorI = 0;
|
||||
#define NEXT_COLOR() EdgeColor(colorPool[colorI++%(int(sizeof(colorPool)/sizeof(*colorPool)))])
|
||||
|
||||
double crossThreshold = sin(angleThreshold);
|
||||
std::vector<int> corners;
|
||||
for (std::vector<Contour>::iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
|
||||
if (seed) {
|
||||
// Shuffle colorPool
|
||||
for (int i = int(sizeof(colorPool)/sizeof(*colorPool))-1; i; --i) {
|
||||
seed = 6364136223846793005ll*seed+1442695040888963407ll; // LCG
|
||||
int j = int(seed%(i+1));
|
||||
int tmp = colorPool[i];
|
||||
colorPool[i] = colorPool[j];
|
||||
colorPool[j] = tmp;
|
||||
}
|
||||
}
|
||||
// Identify corners
|
||||
corners.clear();
|
||||
if (!contour->edges.empty()) {
|
||||
Vector2 prevDirection = contour->edges.back()->direction(1);
|
||||
int index = 0;
|
||||
for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge, ++index) {
|
||||
if (isCorner(prevDirection.normalize(), (*edge)->direction(0).normalize(), crossThreshold))
|
||||
corners.push_back(index);
|
||||
prevDirection = (*edge)->direction(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Smooth contour
|
||||
if (corners.empty()) {
|
||||
EdgeColor color = NEXT_COLOR();
|
||||
for (std::vector<EdgeHolder>::iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge)
|
||||
(*edge)->color = color;
|
||||
}
|
||||
// "Teardrop" case
|
||||
else if (corners.size() == 1) {
|
||||
EdgeColor colors[3];
|
||||
colors[0] = NEXT_COLOR();
|
||||
colors[2] = NEXT_COLOR();
|
||||
colors[1] = EdgeColor(colors[0]|colors[2]);
|
||||
int corner = corners[0];
|
||||
if (contour->edges.size() >= 3) {
|
||||
int m = (int) contour->edges.size();
|
||||
for (int i = 0; i < m; ++i)
|
||||
contour->edges[(corner+i)%m]->color = (colors+1)[int(3+2.875*i/(m-1)-1.4375+.5)-3];
|
||||
} else if (contour->edges.size() >= 1) {
|
||||
// Less than three edge segments for three colors => edges must be split
|
||||
EdgeSegment *parts[7] = { };
|
||||
contour->edges[0]->splitInThirds(parts[0+3*corner], parts[1+3*corner], parts[2+3*corner]);
|
||||
if (contour->edges.size() >= 2) {
|
||||
contour->edges[1]->splitInThirds(parts[3-3*corner], parts[4-3*corner], parts[5-3*corner]);
|
||||
parts[0]->color = parts[1]->color = colors[0];
|
||||
parts[2]->color = parts[3]->color = colors[1];
|
||||
parts[4]->color = parts[5]->color = colors[2];
|
||||
} else {
|
||||
parts[0]->color = colors[0];
|
||||
parts[1]->color = colors[1];
|
||||
parts[2]->color = colors[2];
|
||||
}
|
||||
contour->edges.clear();
|
||||
for (int i = 0; parts[i]; ++i)
|
||||
contour->edges.push_back(EdgeHolder(parts[i]));
|
||||
}
|
||||
}
|
||||
// Multiple corners
|
||||
else {
|
||||
int cornerCount = (int) corners.size();
|
||||
int spline = 0;
|
||||
int start = corners[0];
|
||||
int m = (int) contour->edges.size();
|
||||
EdgeColor color = NEXT_COLOR();
|
||||
EdgeColor initialColor = color;
|
||||
for (int i = 0; i < m; ++i) {
|
||||
int index = (start+i)%m;
|
||||
if (spline+1 < cornerCount && corners[spline+1] == index) {
|
||||
++spline;
|
||||
color = NEXT_COLOR();
|
||||
if (spline == cornerCount-1 && color == initialColor)
|
||||
color = NEXT_COLOR();
|
||||
}
|
||||
contour->edges[index]->color = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,4 +26,6 @@ void edgeColoringInkTrap(Shape &shape, double angleThreshold, unsigned long long
|
|||
*/
|
||||
void edgeColoringByDistance(Shape &shape, double angleThreshold, unsigned long long seed = 0);
|
||||
|
||||
void edgeColoring7Random(Shape &shape, double angleThreshold, unsigned long long seed = 0);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -258,4 +258,139 @@ MultiAndTrueDistanceSelector::DistanceType MultiAndTrueDistanceSelector::distanc
|
|||
return mtd;
|
||||
}
|
||||
|
||||
void M7AndTrueDistanceSelector::reset(const Point2 &p) {
|
||||
double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
|
||||
b[0].reset(delta);
|
||||
b[1].reset(delta);
|
||||
b[2].reset(delta);
|
||||
b[3].reset(delta);
|
||||
b[4].reset(delta);
|
||||
b[5].reset(delta);
|
||||
b[6].reset(delta);
|
||||
this->p = p;
|
||||
}
|
||||
|
||||
void M7AndTrueDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
|
||||
if (
|
||||
(edge->color&1<<0 && b[0].isEdgeRelevant(cache, edge, p)) ||
|
||||
(edge->color&1<<1 && b[1].isEdgeRelevant(cache, edge, p)) ||
|
||||
(edge->color&1<<2 && b[2].isEdgeRelevant(cache, edge, p)) ||
|
||||
(edge->color&1<<3 && b[3].isEdgeRelevant(cache, edge, p)) ||
|
||||
(edge->color&1<<4 && b[4].isEdgeRelevant(cache, edge, p)) ||
|
||||
(edge->color&1<<5 && b[5].isEdgeRelevant(cache, edge, p)) ||
|
||||
(edge->color&1<<6 && b[6].isEdgeRelevant(cache, edge, p))
|
||||
) {
|
||||
double param;
|
||||
SignedDistance distance = edge->signedDistance(p, param);
|
||||
if (edge->color&1<<0)
|
||||
b[0].addEdgeTrueDistance(edge, distance, param);
|
||||
if (edge->color&1<<1)
|
||||
b[1].addEdgeTrueDistance(edge, distance, param);
|
||||
if (edge->color&1<<2)
|
||||
b[2].addEdgeTrueDistance(edge, distance, param);
|
||||
if (edge->color&1<<3)
|
||||
b[3].addEdgeTrueDistance(edge, distance, param);
|
||||
if (edge->color&1<<4)
|
||||
b[4].addEdgeTrueDistance(edge, distance, param);
|
||||
if (edge->color&1<<5)
|
||||
b[5].addEdgeTrueDistance(edge, distance, param);
|
||||
if (edge->color&1<<6)
|
||||
b[6].addEdgeTrueDistance(edge, distance, param);
|
||||
cache.point = p;
|
||||
cache.absDistance = fabs(distance.distance);
|
||||
|
||||
Vector2 ap = p-edge->point(0);
|
||||
Vector2 bp = p-edge->point(1);
|
||||
Vector2 aDir = edge->direction(0).normalize(true);
|
||||
Vector2 bDir = edge->direction(1).normalize(true);
|
||||
Vector2 prevDir = prevEdge->direction(1).normalize(true);
|
||||
Vector2 nextDir = nextEdge->direction(0).normalize(true);
|
||||
double add = dotProduct(ap, (prevDir+aDir).normalize(true));
|
||||
double bdd = -dotProduct(bp, (bDir+nextDir).normalize(true));
|
||||
if (add > 0) {
|
||||
double pd = distance.distance;
|
||||
if (PseudoDistanceSelectorBase::getPseudoDistance(pd, ap, -aDir)) {
|
||||
pd = -pd;
|
||||
if (edge->color&1<<0)
|
||||
b[0].addEdgePseudoDistance(pd);
|
||||
if (edge->color&1<<1)
|
||||
b[1].addEdgePseudoDistance(pd);
|
||||
if (edge->color&1<<2)
|
||||
b[2].addEdgePseudoDistance(pd);
|
||||
if (edge->color&1<<3)
|
||||
b[3].addEdgePseudoDistance(pd);
|
||||
if (edge->color&1<<4)
|
||||
b[4].addEdgePseudoDistance(pd);
|
||||
if (edge->color&1<<5)
|
||||
b[5].addEdgePseudoDistance(pd);
|
||||
if (edge->color&1<<6)
|
||||
b[6].addEdgePseudoDistance(pd);
|
||||
}
|
||||
cache.aPseudoDistance = pd;
|
||||
}
|
||||
if (bdd > 0) {
|
||||
double pd = distance.distance;
|
||||
if (PseudoDistanceSelectorBase::getPseudoDistance(pd, bp, bDir)) {
|
||||
if (edge->color&1<<0)
|
||||
b[0].addEdgePseudoDistance(pd);
|
||||
if (edge->color&1<<1)
|
||||
b[1].addEdgePseudoDistance(pd);
|
||||
if (edge->color&1<<2)
|
||||
b[2].addEdgePseudoDistance(pd);
|
||||
if (edge->color&1<<3)
|
||||
b[3].addEdgePseudoDistance(pd);
|
||||
if (edge->color&1<<4)
|
||||
b[4].addEdgePseudoDistance(pd);
|
||||
if (edge->color&1<<5)
|
||||
b[5].addEdgePseudoDistance(pd);
|
||||
if (edge->color&1<<6)
|
||||
b[6].addEdgePseudoDistance(pd);
|
||||
}
|
||||
cache.bPseudoDistance = pd;
|
||||
}
|
||||
cache.aDomainDistance = add;
|
||||
cache.bDomainDistance = bdd;
|
||||
}
|
||||
}
|
||||
|
||||
void M7AndTrueDistanceSelector::merge(const M7AndTrueDistanceSelector &other) {
|
||||
b[0].merge(other.b[0]);
|
||||
b[1].merge(other.b[1]);
|
||||
b[2].merge(other.b[2]);
|
||||
b[3].merge(other.b[3]);
|
||||
b[4].merge(other.b[4]);
|
||||
b[5].merge(other.b[5]);
|
||||
b[6].merge(other.b[6]);
|
||||
}
|
||||
|
||||
M7AndTrueDistanceSelector::DistanceType M7AndTrueDistanceSelector::distance() const {
|
||||
DistanceType multiDistance;
|
||||
multiDistance.p[0] = b[0].computeDistance(p);
|
||||
multiDistance.p[1] = b[1].computeDistance(p);
|
||||
multiDistance.p[2] = b[2].computeDistance(p);
|
||||
multiDistance.p[3] = b[3].computeDistance(p);
|
||||
multiDistance.p[4] = b[4].computeDistance(p);
|
||||
multiDistance.p[5] = b[5].computeDistance(p);
|
||||
multiDistance.p[6] = b[6].computeDistance(p);
|
||||
multiDistance.t = trueDistance().distance;
|
||||
return multiDistance;
|
||||
}
|
||||
|
||||
SignedDistance M7AndTrueDistanceSelector::trueDistance() const {
|
||||
SignedDistance distance = b[0].trueDistance();
|
||||
if (b[1].trueDistance() < distance)
|
||||
distance = b[1].trueDistance();
|
||||
if (b[2].trueDistance() < distance)
|
||||
distance = b[2].trueDistance();
|
||||
if (b[3].trueDistance() < distance)
|
||||
distance = b[3].trueDistance();
|
||||
if (b[4].trueDistance() < distance)
|
||||
distance = b[4].trueDistance();
|
||||
if (b[5].trueDistance() < distance)
|
||||
distance = b[5].trueDistance();
|
||||
if (b[6].trueDistance() < distance)
|
||||
distance = b[6].trueDistance();
|
||||
return distance;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,4 +114,25 @@ public:
|
|||
|
||||
};
|
||||
|
||||
class M7AndTrueDistanceSelector {
|
||||
|
||||
public:
|
||||
typedef PseudoDistanceSelectorBase::EdgeCache EdgeCache;
|
||||
struct DistanceType {
|
||||
double p[7];
|
||||
double t;
|
||||
};
|
||||
|
||||
void reset(const Point2 &p);
|
||||
void addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge);
|
||||
void merge(const M7AndTrueDistanceSelector &other);
|
||||
DistanceType distance() const;
|
||||
SignedDistance trueDistance() const;
|
||||
|
||||
private:
|
||||
Point2 p;
|
||||
PseudoDistanceSelectorBase b[7];
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,24 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class DistancePixelConversion<M7AndTrueDistanceSelector::DistanceType> {
|
||||
double invRange;
|
||||
public:
|
||||
typedef BitmapRef<float, 8> BitmapRefType;
|
||||
inline explicit DistancePixelConversion(double range) : invRange(1/range) { }
|
||||
inline void operator()(float *pixels, const M7AndTrueDistanceSelector::DistanceType &distance) const {
|
||||
pixels[0] = float(invRange*distance.p[0]+.5);
|
||||
pixels[1] = float(invRange*distance.p[1]+.5);
|
||||
pixels[2] = float(invRange*distance.p[2]+.5);
|
||||
pixels[3] = float(invRange*distance.p[3]+.5);
|
||||
pixels[4] = float(invRange*distance.p[4]+.5);
|
||||
pixels[5] = float(invRange*distance.p[5]+.5);
|
||||
pixels[6] = float(invRange*distance.p[6]+.5);
|
||||
pixels[7] = float(invRange*distance.t+.5);
|
||||
}
|
||||
};
|
||||
|
||||
template <class ContourCombiner>
|
||||
void generateDistanceField(const typename DistancePixelConversion<typename ContourCombiner::DistanceType>::BitmapRefType &output, const Shape &shape, const Projection &projection, double range) {
|
||||
DistancePixelConversion<typename ContourCombiner::DistanceType> distancePixelConversion(range);
|
||||
|
|
@ -104,6 +122,13 @@ void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, const
|
|||
msdfErrorCorrection(output, shape, projection, range, config);
|
||||
}
|
||||
|
||||
void generate7TSDF(const BitmapRef<float, 8> &output, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config) {
|
||||
if (config.overlapSupport)
|
||||
generateDistanceField<OverlappingContourCombiner<M7AndTrueDistanceSelector> >(output, shape, projection, range);
|
||||
else
|
||||
generateDistanceField<SimpleContourCombiner<M7AndTrueDistanceSelector> >(output, shape, projection, range);
|
||||
}
|
||||
|
||||
// Legacy API
|
||||
|
||||
void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
|
||||
|
|
|
|||
29
main.cpp
29
main.cpp
|
|
@ -516,6 +516,7 @@ int main(int argc, const char *const *argv) {
|
|||
PSEUDO,
|
||||
MULTI,
|
||||
MULTI_AND_TRUE,
|
||||
MULTI7_AND_TRUE,
|
||||
METRICS
|
||||
} mode = MULTI;
|
||||
enum {
|
||||
|
|
@ -592,6 +593,7 @@ int main(int argc, const char *const *argv) {
|
|||
ARG_MODE("psdf", PSEUDO)
|
||||
ARG_MODE("msdf", MULTI)
|
||||
ARG_MODE("mtsdf", MULTI_AND_TRUE)
|
||||
ARG_MODE("7tsdf", MULTI7_AND_TRUE)
|
||||
ARG_MODE("metrics", METRICS)
|
||||
|
||||
#if defined(MSDFGEN_EXTENSIONS) && !defined(MSDFGEN_DISABLE_SVG)
|
||||
|
|
@ -1140,6 +1142,7 @@ int main(int argc, const char *const *argv) {
|
|||
Bitmap<float, 1> sdf;
|
||||
Bitmap<float, 3> msdf;
|
||||
Bitmap<float, 4> mtsdf;
|
||||
Bitmap<float, 8> m7tsdf;
|
||||
MSDFGeneratorConfig postErrorCorrectionConfig(generatorConfig);
|
||||
if (scanlinePass) {
|
||||
if (explicitErrorCorrectionMode && generatorConfig.errorCorrection.distanceCheckMode != ErrorCorrectionConfig::DO_NOT_CHECK_DISTANCE) {
|
||||
|
|
@ -1196,6 +1199,27 @@ int main(int argc, const char *const *argv) {
|
|||
generateMTSDF(mtsdf, shape, projection, range, generatorConfig);
|
||||
break;
|
||||
}
|
||||
case MULTI7_AND_TRUE:
|
||||
edgeColoring7Random(shape, angleThreshold, coloringSeed);
|
||||
m7tsdf = Bitmap<float, 8>(width, height);
|
||||
generate7TSDF(m7tsdf, shape, projection, range, generatorConfig);
|
||||
mtsdf = Bitmap<float, 4>(width, 2*height);
|
||||
for (float
|
||||
*dstLow = mtsdf(0, 0),
|
||||
*dstHigh = mtsdf(0, height),
|
||||
*src = m7tsdf(0, 0),
|
||||
*srcEnd = m7tsdf(0, height);
|
||||
src < srcEnd; dstLow += 4, dstHigh += 4, src += 8
|
||||
) {
|
||||
dstLow[0] = src[0];
|
||||
dstLow[1] = src[1];
|
||||
dstLow[2] = src[2];
|
||||
dstLow[3] = src[3];
|
||||
dstHigh[0] = src[4];
|
||||
dstHigh[1] = src[5];
|
||||
dstHigh[2] = src[6];
|
||||
dstHigh[3] = src[7];
|
||||
}
|
||||
default:;
|
||||
}
|
||||
|
||||
|
|
@ -1343,6 +1367,11 @@ int main(int argc, const char *const *argv) {
|
|||
fputs("Failed to write test render file.\n", stderr);
|
||||
}
|
||||
break;
|
||||
case MULTI7_AND_TRUE:
|
||||
if ((error = writeOutput<4>(mtsdf, output, format))) {
|
||||
fprintf(stderr, "%s\n", error);
|
||||
return 1;
|
||||
}
|
||||
default:;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,9 @@ void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, const P
|
|||
/// Generates a multi-channel signed distance field with true distance in the alpha channel. Edge colors must be assigned first.
|
||||
void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
|
||||
/// Generates a 7+1 channel signed distance field with true distance in the last channel. Edge colors must be assigned first.
|
||||
void generate7TSDF(const BitmapRef<float, 8> &output, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
|
||||
|
||||
// Old version of the function API's kept for backwards compatibility
|
||||
void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport = true);
|
||||
void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport = true);
|
||||
|
|
|
|||
Loading…
Reference in New Issue