@@ -164,8 +164,10 @@ auto TextRenderer::generate_glyph(FontRuntime &rt, FontData &fd,
|
||||
|
||||
msdfgen::Bitmap<float, 3> msdf_bitmap(bmp_w, bmp_h);
|
||||
msdfgen::Vector2 scale_vec(scale, scale);
|
||||
double const inv_scale = 1.0 / scale;
|
||||
msdfgen::Vector2 translate(
|
||||
-bounds.l * scale + rt.px_range, -bounds.b * scale + rt.px_range);
|
||||
-bounds.l + rt.px_range * inv_scale,
|
||||
-bounds.b + rt.px_range * inv_scale);
|
||||
msdfgen::generateMSDF(msdf_bitmap, shape, rt.px_range, scale_vec, translate);
|
||||
|
||||
std::vector<Color> buffer(static_cast<size_t>(bmp_w) * bmp_h);
|
||||
|
||||
BIN
tools/dump_msdf
Executable file
BIN
tools/dump_msdf
Executable file
Binary file not shown.
85
tools/dump_msdf.cpp
Normal file
85
tools/dump_msdf.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <msdfgen.h>
|
||||
#include <ext/import-font.h>
|
||||
|
||||
static unsigned char clamp_channel(float v) {
|
||||
if (v <= 0.0f) return 0;
|
||||
if (v >= 1.0f) return 255;
|
||||
return static_cast<unsigned char>(std::lround(v * 255.0f));
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 3) {
|
||||
std::fprintf(stderr, "Usage: %s <font-file> <codepoint>\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
const char *fontPath = argv[1];
|
||||
unsigned codepoint = std::strtoul(argv[2], nullptr, 0);
|
||||
auto *ft = msdfgen::initializeFreetype();
|
||||
if (!ft) return 1;
|
||||
auto *font = msdfgen::loadFont(ft, fontPath);
|
||||
if (!font) return 1;
|
||||
msdfgen::Shape shape;
|
||||
double advance = 0.0;
|
||||
if (!msdfgen::loadGlyph(shape, font, msdfgen::GlyphIndex(codepoint), msdfgen::FONT_SCALING_EM_NORMALIZED, &advance)) {
|
||||
std::fprintf(stderr, "Failed to load glyph %u\n", codepoint);
|
||||
return 1;
|
||||
}
|
||||
shape.normalize();
|
||||
msdfgen::edgeColoringSimple(shape, 3.0);
|
||||
auto bounds = shape.getBounds();
|
||||
|
||||
double emScale = 48.0;
|
||||
double pxRange = 4.0;
|
||||
int bmp_w = std::max(1, (int)std::ceil((bounds.r - bounds.l) * emScale + 2.0 * pxRange));
|
||||
int bmp_h = std::max(1, (int)std::ceil((bounds.t - bounds.b) * emScale + 2.0 * pxRange));
|
||||
|
||||
msdfgen::Bitmap<float, 3> bitmap(bmp_w, bmp_h);
|
||||
msdfgen::Vector2 scale(emScale, emScale);
|
||||
msdfgen::Vector2 translate(-bounds.l * emScale + pxRange, -bounds.b * emScale + pxRange);
|
||||
msdfgen::generateMSDF(bitmap, shape, pxRange, scale, translate);
|
||||
|
||||
std::vector<unsigned char> buffer(static_cast<size_t>(bmp_w) * bmp_h * 4);
|
||||
for (int y = 0; y < bmp_h; ++y) {
|
||||
int dst_y = bmp_h - 1 - y;
|
||||
for (int x = 0; x < bmp_w; ++x) {
|
||||
const float *px = bitmap(x, y);
|
||||
size_t idx = (static_cast<size_t>(dst_y) * bmp_w + x) * 4;
|
||||
buffer[idx + 0] = clamp_channel(px[0]);
|
||||
buffer[idx + 1] = clamp_channel(px[1]);
|
||||
buffer[idx + 2] = clamp_channel(px[2]);
|
||||
buffer[idx + 3] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
int minX = bmp_w, minY = bmp_h, maxX = -1, maxY = -1;
|
||||
for (int y = 0; y < bmp_h; ++y) {
|
||||
for (int x = 0; x < bmp_w; ++x) {
|
||||
size_t idx = (static_cast<size_t>(y) * bmp_w + x) * 4;
|
||||
unsigned char r = buffer[idx];
|
||||
unsigned char g = buffer[idx + 1];
|
||||
unsigned char b = buffer[idx + 2];
|
||||
bool interesting = !(r == 0 && g == 0 && b == 0) && !(r == 255 && g == 255 && b == 255);
|
||||
if (interesting) {
|
||||
if (x < minX) minX = x;
|
||||
if (x > maxX) maxX = x;
|
||||
if (y < minY) minY = y;
|
||||
if (y > maxY) maxY = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::printf("bmp %dx%d\n", bmp_w, bmp_h);
|
||||
if (maxX >= minX && maxY >= minY) {
|
||||
std::printf("interesting bbox: x=[%d,%d] y=[%d,%d]\n", minX, maxX, minY, maxY);
|
||||
}
|
||||
|
||||
msdfgen::destroyFont(font);
|
||||
msdfgen::deinitializeFreetype(ft);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user