使用指针的用户数据示例 |
|
如果您想要从 Lua 中操作的结构需要由 C/C++ 代码分配或创建,那么最好将指向该结构的指针存储在用户数据中。
例如,在使用 Thomas Boutell 的 GD 图形库[1]创建图像时,函数 gdImageCreate
只返回指向图像对象的指针。
Image.new
是一个构造函数,它返回一个包含指向要操作的图像的指针的用户数据。用户数据的元表有一个垃圾回收事件来销毁图像,以及一个索引事件来调用图像方法。
只实现了三种方法
colorallocate
接受三个表示 RGB 的数字,并返回一个颜色索引。
line
在两点之间绘制一条线。
PNG
绘制图像并将其保存到文件。
用户数据的元表被放在注册表中,__index
字段指向方法表,以便 object:method()
语法可以正常工作。方法表存储在全局表中,以便脚本可以添加用 Lua 编写的其他方法。
操作 Image 的 Lua 函数需要访问堆栈上的用户数据,或者将新的用户数据压入堆栈。
checkImage
确保堆栈上的用户数据是正确的类型,并返回用户数据中的 Image 指针。
pushImage
将新的用户数据留在堆栈顶部,设置其元表,并在用户数据中设置 Image 指针。
#include <stdio.h> #include "lua.h" #include "lauxlib.h" #include "lualib.h" #include "gd.h" /* ============================================================================== Example Lua bindings for GD ============================================================================== */ #define IMAGE "Image" typedef gdImagePtr Image; static Image toImage (lua_State *L, int index) { Image *pi = (Image *)lua_touserdata(L, index); if (pi == NULL) luaL_typerror(L, index, IMAGE); return *pi; } static Image checkImage (lua_State *L, int index) { Image *pi, im; luaL_checktype(L, index, LUA_TUSERDATA); pi = (Image*)luaL_checkudata(L, index, IMAGE); if (pi == NULL) luaL_typerror(L, index, IMAGE); im = *pi; if (!im) luaL_error(L, "null Image"); return im; } static Image *pushImage (lua_State *L, Image im) { Image *pi = (Image *)lua_newuserdata(L, sizeof(Image)); *pi = im; luaL_getmetatable(L, IMAGE); lua_setmetatable(L, -2); return pi; } static int Image_new (lua_State *L) { int x = luaL_checkint(L, 1); int y = luaL_checkint(L, 2); pushImage(L, gdImageCreate(x, y)); return 1; } static int Image_color_allocate (lua_State *L) { Image im = checkImage(L, 1); int r = luaL_checkint(L, 2); int g = luaL_checkint(L, 3); int b = luaL_checkint(L, 4); lua_pushnumber(L, gdImageColorAllocate(im, r, g, b)); return 1; } static int Image_line (lua_State *L) { Image im = checkImage(L, 1); int x1 = luaL_checkint(L, 2); int y1 = luaL_checkint(L, 3); int x2 = luaL_checkint(L, 4); int y2 = luaL_checkint(L, 5); int colour = luaL_checkint(L, 6); gdImageLine(im, x1, y1, x2, y2, colour); return 0; } static int Image_png (lua_State *L) { /* Output the image to the disk file in PNG format. */ Image im = checkImage(L, 1); const char *name = luaL_checkstring(L, 2); FILE *pngout = fopen( name, "wb"); gdImagePng(im, pngout); fclose(pngout); return 0; } static const luaL_reg Image_methods[] = { {"new", Image_new}, {"colorallocate", Image_color_allocate}, {"line", Image_line}, {"PNG", Image_png}, {0,0} }; static int Image_gc (lua_State *L) { Image im = toImage(L, 1); if (im) gdImageDestroy(im); printf("goodbye Image (%p)\n", lua_touserdata(L, 1)); return 0; } static int Image_tostring (lua_State *L) { lua_pushfstring(L, "Image: %p", lua_touserdata(L, 1)); return 1; } static const luaL_reg Image_meta[] = { {"__gc", Image_gc}, {"__tostring", Image_tostring}, {0, 0} }; int Image_register (lua_State *L) { luaL_openlib(L, IMAGE, Image_methods, 0); /* create methods table, add it to the globals */ luaL_newmetatable(L, IMAGE); /* create metatable for Image, add it to the Lua registry */ luaL_openlib(L, 0, Image_meta, 0); /* fill metatable */ lua_pushliteral(L, "__index"); lua_pushvalue(L, -3); /* dup methods table*/ lua_rawset(L, -3); /* metatable.__index = methods */ lua_pushliteral(L, "__metatable"); lua_pushvalue(L, -3); /* dup methods table*/ lua_rawset(L, -3); /* hide metatable: metatable.__metatable = methods */ lua_pop(L, 1); /* drop metatable */ return 1; /* return methods on the stack */ } int main(int argc, char *argv[]) { lua_State *L = lua_open(); luaopen_base(L); luaopen_table(L); luaopen_io(L); luaopen_string(L); luaopen_math(L); luaopen_debug(L); Image_register(L); if(argc>1) lua_dofile(L, argv[1]); lua_close(L); return 0; }
此代码可以按如下方式编译用于 Lua 5.0
gcc gd.c -L/usr/local/lib/ -llua -llualib -lgd -lpng
for n,v in pairs(Image) do print(n,v) end size = 256 im = Image.new(size, size) print(im) white = im:colorallocate(255, 255, 255) for i = 0,size-1,1 do c = im:colorallocate(0, i, i) im:line(0, 0, size-1 , i, c) end im:PNG'test.png' -- debug.debug()
$ ./a gd.lua line function: 0x10054ff0 PNG function: 0x100553b8 colorallocate function: 0x100552f8 new function: 0x10054fb8 Image (0x10055ef0) goodbye Image (0x10055ef0)
这是测试代码创建的图像。