#include "qjs_staef.h" #include "font.h" #include "qjs_macros.h" #include "HandmadeMath.h" #include "render.h" #include "stb_ds.h" #include "cell.h" #include "qjs_sdl.h" #include // External functions from jsffi.c typedef HMM_Vec4 colorf; extern colorf js2color(JSContext *js, JSValue v); extern JSValue vec22js(JSContext *js, HMM_Vec2 v); extern HMM_Vec2 js2vec2(JSContext *js, JSValue v); extern rect js2rect(JSContext *js, JSValue v); extern double js2number(JSContext *js, JSValue v); extern JSValue number2js(JSContext *js, double g); extern void *js_get_blob_data(JSContext *js, size_t *len, JSValue v); extern JSValue js_new_blob_stoned_copy(JSContext *js, void *data, size_t size); extern JSValue quads_to_mesh(JSContext *js, text_vert *buffer); extern int uncaught_exception(JSContext *js, JSValue ret); // QuickJS class for font QJSCLASS(font,) // Font constructor JSC_CCALL(staef_font_new, size_t len; void *data = js_get_blob_data(js, &len, argv[0]); if (!data) return JS_ThrowReferenceError(js, "could not get array buffer data"); double height = js2number(js, argv[1]); font *f = MakeFont(data, len, (int)height); if (!f) return JS_ThrowReferenceError(js, "could not create font"); ret = font2js(js, f); // Create surface data object for the font's atlas if (f->surface) { JSValue surfData = JS_NewObject(js); JS_SetPropertyStr(js, surfData, "width", JS_NewInt32(js, f->surface->w)); JS_SetPropertyStr(js, surfData, "height", JS_NewInt32(js, f->surface->h)); JS_SetPropertyStr(js, surfData, "format", pixelformat2js(js, f->surface->format)); JS_SetPropertyStr(js, surfData, "pitch", JS_NewInt32(js, f->surface->pitch)); // Lock surface if needed int locked = 0; if (SDL_MUSTLOCK(f->surface)) { if (SDL_LockSurface(f->surface) < 0) return JS_ThrowInternalError(js, "Lock surface failed: %s", SDL_GetError()); locked = 1; } size_t byte_size = f->surface->pitch * f->surface->h; JS_SetPropertyStr(js, surfData, "pixels", js_new_blob_stoned_copy(js, f->surface->pixels, byte_size)); if (locked) SDL_UnlockSurface(f->surface); JS_SetPropertyStr(js, ret, "surface", surfData); } ) // Calculate text size JSC_CCALL(staef_font_text_size, font *f = js2font(js, self); const char *str = JS_ToCString(js, argv[0]); float letterSpacing = argc > 1 ? js2number(js, argv[1]) : 0; float wrap = argc > 2 ? js2number(js, argv[2]) : -1; ret = vec22js(js, measure_text(str, f, letterSpacing, wrap)); JS_FreeCString(js, str); ) // Generate text buffer (mesh data) JSC_CCALL(staef_font_make_text_buffer, font *f = js2font(js, self); const char *s = JS_ToCString(js, argv[0]); rect rectpos = js2rect(js, argv[1]); colorf c = js2color(js, argv[2]); float wrap = argc > 3 ? js2number(js, argv[3]) : -1; HMM_Vec2 startpos = {.x = rectpos.x, .y = rectpos.y }; text_vert *buffer = renderText(s, startpos, f, c, wrap); ret = quads_to_mesh(js, buffer); JS_FreeCString(js, s); arrfree(buffer); ) // Font property getters/setters JSC_GETSET(font, linegap, number) // Font methods static const JSCFunctionListEntry js_font_funcs[] = { MIST_FUNC_DEF(staef_font, text_size, 3), MIST_FUNC_DEF(staef_font, make_text_buffer, 4), CGETSET_ADD(font, linegap), }; // Font constructor function static JSValue js_font_constructor(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv) { return js_staef_font_new(ctx, JS_NULL, argc, argv); } // Initialize the staef module JSValue js_staef_use(JSContext *js) { JSValue mod = JS_NewObject(js); JSValue proto; // Initialize font class JS_NewClassID(&js_font_id); JS_NewClass(JS_GetRuntime(js), js_font_id, &js_font_class); proto = JS_NewObject(js); JS_SetPropertyFunctionList(js, proto, js_font_funcs, countof(js_font_funcs)); JS_SetClassProto(js, js_font_id, proto); // Create font constructor JSValue font_ctor = JS_NewCFunction2(js, js_font_constructor, "font", 2, JS_CFUNC_constructor, 0); JS_SetConstructor(js, font_ctor, proto); // Add font constructor to module (lowercase to match "new staef.font") JS_SetPropertyStr(js, mod, "font", font_ctor); return mod; }