Binding With Metatable And Closures |
|
Image.Create is a constructor that returns a userdata containing the image |
Image.new is a constructor that returns a userdata containing the image |
|
to destroy the image, and a gettable event for calling the methods needed to |
|
to destroy the image, and a index event for calling the methods needed to |
|
#include <stdio.h> |
|
#include "lualib.h" |
|
#include <stdio.h> |
|
static gdImagePtr check_image (lua_State *L, int index) |
|
#define IMAGE "Image" static gdImagePtr checkimage (lua_State *L, int index) |
|
luaL_check_type(L, index, LUA_TUSERDATA); |
|
luaL_checktype(L, index, LUA_TUSERDATA); |
|
luaL_typerror(L, index, "Image"); /* die */ |
|
luaL_typerror(L, index, IMAGE); /* die */ |
|
static int image_create (lua_State *L) |
|
static gdImagePtr pushimage (lua_State *L, gdImagePtr im) |
|
int x = luaL_check_int(L, 1); int y = luaL_check_int(L, 2); gdImagePtr im = gdImageCreate(x, y); |
|
return im; } static int image_new (lua_State *L) { int x = luaL_checkint(L, 1); int y = luaL_checkint(L, 2); pushimage(L, gdImageCreate(x, y)); |
|
gdImagePtr im = (gdImagePtr)lua_unboxpointer(L,1); gdImageDestroy(im); printf("Goodbye!\n"); |
|
gdImagePtr im = (gdImagePtr)lua_unboxpointer(L, 1); if (im) gdImageDestroy(im); |
|
gdImagePtr im = check_image(L, 1); int r = luaL_check_int(L, 2); int g = luaL_check_int(L, 3); int b = luaL_check_int(L, 4); |
|
gdImagePtr im = checkimage(L, 1); int r = luaL_checkint(L, 2); int g = luaL_checkint(L, 3); int b = luaL_checkint(L, 4); |
|
gdImagePtr im = check_image(L, 1); int x1 = luaL_check_int(L, 2); int y1 = luaL_check_int(L, 3); int x2 = luaL_check_int(L, 4); int y2 = luaL_check_int(L, 5); int colour = luaL_check_int(L, 6); |
|
gdImagePtr 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); |
|
gdImagePtr im = check_image(L, 1); const char *name = luaL_check_string(L, 2); |
|
gdImagePtr im = checkimage(L, 1); const char *name = luaL_checkstring(L, 2); |
|
{"Create", image_create}, {"ColorAllocate?", image_color_allocate}, {"Line", image_line}, |
|
{"new", image_new}, {"colorallocate", image_color_allocate}, {"line", image_line}, |
|
int openGDlua (lua_State *L) |
|
int Image_register (lua_State *L) |
|
printf("Hi there!\n"); lua_pushliteral(L, "Image"); /* name of Image table */ |
|
lua_pushliteral(L, IMAGE); /* name of Image table */ |
|
lua_pushliteral(L, "__index"); lua_pushvalue(L, methods); /* reference to Image methods */ lua_settable(L, metatable); /* add gettable event to metatable */ |
|
lua_pushliteral(L, "__index"); /* add index event to metatable */ lua_pushvalue(L, methods); lua_settable(L, metatable); /* metatable.__index = methods */ lua_pushliteral(L, "__metatable"); /* hide metatable */ lua_pushvalue(L, methods); lua_settable(L, metatable); /* metatable.__metatable = methods */ |
|
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; } |
|
This code can be compiled for Lua 5.0 (alpha) as follows: |
|
This code can be compiled for Lua 5.0 as follows: |
|
gcc -fPIC -g -c GDlua.c -o GDlua.o gcc -g -shared -Wl,-soname,libgdlua.so -o libgdlua.so.1.0.0 GDlua.o -L/usr/local/lib/ -llua -llualib -lgd |
|
gcc gd.c -L/usr/local/lib/ -llua -llualib -lgd -lpng |
|
{{{ assert(loadlib('/usr/local/lib/libgdlua.so','openGDlua'))() |
|
{{{!Lua for n,v in pairs(Image) do print(n,v) end |
|
im = Image.Create(size,size) |
|
im = Image.new(size, size) |
|
white = im:ColorAllocate?(255, 255, 255) |
|
print(im) white = im:colorallocate(255, 255, 255) |
|
c = im:ColorAllocate?(0, i, i) im:Line(0, 0, size-1 , i, c) |
|
c = im:colorallocate(0, i, i) im:line(0, 0, size-1 , i, c) |
|
------------------------------------------------------------------------------ print('= Image =',Image) for n,v in pairs(Image) do print(n,v) end mt = getmetatable(im) print('= metatable =',mt) for n,v in pairs(mt) do print(n,v) end |
|
-- debug.debug() |
|
$ lua test_gd.lua Hi there! = Image = table: 0x8066868 Line function: 0x8066980 Create function: 0x80668b8 ColorAllocate? function: 0x80668d8 PNG function: 0x80669a0 = metatable = table: 0x8066890 __gettable table: 0x8066868 __gc function: 0x80668f8 Goodbye! |
|
$ ./a gd.lua line function: 0x100553b8 PNG function: 0x10055500 colorallocate function: 0x10055418 new function: 0x10054ff8 userdata: 0x10055e98 |
|
The next example shows how to use the gettable and settable events to read and write structure members |
|
The next example shows how to use the index and newindex events to read and write structure members |
|
=== Related Pages === * UserDataWithPointerExample - another GD example. |
Here is an example of how to make a Lua binding to Thomas Boutell's GD Graphics Library[1] using closures containing a metatable. The original example of how to use GD in C can be found on Tom's web page[2].
Image.new is a constructor that returns a userdata containing the image
to be maninpulated. The userdata's metatable has a garbage collection event
to destroy the image, and a index event for calling the methods needed to
draw the image and save the image to a file. Only three methods are implimented:
ColorAllocate, Line and PNG.
#include <stdio.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#include "gd.h"
/*
==============================================================================
Example Lua bindings for GD
==============================================================================
*/
#define IMAGE "Image"
static gdImagePtr checkimage (lua_State *L, int index)
{
luaL_checktype(L, index, LUA_TUSERDATA);
lua_getmetatable(L, index);
if( ! lua_equal(L, lua_upvalueindex(1), -1) )
luaL_typerror(L, index, IMAGE); /* die */
lua_pop(L, 1);
return (gdImagePtr)lua_unboxpointer(L, index);
}
static gdImagePtr pushimage (lua_State *L, gdImagePtr im)
{
lua_boxpointer(L, im);
lua_pushvalue(L, lua_upvalueindex(1));
lua_setmetatable(L, -2);
return im;
}
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_destroy (lua_State *L)
{
gdImagePtr im = (gdImagePtr)lua_unboxpointer(L, 1);
if (im) gdImageDestroy(im);
return 0;
}
static int image_color_allocate (lua_State *L)
{
gdImagePtr 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)
{
gdImagePtr 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. */
gdImagePtr 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 meta_methods[] = {
{"__gc", image_destroy },
{0,0}
};
static const luaL_reg image_methods[] = {
{"new", image_new},
{"colorallocate", image_color_allocate},
{"line", image_line},
{"PNG", image_png},
{0,0}
};
#define newtable(L) (lua_newtable(L), lua_gettop(L))
int Image_register (lua_State *L)
{
int metatable, methods;
lua_pushliteral(L, IMAGE); /* name of Image table */
methods = newtable(L); /* Image methods table */
metatable = newtable(L); /* Image metatable */
lua_pushliteral(L, "__index"); /* add index event to metatable */
lua_pushvalue(L, methods);
lua_settable(L, metatable); /* metatable.__index = methods */
lua_pushliteral(L, "__metatable"); /* hide metatable */
lua_pushvalue(L, methods);
lua_settable(L, metatable); /* metatable.__metatable = methods */
luaL_openlib(L, 0, meta_methods, 0); /* fill metatable */
luaL_openlib(L, 0, image_methods, 1); /* fill Image methods table */
lua_settable(L, LUA_GLOBALSINDEX); /* add Image to globals */
return 0;
}
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;
}
This code can be compiled for Lua 5.0 as follows:
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: 0x100553b8 PNG function: 0x10055500 colorallocate function: 0x10055418 new function: 0x10054ff8 userdata: 0x10055e98
This is the image created by the test code.
The next example shows how to use the index and newindex events to read and write structure members BindingWithMembersAndMethods