#include #include #include #include "api.h" #include "../renderer.h" #include "../rencache.h" #ifdef PRAGTICAL_USE_SDL_RENDERER #include "../renwindow.h" #endif #include "lua.h" // a reference index to a table that stores the fonts static int RENDERER_FONT_REF = LUA_NOREF; static int font_get_options( lua_State *L, ERenFontAntialiasing *antialiasing, ERenFontHinting *hinting, int *style ) { if (lua_gettop(L) > 2 && lua_istable(L, 3)) { lua_getfield(L, 3, "antialiasing"); if (lua_isstring(L, -1)) { const char *antialiasing_str = lua_tostring(L, -1); if (antialiasing_str) { if (strcmp(antialiasing_str, "none") == 0) { *antialiasing = FONT_ANTIALIASING_NONE; } else if (strcmp(antialiasing_str, "grayscale") == 0) { *antialiasing = FONT_ANTIALIASING_GRAYSCALE; } else if (strcmp(antialiasing_str, "subpixel") == 0) { *antialiasing = FONT_ANTIALIASING_SUBPIXEL; } else { return luaL_error( L, "error in font options, unknown antialiasing option: \"%s\"", antialiasing_str ); } } } lua_getfield(L, 3, "hinting"); if (lua_isstring(L, -1)) { const char *hinting_str = lua_tostring(L, -1); if (hinting_str) { if (strcmp(hinting_str, "slight") == 0) { *hinting = FONT_HINTING_SLIGHT; } else if (strcmp(hinting_str, "none") == 0) { *hinting = FONT_HINTING_NONE; } else if (strcmp(hinting_str, "full") == 0) { *hinting = FONT_HINTING_FULL; } else { return luaL_error( L, "error in font options, unknown hinting option: \"%s\"", hinting ); } } } int style_local = 0; lua_getfield(L, 3, "italic"); if (lua_toboolean(L, -1)) style_local |= FONT_STYLE_ITALIC; lua_getfield(L, 3, "bold"); if (lua_toboolean(L, -1)) style_local |= FONT_STYLE_BOLD; lua_getfield(L, 3, "underline"); if (lua_toboolean(L, -1)) style_local |= FONT_STYLE_UNDERLINE; lua_getfield(L, 3, "smoothing"); if (lua_toboolean(L, -1)) style_local |= FONT_STYLE_SMOOTH; lua_getfield(L, 3, "strikethrough"); if (lua_toboolean(L, -1)) style_local |= FONT_STYLE_STRIKETHROUGH; lua_pop(L, 5); if (style_local != 0) *style = style_local; } return 0; } static int f_font_load(lua_State *L) { const char *filename = luaL_checkstring(L, 1); float size = luaL_checknumber(L, 2); int style = 0; ERenFontHinting hinting = FONT_HINTING_SLIGHT; ERenFontAntialiasing antialiasing = FONT_ANTIALIASING_SUBPIXEL; int ret_code = font_get_options(L, &antialiasing, &hinting, &style); if (ret_code > 0) return ret_code; RenFont** font = lua_newuserdata(L, sizeof(RenFont*)); *font = ren_font_load(filename, size, antialiasing, hinting, style); if (!*font) return luaL_error(L, "failed to load font: %s", SDL_GetError()); luaL_setmetatable(L, API_TYPE_FONT); return 1; } static bool font_retrieve(lua_State* L, RenFont** fonts, int idx) { bool is_table; memset(fonts, 0, sizeof(RenFont*)*FONT_FALLBACK_MAX); if (lua_type(L, idx) != LUA_TTABLE) { fonts[0] = *(RenFont**)luaL_checkudata(L, idx, API_TYPE_FONT); is_table = false; } else { is_table = true; int len = luaL_len(L, idx); len = len > FONT_FALLBACK_MAX ? FONT_FALLBACK_MAX : len; for (int i = 0; i < len; i++) { lua_rawgeti(L, idx, i+1); fonts[i] = *(RenFont**) luaL_checkudata(L, -1, API_TYPE_FONT); lua_pop(L, 1); } } #ifdef PRAGTICAL_USE_SDL_RENDERER update_font_scale(ren_get_target_window(), fonts); #endif return is_table; } static int f_font_copy(lua_State *L) { RenFont* fonts[FONT_FALLBACK_MAX]; bool table = font_retrieve(L, fonts, 1); float size = lua_gettop(L) >= 2 ? luaL_checknumber(L, 2) : ren_font_group_get_height(fonts); int style = -1; ERenFontHinting hinting = -1; ERenFontAntialiasing antialiasing = -1; int ret_code = font_get_options(L, &antialiasing, &hinting, &style); if (ret_code > 0) return ret_code; if (table) { lua_newtable(L); luaL_setmetatable(L, API_TYPE_FONT); } for (int i = 0; i < FONT_FALLBACK_MAX && fonts[i]; ++i) { RenFont** font = lua_newuserdata(L, sizeof(RenFont*)); *font = ren_font_copy(fonts[i], size, antialiasing, hinting, style); if (!*font) return luaL_error(L, "failed to copy font: %s", SDL_GetError()); luaL_setmetatable(L, API_TYPE_FONT); if (table) lua_rawseti(L, -2, i+1); } return 1; } static int f_font_group(lua_State* L) { int table_size; luaL_checktype(L, 1, LUA_TTABLE); table_size = lua_rawlen(L, 1); if (table_size <= 0) return luaL_error(L, "failed to create font group: table is empty"); if (table_size > FONT_FALLBACK_MAX) return luaL_error(L, "failed to create font group: table size too large"); // we also need to ensure that there are no fontgroups inside it for (int i = 1; i <= table_size; i++) { if (lua_rawgeti(L, 1, i) != LUA_TUSERDATA) return luaL_typeerror(L, -1, API_TYPE_FONT "(userdata)"); lua_pop(L, 1); } luaL_setmetatable(L, API_TYPE_FONT); return 1; } static int f_font_get_path(lua_State *L) { RenFont* fonts[FONT_FALLBACK_MAX]; bool table = font_retrieve(L, fonts, 1); if (table) { lua_newtable(L); } for (int i = 0; i < FONT_FALLBACK_MAX && fonts[i]; ++i) { const char* path = ren_font_get_path(fonts[i]); lua_pushstring(L, path); if (table) lua_rawseti(L, -2, i+1); } return 1; } static int f_font_set_tab_size(lua_State *L) { RenFont* fonts[FONT_FALLBACK_MAX]; font_retrieve(L, fonts, 1); int n = luaL_checknumber(L, 2); ren_font_group_set_tab_size(fonts, n); return 0; } static int f_font_gc(lua_State *L) { if (lua_istable(L, 1)) return 0; // do not run if its FontGroup RenFont** self = luaL_checkudata(L, 1, API_TYPE_FONT); ren_font_free(*self); return 0; } static RenTab checktab(lua_State *L, int idx) { RenTab tab = {.offset = NAN}; if (lua_isnoneornil(L, idx)) { return tab; } luaL_checktype(L, idx, LUA_TTABLE); if (lua_getfield(L, idx, "tab_offset") == LUA_TNIL) { return tab; } tab.offset = luaL_checknumber(L, -1); return tab; } static int f_font_get_width(lua_State *L) { RenFont* fonts[FONT_FALLBACK_MAX]; font_retrieve(L, fonts, 1); size_t len; const char *text = luaL_checklstring(L, 2, &len); RenTab tab = checktab(L, 3); lua_pushnumber(L, ren_font_group_get_width(fonts, text, len, tab, NULL)); return 1; } static int f_font_get_height(lua_State *L) { RenFont* fonts[FONT_FALLBACK_MAX]; font_retrieve(L, fonts, 1); lua_pushnumber(L, ren_font_group_get_height(fonts)); return 1; } static int f_font_get_size(lua_State *L) { RenFont* fonts[FONT_FALLBACK_MAX]; font_retrieve(L, fonts, 1); lua_pushnumber(L, ren_font_group_get_size(fonts)); return 1; } static int f_font_set_size(lua_State *L) { RenFont* fonts[FONT_FALLBACK_MAX]; font_retrieve(L, fonts, 1); float size = luaL_checknumber(L, 2); double scale = 1.0; #ifdef PRAGTICAL_USE_SDL_RENDERER RenWindow *window = ren_get_target_window(); if (window != NULL) { scale = renwin_get_surface(window).scale_x; } #endif ren_font_group_set_size(fonts, size, scale); return 0; } static int f_font_get_metadata(lua_State *L) { const char* filenames[FONT_FALLBACK_MAX]; int fonts_found = 0; bool table = false; if (lua_type(L, 1) == LUA_TSTRING) { fonts_found = 1; filenames[0] = luaL_checkstring(L, 1); } else { RenFont* fonts[FONT_FALLBACK_MAX]; table = font_retrieve(L, fonts, 1); if (table) lua_newtable(L); for (int i = 0; i < FONT_FALLBACK_MAX && fonts[i]; ++i) { filenames[i] = ren_font_get_path(fonts[i]); fonts_found++; } } int ret_count = 1; for(int f=0; f 0) || fonts_found > 1) { int meta_idx = table ? 3 : 2; lua_newtable(L); for (int i=0; i