指標範例之使用者資料 |
|
如果使用者想要操作的結構必須由 C/C++ 程式碼來配置或建立,則最好在使用者資料中只儲存指向結構的指標。
例如,當使用 Thomas Boutell 的 GD 圖形函式庫[1]建立影像時,函式 gdImageCreate
只會傳回指向影像物件的指標。
Image.new
是傳回一個含有指向要操作的影像指標的使用者資料的建構函式。使用者資料的元表有一個垃圾回收事件來毀損影像,以及一個用來呼叫影像方法的索引事件。
僅實現三個方法
colorallocate
接受三個 RGB 數字,並傳回色彩索引。line
在兩個點之間畫一條線。PNG
會繪製影像,並將其儲存到檔案。使用者資料的元表會放入登錄,而 __index
欄位會指向方法表格,因此 object:method()
語法才會運作。方法表格會儲存在全域變數表格中,因此腳本才能夠新增使用 Lua 所寫的方法。
用來操作影像的 Lua 函式需要存取堆疊中的使用者資料,或將新的使用者資料推入堆疊。
checkImage
可確保堆疊中的使用者資料是正確類型,並傳回使用者資料內的影像指標。
pushImage
會在堆疊頂端留下新的使用者資料,並設定其元表,以及設定使用者資料內的影像指標。
#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)
這是測試程式碼所建立的影像。