#include "api.h" #include "data/rasterizer.h" #include "data/image.h" #include "util.h" #include uint32_t luax_checkcodepoint(lua_State* L, int index) { size_t length; const char* str; uint32_t codepoint; switch (lua_type(L, index)) { case LUA_TSTRING: str = lua_tolstring(L, index, &length); return utf8_decode(str, str + length, &codepoint) ? codepoint : 0; case LUA_TNUMBER: return luax_checku32(L, index); default: return luax_typeerror(L, index, "string or number"), 0; } } static int l_lovrRasterizerGetFontSize(lua_State* L) { Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer); float size = lovrRasterizerGetFontSize(rasterizer); lua_pushnumber(L, size); return 1; } static int l_lovrRasterizerGetGlyphCount(lua_State* L) { Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer); uint32_t count = lovrRasterizerGetGlyphCount(rasterizer); lua_pushinteger(L, count); return 1; } static int l_lovrRasterizerHasGlyphs(lua_State* L) { Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer); for (int i = 2; i <= lua_gettop(L); i++) { size_t length; const char* str; switch (lua_type(L, i)) { case LUA_TSTRING: str = lua_tolstring(L, i, &length); if (!lovrRasterizerHasGlyphs(rasterizer, str, length)) { lua_pushboolean(L, false); return 1; } break; case LUA_TNUMBER: if (!lovrRasterizerHasGlyph(rasterizer, luax_checku32(L, i))) { lua_pushboolean(L, false); return 1; } break; default: return luax_typeerror(L, i, "string or number"); } } lua_pushboolean(L, true); return 1; } static int l_lovrRasterizerGetAscent(lua_State* L) { Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer); float ascent = lovrRasterizerGetAscent(rasterizer); lua_pushnumber(L, ascent); return 1; } static int l_lovrRasterizerGetDescent(lua_State* L) { Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer); float descent = lovrRasterizerGetDescent(rasterizer); lua_pushnumber(L, descent); return 1; } static int l_lovrRasterizerGetLeading(lua_State* L) { Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer); float leading = lovrRasterizerGetLeading(rasterizer); lua_pushnumber(L, leading); return 1; } static int l_lovrRasterizerGetAdvance(lua_State* L) { Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer); uint32_t codepoint = luax_checkcodepoint(L, 2); float advance = lovrRasterizerGetAdvance(rasterizer, codepoint); lua_pushnumber(L, advance); return 1; } static int l_lovrRasterizerGetBearing(lua_State* L) { Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer); uint32_t codepoint = luax_checkcodepoint(L, 2); float bearing = lovrRasterizerGetBearing(rasterizer, codepoint); lua_pushnumber(L, bearing); return 1; } static int l_lovrRasterizerGetKerning(lua_State* L) { Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer); uint32_t first = luax_checkcodepoint(L, 2); uint32_t second = luax_checkcodepoint(L, 3); float kerning = lovrRasterizerGetKerning(rasterizer, first, second); lua_pushnumber(L, kerning); return 1; } static void luax_getboundingbox(lua_State* L, int index, Rasterizer* rasterizer, float box[4]) { if (lua_isnoneornil(L, index)) { lovrRasterizerGetBoundingBox(rasterizer, box); } else { uint32_t codepoint = luax_checkcodepoint(L, index); lovrRasterizerGetGlyphBoundingBox(rasterizer, codepoint, box); } } static int l_lovrRasterizerGetWidth(lua_State* L) { Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer); float box[4]; luax_getboundingbox(L, 2, rasterizer, box); lua_pushnumber(L, box[2] - box[0]); return 1; } static int l_lovrRasterizerGetHeight(lua_State* L) { Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer); float box[4]; luax_getboundingbox(L, 2, rasterizer, box); lua_pushnumber(L, box[3] - box[1]); return 1; } static int l_lovrRasterizerGetDimensions(lua_State* L) { Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer); float box[4]; luax_getboundingbox(L, 2, rasterizer, box); lua_pushnumber(L, box[2] - box[0]); lua_pushnumber(L, box[3] - box[1]); return 2; } static int l_lovrRasterizerGetBoundingBox(lua_State* L) { Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer); float box[4]; luax_getboundingbox(L, 2, rasterizer, box); lua_pushnumber(L, box[0]); lua_pushnumber(L, box[1]); lua_pushnumber(L, box[2]); lua_pushnumber(L, box[3]); return 4; } static void onCurve2D(void* context, uint32_t degree, float* points) { lua_State* L = context; uint32_t count = (degree + 1) * 2; lua_createtable(L, count, 0); for (uint32_t i = 0; i < count; i++) { lua_pushnumber(L, points[i]); lua_rawseti(L, -2, i + 1); } lua_rawseti(L, -2, luax_len(L, -2) + 1); } static void onCurve3D(void* context, uint32_t degree, float* points) { lua_State* L = context; lua_createtable(L, (degree + 1) * 3, 0); for (uint32_t i = 0; i < degree + 1; i++) { lua_pushnumber(L, points[2 * i + 0]); lua_rawseti(L, -2, 3 * i + 1); lua_pushnumber(L, points[2 * i + 1]); lua_rawseti(L, -2, 3 * i + 2); lua_pushnumber(L, 0.); lua_rawseti(L, -2, 3 * i + 3); } lua_rawseti(L, -2, luax_len(L, -2) + 1); } static int l_lovrRasterizerGetCurves(lua_State* L) { Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer); uint32_t codepoint = luax_checkcodepoint(L, 2); bool three = lua_toboolean(L, 3); lua_newtable(L); lovrRasterizerGetCurves(rasterizer, codepoint, three ? onCurve3D : onCurve2D, L); return 1; } static int l_lovrRasterizerNewImage(lua_State* L) { Rasterizer* rasterizer = luax_checktype(L, 1, Rasterizer); uint32_t codepoint = luax_checkcodepoint(L, 2); double spread = luaL_optnumber(L, 3, 4.); uint32_t padding = (uint32_t) ceil(spread / 2.); float box[4]; lovrRasterizerGetGlyphBoundingBox(rasterizer, codepoint, box); uint32_t width = 2 * padding + (uint32_t) ceilf(box[2] - box[0]); uint32_t height = 2 * padding + (uint32_t) ceilf(box[3] - box[1]); Image* image = lovrImageCreateRaw(width, height, FORMAT_RGBA32F, false); void* pixels = lovrImageGetLayerData(image, 0, 0); lovrRasterizerGetPixels(rasterizer, codepoint, pixels, width, height, spread); luax_pushtype(L, Image, image); lovrRelease(image, lovrImageDestroy); return 1; } const luaL_Reg lovrRasterizer[] = { { "getFontSize", l_lovrRasterizerGetFontSize }, { "getGlyphCount", l_lovrRasterizerGetGlyphCount }, { "hasGlyphs", l_lovrRasterizerHasGlyphs }, { "getAscent", l_lovrRasterizerGetAscent }, { "getDescent", l_lovrRasterizerGetDescent }, { "getLeading", l_lovrRasterizerGetLeading }, { "getAdvance", l_lovrRasterizerGetAdvance }, { "getBearing", l_lovrRasterizerGetBearing }, { "getKerning", l_lovrRasterizerGetKerning }, { "getWidth", l_lovrRasterizerGetWidth }, { "getHeight", l_lovrRasterizerGetHeight }, { "getDimensions", l_lovrRasterizerGetDimensions }, { "getBoundingBox", l_lovrRasterizerGetBoundingBox }, { "getCurves", l_lovrRasterizerGetCurves }, { "newImage", l_lovrRasterizerNewImage }, { NULL, NULL } };