174 lines
4.6 KiB
C
174 lines
4.6 KiB
C
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <ft2build.h>
|
|
#include <stdio.h>
|
|
#include FT_FREETYPE_H
|
|
#include <string.h>
|
|
#include <strings.h>
|
|
#include <ctype.h>
|
|
|
|
#define N_CHARS 128
|
|
|
|
#define round_up_26_6(val) (((val) + 63) >> 6u)
|
|
|
|
int max_advance;
|
|
int max_top = -9999;
|
|
int min_bottom = 9999;
|
|
int line_height;
|
|
int baseline_offset;
|
|
|
|
typedef struct {
|
|
int width;
|
|
int height;
|
|
int top;
|
|
int left;
|
|
uint8_t * bitmap;
|
|
} char_info_t;
|
|
|
|
static char_info_t char_infos[N_CHARS];
|
|
|
|
static void load_char(FT_Face face, int char_code)
|
|
{
|
|
if (FT_Load_Char(face, char_code, FT_LOAD_RENDER) != 0)
|
|
{
|
|
return;
|
|
}
|
|
int advance = round_up_26_6(face->glyph->advance.x);
|
|
if (advance > max_advance)
|
|
{
|
|
max_advance = advance;
|
|
}
|
|
if ((face->glyph->bitmap.width == 0) ||
|
|
(face->glyph->bitmap.rows == 0))
|
|
{
|
|
return;
|
|
}
|
|
char_infos[char_code].width = face->glyph->bitmap.width;
|
|
char_infos[char_code].height = face->glyph->bitmap.rows;
|
|
char_infos[char_code].top = face->glyph->bitmap_top;
|
|
if (char_infos[char_code].top > max_top)
|
|
{
|
|
max_top = char_infos[char_code].top;
|
|
}
|
|
int bottom = char_infos[char_code].top - char_infos[char_code].height;
|
|
if (bottom < min_bottom)
|
|
{
|
|
min_bottom = bottom;
|
|
}
|
|
char_infos[char_code].left = face->glyph->bitmap_left;
|
|
char_infos[char_code].bitmap = malloc(char_infos[char_code].width * char_infos[char_code].height);
|
|
memcpy(char_infos[char_code].bitmap,
|
|
face->glyph->bitmap.buffer,
|
|
char_infos[char_code].width * char_infos[char_code].height);
|
|
}
|
|
|
|
static void generate_bytes(FILE * file, const uint8_t * bytes, int count)
|
|
{
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
if (i % 8 == 0)
|
|
{
|
|
fprintf(file, " ");
|
|
}
|
|
fprintf(file, "0x%02xu,", bytes[i]);
|
|
if ((i + 1) % 8 == 0)
|
|
{
|
|
fprintf(file, "\n");
|
|
}
|
|
else if (i < (count - 1))
|
|
{
|
|
fprintf(file, " ");
|
|
}
|
|
}
|
|
if (count % 8 != 0)
|
|
{
|
|
fprintf(file, "\n");
|
|
}
|
|
}
|
|
|
|
static void generate(const char * d_file_name)
|
|
{
|
|
FILE * fh = fopen(d_file_name, "wb");
|
|
fprintf(fh, "module hulk.kfont;\n");
|
|
fprintf(fh, "struct CharInfo {\n");
|
|
fprintf(fh, " uint width;\n");
|
|
fprintf(fh, " uint height;\n");
|
|
fprintf(fh, " int top;\n");
|
|
fprintf(fh, " int left;\n");
|
|
fprintf(fh, " const ubyte[] bitmap;\n");
|
|
fprintf(fh, "};\n");
|
|
fprintf(fh, "struct FontInfo {\n");
|
|
fprintf(fh, " uint line_height;\n");
|
|
fprintf(fh, " uint advance;\n");
|
|
fprintf(fh, " int baseline_offset;\n");
|
|
fprintf(fh, " const CharInfo[] chars;\n");
|
|
fprintf(fh, "};\n");
|
|
fprintf(fh, "__gshared const FontInfo Kfont = {\n");
|
|
fprintf(fh, " %du,\n", line_height);
|
|
fprintf(fh, " %du,\n", max_advance);
|
|
fprintf(fh, " %d,\n", baseline_offset);
|
|
fprintf(fh, " [\n");
|
|
for (int i = 0; i < N_CHARS; i++)
|
|
{
|
|
fprintf(fh, " CharInfo(\n");
|
|
fprintf(fh, " %du,\n", char_infos[i].width);
|
|
fprintf(fh, " %du,\n", char_infos[i].height);
|
|
fprintf(fh, " %d,\n", char_infos[i].top);
|
|
fprintf(fh, " %d,\n", char_infos[i].left);
|
|
if (char_infos[i].width > 0)
|
|
{
|
|
fprintf(fh, " [\n");
|
|
generate_bytes(fh, char_infos[i].bitmap, char_infos[i].width * char_infos[i].height);
|
|
fprintf(fh, " ]\n");
|
|
}
|
|
else
|
|
{
|
|
fprintf(fh, " []\n");
|
|
}
|
|
fprintf(fh, " ),\n");
|
|
}
|
|
fprintf(fh, " ],\n");
|
|
fprintf(fh, "};\n");
|
|
fclose(fh);
|
|
}
|
|
|
|
int main(int argc, char * argv[])
|
|
{
|
|
/* Expect: font file, size, out file */
|
|
if (argc != 4)
|
|
{
|
|
fprintf(stderr, "Incorrect arguments\n");
|
|
return 1;
|
|
}
|
|
const char * font_file = argv[1];
|
|
int size = atoi(argv[2]);
|
|
const char * out_file = argv[3];
|
|
|
|
FT_Library ft_library;
|
|
if (FT_Init_FreeType(&ft_library) != 0)
|
|
{
|
|
fprintf(stderr, "Could not initialize freetype\n");
|
|
return 2;
|
|
}
|
|
|
|
FT_Face face;
|
|
if (FT_New_Face(ft_library, font_file, 0, &face) != 0)
|
|
{
|
|
fprintf(stderr, "Could not open %s\n", font_file);
|
|
return 3;
|
|
}
|
|
|
|
FT_Set_Pixel_Sizes(face, 0, size);
|
|
|
|
for (int i = 0; i < N_CHARS; i++)
|
|
{
|
|
load_char(face, i);
|
|
}
|
|
line_height = round_up_26_6(face->size->metrics.height);
|
|
baseline_offset = (line_height - (max_top - min_bottom)) / 2 - min_bottom;
|
|
|
|
generate(out_file);
|
|
|
|
return 0;
|
|
}
|