Files
waylight/tools/dump_msdf.cpp
Slendi 9268380fd9 progres
Signed-off-by: Slendi <slendi@socopon.com>
2025-10-05 08:22:47 +03:00

86 lines
3.0 KiB
C++

#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;
}