/* ** Lua eXtended draw library */ #define lxdrawlib_c #define LUA_LIB #include #include #include #include #include #include #include #include #include #include #include "lxlib.h" typedef struct { font_t *font; } drawlib_font; #define FONT "lx.draw.font" typedef struct { fb_t *fb; fb_region_t subregion; bool has_subregion; } drawlib_surface; #define SURFACE "lx.draw.surface" // ==================================================================== // FONTS static int draw_load_bitmap_font(lua_State *L) { const char* name = luaL_checkstring(L, 1); font_t *f = g_load_ascii_bitmap_font(name); if (f == NULL) { lua_pushnil(L); return 1; } drawlib_font *ff = (drawlib_font*)lua_newuserdata(L, sizeof(drawlib_font)); luaL_getmetatable(L, FONT); lua_setmetatable(L, -2); ff->font = f; return 1; } static int draw_load_ttf_font(lua_State *L) { const char* name = luaL_checkstring(L, 1); font_t *f = g_load_ttf_font(name); if (f == NULL) { lua_pushnil(L); return 1; } drawlib_font *ff = (drawlib_font*)lua_newuserdata(L, sizeof(drawlib_font)); luaL_getmetatable(L, FONT); lua_setmetatable(L, -2); ff->font = f; return 1; } static int font_gc(lua_State *L) { drawlib_font *f = (drawlib_font*)luaL_checkudata(L, 1, FONT); if(f->font == NULL) { luaL_error(L, "f->font == NULL ?"); } g_decref_font(f->font); f->font = NULL; return 0; } static int font_text_width(lua_State *L) { drawlib_font *f = (drawlib_font*)luaL_checkudata(L, 1, FONT); const char* txt = luaL_checkstring(L, 2); int size = luaL_checkinteger(L, 3); lua_pushinteger(L, g_text_width(f->font, txt, size)); return 1; } static int font_text_height(lua_State *L) { drawlib_font *f = (drawlib_font*)luaL_checkudata(L, 1, FONT); const char* txt = luaL_checkstring(L, 2); int size = luaL_checkinteger(L, 3); lua_pushinteger(L, g_text_height(f->font, txt, size)); return 1; } // ==================================================================== // SURFACES static int draw_surface_from_fd(lua_State *L) { int fd = luaL_checkinteger(L, 1); luaL_checktype(L, 2, LUA_TTABLE); fb_info_t geom; geom.width = getintfield(L, 2, "width"); geom.height = getintfield(L, 2, "height"); geom.bpp = getintfield(L, 2, "bpp"); geom.pitch = getintfield(L, 2, "pitch"); geom.memory_model = getintfield(L, 2, "memory_model"); fb_t *fb = g_fb_from_file(fd, &geom); if (fb == NULL) { lua_pushnil(L); return 1; } drawlib_surface *s = (drawlib_surface*)lua_newuserdata(L, sizeof(drawlib_surface)); luaL_getmetatable(L, SURFACE); lua_setmetatable(L, -2); s->fb = fb; s->subregion.x = s->subregion.y = 0; s->subregion.w = geom.width; s->subregion.h = geom.height; s->has_subregion = false; return 1; } static int draw_new_surface(lua_State *L) { int w = luaL_checkinteger(L, 1); int h = luaL_checkinteger(L, 2); int bpp = luaL_checkinteger(L, 3); bool alpha = lx_checkboolean(L, 4); if (bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32) { luaL_error(L, "Invalid BPP value %d, must be 8 16 24 or 32.", bpp); } if (alpha && (bpp == 8 || bpp == 24)) { luaL_error(L, "Invalid BPP value %d with alpha, must be 16 or 32.", bpp); } if (w < 0 || h < 0) { luaL_error(L, "Invalid dimensions (%d %d)", w, h); } fb_info_t geom; geom.width = w; geom.height = h; geom.bpp = bpp; geom.pitch = w * bpp / 8; if (bpp == 8) geom.memory_model = FB_MM_GREY8; if (bpp == 16 && alpha) geom.memory_model = FB_MM_GA16; if (bpp == 16 && !alpha) geom.memory_model = FB_MM_RGB16; if (bpp == 24) geom.memory_model = FB_MM_RGB24; if (bpp == 32 && alpha) geom.memory_model = FB_MM_RGBA32; if (bpp == 32 && !alpha) geom.memory_model = FB_MM_RGB32; uint8_t *buf = (uint8_t*)malloc(geom.height * geom.pitch); if (buf == NULL) { luaL_error(L, "Buffer allocation failed"); } memset(buf, 0, geom.height * geom.pitch); fb_t *fb = g_fb_from_mem(buf, &geom, true); if (fb == NULL) { luaL_error(L, "fb_t allocation failed"); } drawlib_surface *s = (drawlib_surface*)lua_newuserdata(L, sizeof(drawlib_surface)); luaL_getmetatable(L, SURFACE); lua_setmetatable(L, -2); s->fb = fb; s->subregion.x = s->subregion.y = 0; s->subregion.w = geom.width; s->subregion.h = geom.height; s->has_subregion = false; return 1; } static int draw_load_image(lua_State *L) { const char* filename = luaL_checkstring(L, 1); fb_t *img = g_load_image(filename); if (img == NULL) { lua_pushnil(L); return 1; } drawlib_surface *s = (drawlib_surface*)lua_newuserdata(L, sizeof(drawlib_surface)); luaL_getmetatable(L, SURFACE); lua_setmetatable(L, -2); s->fb = img; s->subregion.x = s->subregion.y = 0; s->subregion.w = img->geom.width; s->subregion.h = img->geom.height; s->has_subregion = false; return 1; } static int surface_gc(lua_State *L) { drawlib_surface *s = (drawlib_surface*)luaL_checkudata(L, 1, SURFACE); if(s->fb == NULL) { luaL_error(L, "s->fb == NULL ?"); } g_decref_fb(s->fb); s->fb = NULL; return 0; } static int surface_sub(lua_State *L) { drawlib_surface *s = (drawlib_surface*)luaL_checkudata(L, 1, SURFACE); int x = luaL_checkinteger(L, 2); int y = luaL_checkinteger(L, 3); int w, h; if (lua_isinteger(L, 4)) { w = luaL_checkinteger(L, 4); } else { w = s->subregion.w - x; } if (lua_isinteger(L, 5)) { h = luaL_checkinteger(L, 5); } else { h = s->subregion.h - y; } if (x < 0 || y < 0 || w < 0 || h < 0) luaL_error(L, "negative argument is invalid"); if (x > s->subregion.w || y > s->subregion.h) luaL_error(L, "out of bounds"); if (x+w > (int)s->subregion.w) w = s->subregion.w - x; if (y+h > (int)s->subregion.h) h = s->subregion.h - y; drawlib_surface *s2 = (drawlib_surface*)lua_newuserdata(L, sizeof(drawlib_surface)); luaL_getmetatable(L, SURFACE); lua_setmetatable(L, -2); s2->fb = s->fb; g_incref_fb(s->fb); s2->has_subregion = true; s2->subregion.x = s->subregion.x + x; s2->subregion.y = s->subregion.y + y; s2->subregion.w = w; s2->subregion.h = h; return 1; } static int surface_width(lua_State *L) { drawlib_surface *s = (drawlib_surface*)luaL_checkudata(L, 1, SURFACE); lua_pushinteger(L, s->subregion.w); return 1; } static int surface_height(lua_State *L) { drawlib_surface *s = (drawlib_surface*)luaL_checkudata(L, 1, SURFACE); lua_pushinteger(L, s->subregion.h); return 1; } static int surface_rgb(lua_State *L) { drawlib_surface *s = (drawlib_surface*)luaL_checkudata(L, 1, SURFACE); int r = luaL_checkinteger(L, 2); int g = luaL_checkinteger(L, 3); int b = luaL_checkinteger(L, 4); color_t c = g_color_rgb(s->fb, r, g, b); lua_pushlightuserdata(L, (void*)c); return 1; } // ############################# DRAWING PRIMITIVES ############## static int surface_plot(lua_State *L) { drawlib_surface *s = (drawlib_surface*)luaL_checkudata(L, 1, SURFACE); int x = luaL_checkinteger(L, 2); int y = luaL_checkinteger(L, 3); color_t c = (color_t)lx_checklightudata(L, 4); g_region_plot(s->fb, &s->subregion, x, y, c); return 0; } static int surface_hline(lua_State *L) { drawlib_surface *s = (drawlib_surface*)luaL_checkudata(L, 1, SURFACE); int x = luaL_checkinteger(L, 2); int y = luaL_checkinteger(L, 3); int w = luaL_checkinteger(L, 4); color_t c = (color_t)lx_checklightudata(L, 5); g_region_hline(s->fb, &s->subregion, x, y, w, c); return 0; } static int surface_vline(lua_State *L) { drawlib_surface *s = (drawlib_surface*)luaL_checkudata(L, 1, SURFACE); int x = luaL_checkinteger(L, 2); int y = luaL_checkinteger(L, 3); int h = luaL_checkinteger(L, 4); color_t c = (color_t)lx_checklightudata(L, 5); g_region_vline(s->fb, &s->subregion, x, y, h, c); return 0; } static int surface_line(lua_State *L) { drawlib_surface *s = (drawlib_surface*)luaL_checkudata(L, 1, SURFACE); int x = luaL_checkinteger(L, 2); int y = luaL_checkinteger(L, 3); int x2 = luaL_checkinteger(L, 4); int y2 = luaL_checkinteger(L, 5); color_t c = (color_t)lx_checklightudata(L, 6); g_region_line(s->fb, &s->subregion, x, y, x2, y2, c); return 0; } static int surface_rect(lua_State *L) { drawlib_surface *s = (drawlib_surface*)luaL_checkudata(L, 1, SURFACE); int x = luaL_checkinteger(L, 2); int y = luaL_checkinteger(L, 3); int w = luaL_checkinteger(L, 4); int h = luaL_checkinteger(L, 5); color_t c = (color_t)lx_checklightudata(L, 6); g_region_rect(s->fb, &s->subregion, x, y, w, h, c); return 0; } static int surface_fillrect(lua_State *L) { drawlib_surface *s = (drawlib_surface*)luaL_checkudata(L, 1, SURFACE); int x = luaL_checkinteger(L, 2); int y = luaL_checkinteger(L, 3); int w = luaL_checkinteger(L, 4); int h = luaL_checkinteger(L, 5); color_t c = (color_t)lx_checklightudata(L, 6); g_region_fillrect(s->fb, &s->subregion, x, y, w, h, c); return 0; } static int surface_circle(lua_State *L) { drawlib_surface *s = (drawlib_surface*)luaL_checkudata(L, 1, SURFACE); int x = luaL_checkinteger(L, 2); int y = luaL_checkinteger(L, 3); int r = luaL_checkinteger(L, 4); color_t c = (color_t)lx_checklightudata(L, 5); g_region_circle(s->fb, &s->subregion, x, y, r, c); return 0; } static int surface_fillcircle(lua_State *L) { drawlib_surface *s = (drawlib_surface*)luaL_checkudata(L, 1, SURFACE); int x = luaL_checkinteger(L, 2); int y = luaL_checkinteger(L, 3); int r = luaL_checkinteger(L, 4); color_t c = (color_t)lx_checklightudata(L, 5); g_region_fillcircle(s->fb, &s->subregion, x, y, r, c); return 0; } static int surface_blit(lua_State *L) { drawlib_surface *s = (drawlib_surface*)luaL_checkudata(L, 1, SURFACE); int x = luaL_checkinteger(L, 2); int y = luaL_checkinteger(L, 3); drawlib_surface *s2 = (drawlib_surface*)luaL_checkudata(L, 4, SURFACE); g_region_blit_region(s->fb, &s->subregion, x, y, s2->fb, s2->subregion); return 0; } static int surface_write(lua_State *L) { drawlib_surface *s = (drawlib_surface*)luaL_checkudata(L, 1, SURFACE); int x = luaL_checkinteger(L, 2); int y = luaL_checkinteger(L, 3); const char *text = luaL_checkstring(L, 4); drawlib_font *f = (drawlib_font*)luaL_checkudata(L, 5, FONT); int size = luaL_checkinteger(L, 6); color_t c = (color_t)lx_checklightudata(L, 7); g_region_write(s->fb, &s->subregion, x, y, text, f->font, size, c); return 0; } /* }====================================================== */ static const luaL_Reg drawlib[] = { {"surface_from_fd",draw_surface_from_fd}, {"new_surface", draw_new_surface}, {"load_image", draw_load_image}, {"load_bitmap_font",draw_load_bitmap_font}, {"load_ttf_font",draw_load_ttf_font}, {NULL, NULL} }; static const luaL_Reg surface_meta[] = { {"sub", surface_sub}, {"width", surface_width}, {"height", surface_height}, {"rgb", surface_rgb}, {"plot", surface_plot}, {"hline", surface_hline}, {"vline", surface_vline}, {"line", surface_line}, {"rect", surface_rect}, {"fillrect", surface_fillrect}, {"circle", surface_circle}, {"fillcircle", surface_fillcircle}, {"blit", surface_blit}, {"write", surface_write}, {"__gc", surface_gc}, {NULL, NULL} }; static const luaL_Reg font_meta[] = { {"text_width", font_text_width}, {"text_height", font_text_height}, {"__gc", font_gc}, {NULL, NULL} }; LUAMOD_API int lx_open_draw (lua_State *L) { luaL_newlib(L, drawlib); luaL_newmetatable(L, SURFACE); luaL_setfuncs(L, surface_meta, 0); lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); lua_pop(L, 1); luaL_newmetatable(L, FONT); luaL_setfuncs(L, font_meta, 0); lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); lua_pop(L, 1); return 1; } /* vim: set sts=2 ts=2 sw=2 tw=0 et :*/