使用指针的用户数据示例 |
|
如果您想要从 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)
这是测试代码创建的图像。