FREETYPEEEEEE

This commit is contained in:
2026-03-05 02:31:31 -05:00
parent fb358e3c4b
commit 6c43a29f9f
293 changed files with 153022 additions and 262 deletions

203
build.c
View File

@@ -36,6 +36,63 @@ static const char *lunasvg_sources[] = {
"vendor/lunasvg/source/svgtextelement.cpp",
};
////////////////////////////////
// FreeType source files
static const char *freetype_sources[] = {
"vendor/freetype/src/base/ftsystem.c",
"vendor/freetype/src/base/ftinit.c",
"vendor/freetype/src/base/ftdebug.c",
"vendor/freetype/src/base/ftbase.c",
"vendor/freetype/src/base/ftbbox.c",
"vendor/freetype/src/base/ftglyph.c",
"vendor/freetype/src/base/ftbitmap.c",
"vendor/freetype/src/base/ftmm.c",
"vendor/freetype/src/truetype/truetype.c",
"vendor/freetype/src/sfnt/sfnt.c",
"vendor/freetype/src/smooth/smooth.c",
"vendor/freetype/src/autofit/autofit.c",
"vendor/freetype/src/psnames/psnames.c",
"vendor/freetype/src/pshinter/pshinter.c",
"vendor/freetype/src/gzip/ftgzip.c",
};
////////////////////////////////
// Font embedding — reads a .ttf and writes a C header with the data as a byte array
static bool embed_font_file(const char *ttf_path, const char *header_path) {
if (!nob_needs_rebuild1(header_path, ttf_path)) {
nob_log(NOB_INFO, "Font header %s is up to date", header_path);
return true;
}
Nob_String_Builder sb = {0};
if (!nob_read_entire_file(ttf_path, &sb)) return false;
FILE *out = fopen(header_path, "wb");
if (!out) {
nob_log(NOB_ERROR, "Could not open %s for writing", header_path);
nob_sb_free(sb);
return false;
}
fprintf(out, "// Auto-generated from %s — do not edit\n", ttf_path);
fprintf(out, "#pragma once\n\n");
fprintf(out, "static const unsigned char font_inter_data[] = {\n");
for (size_t i = 0; i < sb.count; i++) {
if (i % 16 == 0) fprintf(out, " ");
fprintf(out, "0x%02x,", (unsigned char)sb.items[i]);
if (i % 16 == 15 || i == sb.count - 1) fprintf(out, "\n");
}
fprintf(out, "};\n\n");
fprintf(out, "static const unsigned int font_inter_size = %zu;\n", sb.count);
fclose(out);
nob_sb_free(sb);
nob_log(NOB_INFO, "Generated %s (%zu bytes)", header_path, sb.count);
return true;
}
#ifdef __APPLE__
////////////////////////////////
// macOS build (clang++ with Objective-C++)
@@ -47,9 +104,7 @@ static const char *frameworks[] = {
"-framework", "AudioToolbox",
"-framework", "CoreMIDI",
"-framework", "QuartzCore",
"-framework", "CoreText",
"-framework", "CoreFoundation",
"-framework", "CoreGraphics",
};
static bool build_lunasvg_lib(const char *build_dir, bool debug) {
@@ -174,6 +229,74 @@ static bool build_lunasvg_lib(const char *build_dir, bool debug) {
return true;
}
static bool build_freetype_lib(const char *build_dir, bool debug) {
const char *obj_dir = nob_temp_sprintf("%s/freetype_obj", build_dir);
const char *lib_path = nob_temp_sprintf("%s/libfreetype.a", build_dir);
if (!nob_needs_rebuild(lib_path, freetype_sources, NOB_ARRAY_LEN(freetype_sources))) {
nob_log(NOB_INFO, "freetype is up to date");
return true;
}
if (!nob_mkdir_if_not_exists(obj_dir)) return false;
for (size_t i = 0; i < NOB_ARRAY_LEN(freetype_sources); i++) {
const char *src = freetype_sources[i];
const char *base = strrchr(src, '/');
base = base ? base + 1 : src;
char obj_name[256];
snprintf(obj_name, sizeof(obj_name), "%s", base);
char *dot = strrchr(obj_name, '.');
if (dot) { dot[1] = 'o'; dot[2] = '\0'; }
const char *obj_path = nob_temp_sprintf("%s/%s", obj_dir, obj_name);
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, "clang");
nob_cmd_append(&cmd, "-std=c11", "-c");
nob_cmd_append(&cmd, "-DFT2_BUILD_LIBRARY");
nob_cmd_append(&cmd, "-Ivendor/freetype/include");
nob_cmd_append(&cmd, "-Wall", "-Wno-unused-function", "-Wno-unused-parameter");
if (debug) {
nob_cmd_append(&cmd, "-g", "-O0");
} else {
nob_cmd_append(&cmd, "-O2");
}
nob_cmd_append(&cmd, "-o", obj_path);
nob_cmd_append(&cmd, src);
Nob_Cmd_Opt copt = {0};
if (!nob_cmd_run_opt(&cmd, copt)) return false;
}
// Archive
{
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, "ar", "rcs", lib_path);
for (size_t i = 0; i < NOB_ARRAY_LEN(freetype_sources); i++) {
const char *src = freetype_sources[i];
const char *base = strrchr(src, '/');
base = base ? base + 1 : src;
char obj_name[256];
snprintf(obj_name, sizeof(obj_name), "%s", base);
char *dot = strrchr(obj_name, '.');
if (dot) { dot[1] = 'o'; dot[2] = '\0'; }
nob_cmd_append(&cmd, nob_temp_sprintf("%s/%s", obj_dir, obj_name));
}
Nob_Cmd_Opt copt = {0};
if (!nob_cmd_run_opt(&cmd, copt)) return false;
}
// Clean up obj dir
{
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, "rm", "-rf", obj_dir);
Nob_Cmd_Opt copt = {0};
nob_cmd_run_opt(&cmd, copt);
}
nob_log(NOB_INFO, "Built %s", lib_path);
return true;
}
int main(int argc, char **argv) {
NOB_GO_REBUILD_URSELF(argc, argv);
@@ -207,8 +330,15 @@ int main(int argc, char **argv) {
if (!nob_mkdir_if_not_exists(macos_dir)) return 1;
if (!nob_mkdir_if_not_exists(res_dir)) return 1;
// Build lunasvg static library
// Build static libraries
if (!build_lunasvg_lib(build_dir, debug)) return 1;
if (!build_freetype_lib(build_dir, debug)) return 1;
// Generate embedded font header
const char *gen_dir = nob_temp_sprintf("%s/generated", build_dir);
if (!nob_mkdir_if_not_exists(gen_dir)) return 1;
if (!embed_font_file("assets/fonts/Inter-Regular.ttf",
nob_temp_sprintf("%s/font_inter.h", gen_dir))) return 1;
// Unity build: single clang++ invocation compiles main.cpp (which #includes everything)
{
@@ -220,6 +350,8 @@ int main(int argc, char **argv) {
nob_cmd_append(&cmd, "-Wno-deprecated-declarations");
nob_cmd_append(&cmd, "-Isrc", "-Ivendor/clay");
nob_cmd_append(&cmd, "-Ivendor/lunasvg/include");
nob_cmd_append(&cmd, "-Ivendor/freetype/include");
nob_cmd_append(&cmd, nob_temp_sprintf("-I%s", build_dir));
nob_cmd_append(&cmd, "-DLUNASVG_BUILD_STATIC");
if (debug) {
@@ -234,6 +366,7 @@ int main(int argc, char **argv) {
// Reset language mode so .a is treated as a library, not source
nob_cmd_append(&cmd, "-x", "none");
nob_cmd_append(&cmd, nob_temp_sprintf("%s/liblunasvg.a", build_dir));
nob_cmd_append(&cmd, nob_temp_sprintf("%s/libfreetype.a", build_dir));
{
size_t i;
@@ -405,6 +538,58 @@ static bool build_lunasvg_lib(const char *build_dir, bool debug) {
return true;
}
static bool build_freetype_lib(const char *build_dir, bool debug) {
const char *obj_dir = nob_temp_sprintf("%s\\freetype_obj", build_dir);
const char *lib_path = nob_temp_sprintf("%s\\freetype.lib", build_dir);
if (!nob_needs_rebuild(lib_path, freetype_sources, NOB_ARRAY_LEN(freetype_sources))) {
nob_log(NOB_INFO, "freetype is up to date");
return true;
}
if (!nob_mkdir_if_not_exists(obj_dir)) return false;
for (size_t i = 0; i < NOB_ARRAY_LEN(freetype_sources); i++) {
const char *src = freetype_sources[i];
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, "cl.exe", "/nologo", "/c");
nob_cmd_append(&cmd, "/std:c11");
nob_cmd_append(&cmd, "/DFT2_BUILD_LIBRARY");
nob_cmd_append(&cmd, "/Ivendor/freetype/include");
nob_cmd_append(&cmd, "/W3");
if (debug) {
nob_cmd_append(&cmd, "/MTd", "/Zi", "/Od");
} else {
nob_cmd_append(&cmd, "/MT", "/O2");
}
nob_cmd_append(&cmd, nob_temp_sprintf("/Fo:%s/", obj_dir));
nob_cmd_append(&cmd, src);
Nob_Cmd_Opt copt = {0};
if (!nob_cmd_run_opt(&cmd, copt)) return false;
}
// Archive
{
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, "lib.exe", "/nologo", nob_temp_sprintf("/OUT:%s", lib_path));
nob_cmd_append(&cmd, nob_temp_sprintf("%s/*.obj", obj_dir));
Nob_Cmd_Opt copt = {0};
if (!nob_cmd_run_opt(&cmd, copt)) return false;
}
// Clean up obj dir
{
Nob_Cmd cmd = {0};
nob_cmd_append(&cmd, "cmd.exe", "/c",
nob_temp_sprintf("if exist %s rmdir /s /q %s", obj_dir, obj_dir));
Nob_Cmd_Opt copt = {0};
nob_cmd_run_opt(&cmd, copt);
}
nob_log(NOB_INFO, "Built %s", lib_path);
return true;
}
int main(int argc, char **argv) {
NOB_GO_REBUILD_URSELF(argc, argv);
@@ -428,8 +613,15 @@ int main(int argc, char **argv) {
if (!nob_mkdir_if_not_exists(build_dir)) return 1;
// Build lunasvg static library
// Build static libraries
if (!build_lunasvg_lib(build_dir, debug)) return 1;
if (!build_freetype_lib(build_dir, debug)) return 1;
// Generate embedded font header
const char *gen_dir = nob_temp_sprintf("%s\\generated", build_dir);
if (!nob_mkdir_if_not_exists(gen_dir)) return 1;
if (!embed_font_file("assets/fonts/Inter-Regular.ttf",
nob_temp_sprintf("%s\\font_inter.h", gen_dir))) return 1;
// Unity build: single cl.exe invocation compiles main.cpp (which #includes everything)
{
@@ -438,6 +630,8 @@ int main(int argc, char **argv) {
nob_cmd_append(&cmd, "/nologo", "/std:c++20", "/EHsc", "/W3");
nob_cmd_append(&cmd, "/Isrc", "/Ivendor/clay");
nob_cmd_append(&cmd, "/Ivendor/lunasvg/include");
nob_cmd_append(&cmd, "/Ivendor/freetype/include");
nob_cmd_append(&cmd, nob_temp_sprintf("/I%s", build_dir));
nob_cmd_append(&cmd, "/DLUNASVG_BUILD_STATIC");
if (debug) {
@@ -458,6 +652,7 @@ int main(int argc, char **argv) {
nob_cmd_append(&cmd, nob_temp_sprintf("/PDB:%s/autosample.pdb", build_dir));
nob_cmd_append(&cmd, "/DEBUG");
nob_cmd_append(&cmd, nob_temp_sprintf("%s/lunasvg.lib", build_dir));
nob_cmd_append(&cmd, nob_temp_sprintf("%s/freetype.lib", build_dir));
{
size_t i;
for (i = 0; i < NOB_ARRAY_LEN(link_libs); i++)