mirror of https://github.com/Chlumsky/msdfgen.git
Added output distance shift argument
This commit is contained in:
parent
82364f92ec
commit
9d5c7c54e8
|
|
@ -7,83 +7,83 @@
|
||||||
|
|
||||||
namespace msdfgen {
|
namespace msdfgen {
|
||||||
|
|
||||||
static float distVal(float dist, double pxRange) {
|
static float distVal(float dist, double pxRange, float midValue) {
|
||||||
if (!pxRange)
|
if (!pxRange)
|
||||||
return (float) (dist > .5f);
|
return (float) (dist > midValue);
|
||||||
return (float) clamp((dist-.5f)*pxRange+.5);
|
return (float) clamp((dist-midValue)*pxRange+.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 1> &sdf, double pxRange) {
|
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 1> &sdf, double pxRange, float midValue) {
|
||||||
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||||
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
||||||
for (int y = 0; y < output.height; ++y)
|
for (int y = 0; y < output.height; ++y)
|
||||||
for (int x = 0; x < output.width; ++x) {
|
for (int x = 0; x < output.width; ++x) {
|
||||||
float sd;
|
float sd;
|
||||||
interpolate(&sd, sdf, scale*Point2(x+.5, y+.5));
|
interpolate(&sd, sdf, scale*Point2(x+.5, y+.5));
|
||||||
*output(x, y) = distVal(sd, pxRange);
|
*output(x, y) = distVal(sd, pxRange, midValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderSDF(const BitmapRef<float, 3> &output, const BitmapConstRef<float, 1> &sdf, double pxRange) {
|
void renderSDF(const BitmapRef<float, 3> &output, const BitmapConstRef<float, 1> &sdf, double pxRange, float midValue) {
|
||||||
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||||
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
||||||
for (int y = 0; y < output.height; ++y)
|
for (int y = 0; y < output.height; ++y)
|
||||||
for (int x = 0; x < output.width; ++x) {
|
for (int x = 0; x < output.width; ++x) {
|
||||||
float sd;
|
float sd;
|
||||||
interpolate(&sd, sdf, scale*Point2(x+.5, y+.5));
|
interpolate(&sd, sdf, scale*Point2(x+.5, y+.5));
|
||||||
float v = distVal(sd, pxRange);
|
float v = distVal(sd, pxRange, midValue);
|
||||||
output(x, y)[0] = v;
|
output(x, y)[0] = v;
|
||||||
output(x, y)[1] = v;
|
output(x, y)[1] = v;
|
||||||
output(x, y)[2] = v;
|
output(x, y)[2] = v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 3> &sdf, double pxRange) {
|
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 3> &sdf, double pxRange, float midValue) {
|
||||||
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||||
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
||||||
for (int y = 0; y < output.height; ++y)
|
for (int y = 0; y < output.height; ++y)
|
||||||
for (int x = 0; x < output.width; ++x) {
|
for (int x = 0; x < output.width; ++x) {
|
||||||
float sd[3];
|
float sd[3];
|
||||||
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
||||||
*output(x, y) = distVal(median(sd[0], sd[1], sd[2]), pxRange);
|
*output(x, y) = distVal(median(sd[0], sd[1], sd[2]), pxRange, midValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderSDF(const BitmapRef<float, 3> &output, const BitmapConstRef<float, 3> &sdf, double pxRange) {
|
void renderSDF(const BitmapRef<float, 3> &output, const BitmapConstRef<float, 3> &sdf, double pxRange, float midValue) {
|
||||||
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||||
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
||||||
for (int y = 0; y < output.height; ++y)
|
for (int y = 0; y < output.height; ++y)
|
||||||
for (int x = 0; x < output.width; ++x) {
|
for (int x = 0; x < output.width; ++x) {
|
||||||
float sd[3];
|
float sd[3];
|
||||||
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
||||||
output(x, y)[0] = distVal(sd[0], pxRange);
|
output(x, y)[0] = distVal(sd[0], pxRange, midValue);
|
||||||
output(x, y)[1] = distVal(sd[1], pxRange);
|
output(x, y)[1] = distVal(sd[1], pxRange, midValue);
|
||||||
output(x, y)[2] = distVal(sd[2], pxRange);
|
output(x, y)[2] = distVal(sd[2], pxRange, midValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 4> &sdf, double pxRange) {
|
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 4> &sdf, double pxRange, float midValue) {
|
||||||
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||||
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
||||||
for (int y = 0; y < output.height; ++y)
|
for (int y = 0; y < output.height; ++y)
|
||||||
for (int x = 0; x < output.width; ++x) {
|
for (int x = 0; x < output.width; ++x) {
|
||||||
float sd[4];
|
float sd[4];
|
||||||
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
||||||
*output(x, y) = distVal(median(sd[0], sd[1], sd[2]), pxRange);
|
*output(x, y) = distVal(median(sd[0], sd[1], sd[2]), pxRange, midValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderSDF(const BitmapRef<float, 4> &output, const BitmapConstRef<float, 4> &sdf, double pxRange) {
|
void renderSDF(const BitmapRef<float, 4> &output, const BitmapConstRef<float, 4> &sdf, double pxRange, float midValue) {
|
||||||
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
Vector2 scale((double) sdf.width/output.width, (double) sdf.height/output.height);
|
||||||
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
pxRange *= (double) (output.width+output.height)/(sdf.width+sdf.height);
|
||||||
for (int y = 0; y < output.height; ++y)
|
for (int y = 0; y < output.height; ++y)
|
||||||
for (int x = 0; x < output.width; ++x) {
|
for (int x = 0; x < output.width; ++x) {
|
||||||
float sd[4];
|
float sd[4];
|
||||||
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
interpolate(sd, sdf, scale*Point2(x+.5, y+.5));
|
||||||
output(x, y)[0] = distVal(sd[0], pxRange);
|
output(x, y)[0] = distVal(sd[0], pxRange, midValue);
|
||||||
output(x, y)[1] = distVal(sd[1], pxRange);
|
output(x, y)[1] = distVal(sd[1], pxRange, midValue);
|
||||||
output(x, y)[2] = distVal(sd[2], pxRange);
|
output(x, y)[2] = distVal(sd[2], pxRange, midValue);
|
||||||
output(x, y)[3] = distVal(sd[3], pxRange);
|
output(x, y)[3] = distVal(sd[3], pxRange, midValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,12 @@
|
||||||
namespace msdfgen {
|
namespace msdfgen {
|
||||||
|
|
||||||
/// Reconstructs the shape's appearance into output from the distance field sdf.
|
/// Reconstructs the shape's appearance into output from the distance field sdf.
|
||||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 1> &sdf, double pxRange = 0);
|
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 1> &sdf, double pxRange = 0, float midValue = .5f);
|
||||||
void renderSDF(const BitmapRef<float, 3> &output, const BitmapConstRef<float, 1> &sdf, double pxRange = 0);
|
void renderSDF(const BitmapRef<float, 3> &output, const BitmapConstRef<float, 1> &sdf, double pxRange = 0, float midValue = .5f);
|
||||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 3> &sdf, double pxRange = 0);
|
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 3> &sdf, double pxRange = 0, float midValue = .5f);
|
||||||
void renderSDF(const BitmapRef<float, 3> &output, const BitmapConstRef<float, 3> &sdf, double pxRange = 0);
|
void renderSDF(const BitmapRef<float, 3> &output, const BitmapConstRef<float, 3> &sdf, double pxRange = 0, float midValue = .5f);
|
||||||
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 4> &sdf, double pxRange = 0);
|
void renderSDF(const BitmapRef<float, 1> &output, const BitmapConstRef<float, 4> &sdf, double pxRange = 0, float midValue = .5f);
|
||||||
void renderSDF(const BitmapRef<float, 4> &output, const BitmapConstRef<float, 4> &sdf, double pxRange = 0);
|
void renderSDF(const BitmapRef<float, 4> &output, const BitmapConstRef<float, 4> &sdf, double pxRange = 0, float midValue = .5f);
|
||||||
|
|
||||||
/// Snaps the values of the floating-point bitmaps into one of the 256 values representable in a standard 8-bit bitmap.
|
/// Snaps the values of the floating-point bitmaps into one of the 256 values representable in a standard 8-bit bitmap.
|
||||||
void simulate8bit(const BitmapRef<float, 1> &bitmap);
|
void simulate8bit(const BitmapRef<float, 1> &bitmap);
|
||||||
|
|
|
||||||
61
main.cpp
61
main.cpp
|
|
@ -157,7 +157,7 @@ static bool writeTextBitmap(FILE *file, const float *values, int cols, int rows)
|
||||||
static bool writeTextBitmapFloat(FILE *file, const float *values, int cols, int rows) {
|
static bool writeTextBitmapFloat(FILE *file, const float *values, int cols, int rows) {
|
||||||
for (int row = 0; row < rows; ++row) {
|
for (int row = 0; row < rows; ++row) {
|
||||||
for (int col = 0; col < cols; ++col) {
|
for (int col = 0; col < cols; ++col) {
|
||||||
fprintf(file, col ? " %g" : "%g", *values++);
|
fprintf(file, col ? " %.9g" : "%.9g", *values++);
|
||||||
}
|
}
|
||||||
fprintf(file, "\n");
|
fprintf(file, "\n");
|
||||||
}
|
}
|
||||||
|
|
@ -203,7 +203,7 @@ static bool cmpExtension(const char *path, const char *ext) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int N>
|
template <int N>
|
||||||
static const char * writeOutput(const BitmapConstRef<float, N> &bitmap, const char *filename, Format format) {
|
static const char * writeOutput(const BitmapConstRef<float, N> &bitmap, const char *filename, Format &format) {
|
||||||
if (filename) {
|
if (filename) {
|
||||||
if (format == AUTO) {
|
if (format == AUTO) {
|
||||||
if (cmpExtension(filename, ".png")) format = PNG;
|
if (cmpExtension(filename, ".png")) format = PNG;
|
||||||
|
|
@ -291,6 +291,8 @@ static const char *helpText =
|
||||||
"\tAutomatically scales (unless specified) and translates the shape to fit.\n"
|
"\tAutomatically scales (unless specified) and translates the shape to fit.\n"
|
||||||
" -coloringstrategy <simple / inktrap>\n"
|
" -coloringstrategy <simple / inktrap>\n"
|
||||||
"\tSelects the strategy of the edge coloring heuristic.\n"
|
"\tSelects the strategy of the edge coloring heuristic.\n"
|
||||||
|
" -distanceshift <shift>\n"
|
||||||
|
"\tShifts all normalized distances in the output distance field by this value.\n"
|
||||||
" -edgecolors <sequence>\n"
|
" -edgecolors <sequence>\n"
|
||||||
"\tOverrides automatic edge coloring with the specified color sequence.\n"
|
"\tOverrides automatic edge coloring with the specified color sequence.\n"
|
||||||
" -errorcorrection <threshold>\n"
|
" -errorcorrection <threshold>\n"
|
||||||
|
|
@ -389,6 +391,7 @@ int main(int argc, const char * const *argv) {
|
||||||
bool scaleSpecified = false;
|
bool scaleSpecified = false;
|
||||||
double angleThreshold = DEFAULT_ANGLE_THRESHOLD;
|
double angleThreshold = DEFAULT_ANGLE_THRESHOLD;
|
||||||
double errorCorrectionThreshold = MSDFGEN_DEFAULT_ERROR_CORRECTION_THRESHOLD;
|
double errorCorrectionThreshold = MSDFGEN_DEFAULT_ERROR_CORRECTION_THRESHOLD;
|
||||||
|
float outputDistanceShift = 0.f;
|
||||||
const char *edgeAssignment = NULL;
|
const char *edgeAssignment = NULL;
|
||||||
bool yFlip = false;
|
bool yFlip = false;
|
||||||
bool printMetrics = false;
|
bool printMetrics = false;
|
||||||
|
|
@ -597,6 +600,14 @@ int main(int argc, const char * const *argv) {
|
||||||
argPos += 2;
|
argPos += 2;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
ARG_CASE("-distanceshift", 1) {
|
||||||
|
double ds;
|
||||||
|
if (!parseDouble(ds, argv[argPos+1]))
|
||||||
|
ABORT("Invalid distance shift. Use -distanceshift <shift> with a real value.");
|
||||||
|
outputDistanceShift = (float) ds;
|
||||||
|
argPos += 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
ARG_CASE("-exportshape", 1) {
|
ARG_CASE("-exportshape", 1) {
|
||||||
shapeExport = argv[argPos+1];
|
shapeExport = argv[argPos+1];
|
||||||
argPos += 2;
|
argPos += 2;
|
||||||
|
|
@ -738,10 +749,13 @@ int main(int argc, const char * const *argv) {
|
||||||
if (autoFrame) {
|
if (autoFrame) {
|
||||||
double l = bounds.l, b = bounds.b, r = bounds.r, t = bounds.t;
|
double l = bounds.l, b = bounds.b, r = bounds.r, t = bounds.t;
|
||||||
Vector2 frame(width, height);
|
Vector2 frame(width, height);
|
||||||
if (rangeMode == RANGE_UNIT)
|
double m = .5+(double) outputDistanceShift;
|
||||||
l -= .5*range, b -= .5*range, r += .5*range, t += .5*range;
|
if (!scaleSpecified) {
|
||||||
else if (!scaleSpecified)
|
if (rangeMode == RANGE_UNIT)
|
||||||
frame -= pxRange;
|
l -= m*range, b -= m*range, r += m*range, t += m*range;
|
||||||
|
else
|
||||||
|
frame -= 2*m*pxRange;
|
||||||
|
}
|
||||||
if (l >= r || b >= t)
|
if (l >= r || b >= t)
|
||||||
l = 0, b = 0, r = 1, t = 1;
|
l = 0, b = 0, r = 1, t = 1;
|
||||||
if (frame.x <= 0 || frame.y <= 0)
|
if (frame.x <= 0 || frame.y <= 0)
|
||||||
|
|
@ -759,7 +773,7 @@ int main(int argc, const char * const *argv) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rangeMode == RANGE_PX && !scaleSpecified)
|
if (rangeMode == RANGE_PX && !scaleSpecified)
|
||||||
translate += .5*pxRange/scale;
|
translate += m*pxRange/scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rangeMode == RANGE_PX)
|
if (rangeMode == RANGE_PX)
|
||||||
|
|
@ -879,6 +893,27 @@ int main(int argc, const char * const *argv) {
|
||||||
default:;
|
default:;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (outputDistanceShift) {
|
||||||
|
float *pixel = NULL, *pixelsEnd = NULL;
|
||||||
|
switch (mode) {
|
||||||
|
case SINGLE:
|
||||||
|
case PSEUDO:
|
||||||
|
pixel = (float *) sdf;
|
||||||
|
pixelsEnd = pixel+1*sdf.width()*sdf.height();
|
||||||
|
break;
|
||||||
|
case MULTI:
|
||||||
|
pixel = (float *) msdf;
|
||||||
|
pixelsEnd = pixel+3*msdf.width()*msdf.height();
|
||||||
|
break;
|
||||||
|
case MULTI_AND_TRUE:
|
||||||
|
pixel = (float *) mtsdf;
|
||||||
|
pixelsEnd = pixel+4*mtsdf.width()*mtsdf.height();
|
||||||
|
break;
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
while (pixel < pixelsEnd)
|
||||||
|
*pixel++ += outputDistanceShift;
|
||||||
|
}
|
||||||
|
|
||||||
// Save output
|
// Save output
|
||||||
if (shapeExport) {
|
if (shapeExport) {
|
||||||
|
|
@ -904,13 +939,13 @@ int main(int argc, const char * const *argv) {
|
||||||
}
|
}
|
||||||
if (testRenderMulti) {
|
if (testRenderMulti) {
|
||||||
Bitmap<float, 3> render(testWidthM, testHeightM);
|
Bitmap<float, 3> render(testWidthM, testHeightM);
|
||||||
renderSDF(render, sdf, avgScale*range);
|
renderSDF(render, sdf, avgScale*range, .5f+outputDistanceShift);
|
||||||
if (!savePng(render, testRenderMulti))
|
if (!savePng(render, testRenderMulti))
|
||||||
puts("Failed to write test render file.");
|
puts("Failed to write test render file.");
|
||||||
}
|
}
|
||||||
if (testRender) {
|
if (testRender) {
|
||||||
Bitmap<float, 1> render(testWidth, testHeight);
|
Bitmap<float, 1> render(testWidth, testHeight);
|
||||||
renderSDF(render, sdf, avgScale*range);
|
renderSDF(render, sdf, avgScale*range, .5f+outputDistanceShift);
|
||||||
if (!savePng(render, testRender))
|
if (!savePng(render, testRender))
|
||||||
puts("Failed to write test render file.");
|
puts("Failed to write test render file.");
|
||||||
}
|
}
|
||||||
|
|
@ -927,13 +962,13 @@ int main(int argc, const char * const *argv) {
|
||||||
}
|
}
|
||||||
if (testRenderMulti) {
|
if (testRenderMulti) {
|
||||||
Bitmap<float, 3> render(testWidthM, testHeightM);
|
Bitmap<float, 3> render(testWidthM, testHeightM);
|
||||||
renderSDF(render, msdf, avgScale*range);
|
renderSDF(render, msdf, avgScale*range, .5f+outputDistanceShift);
|
||||||
if (!savePng(render, testRenderMulti))
|
if (!savePng(render, testRenderMulti))
|
||||||
puts("Failed to write test render file.");
|
puts("Failed to write test render file.");
|
||||||
}
|
}
|
||||||
if (testRender) {
|
if (testRender) {
|
||||||
Bitmap<float, 1> render(testWidth, testHeight);
|
Bitmap<float, 1> render(testWidth, testHeight);
|
||||||
renderSDF(render, msdf, avgScale*range);
|
renderSDF(render, msdf, avgScale*range, .5f+outputDistanceShift);
|
||||||
if (!savePng(render, testRender))
|
if (!savePng(render, testRender))
|
||||||
ABORT("Failed to write test render file.");
|
ABORT("Failed to write test render file.");
|
||||||
}
|
}
|
||||||
|
|
@ -950,13 +985,13 @@ int main(int argc, const char * const *argv) {
|
||||||
}
|
}
|
||||||
if (testRenderMulti) {
|
if (testRenderMulti) {
|
||||||
Bitmap<float, 4> render(testWidthM, testHeightM);
|
Bitmap<float, 4> render(testWidthM, testHeightM);
|
||||||
renderSDF(render, mtsdf, avgScale*range);
|
renderSDF(render, mtsdf, avgScale*range, .5f+outputDistanceShift);
|
||||||
if (!savePng(render, testRenderMulti))
|
if (!savePng(render, testRenderMulti))
|
||||||
puts("Failed to write test render file.");
|
puts("Failed to write test render file.");
|
||||||
}
|
}
|
||||||
if (testRender) {
|
if (testRender) {
|
||||||
Bitmap<float, 1> render(testWidth, testHeight);
|
Bitmap<float, 1> render(testWidth, testHeight);
|
||||||
renderSDF(render, mtsdf, avgScale*range);
|
renderSDF(render, mtsdf, avgScale*range, .5f+outputDistanceShift);
|
||||||
if (!savePng(render, testRender))
|
if (!savePng(render, testRender))
|
||||||
ABORT("Failed to write test render file.");
|
ABORT("Failed to write test render file.");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue