lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


I'll explain how this code works, and hopefully answer your questions in
the process.

    size = 256

    im = CreateImage(size,size)

    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


CreateImage returns a userdata that has a metatable equal to:

  {
    gc = image_destroy
    gettable = {
      ColorAllocate = image_color_allocate
      Line          = image_line
      PNG           = image_png
    }
  }

Where each of the image_ functions are closures whose upvalueindex(1)
refer to this metatable.

When lua excutes im:ColorAllocate(0,i,i), the gettable event for im
happens.  Since the gettable entry is a table, it looks for
ColorAllocate in this table, and it gets image_color_allocate.  It then
executes image_color_allocate(im,0,i,i).

This takes us into the following C code with the four arguments on Lua
parameter stack, and the first four lines of this code ensure that they
are of the correct type.  The reason for this is that the user may have
entered im.ColorAllocate(0,i,i) by mistake, which would end up calling
image_color_allocate with only three arguments.

    static int image_color_allocate (lua_State *L)
    {
      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);
      lua_pushnumber(L, gdImageColorAllocate(im, r, g, b));
      return 1;
    }

Now lets look at how check_image checks the first argument which is our
userdata im.

    static gdImagePtr check_image (lua_State *L, int index)
    {
      luaL_check_type(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);  /* drop value pushed by lua_getmetatable */
      return (gdImagePtr)lua_touserdata(L, index);
    }

First we make sure that it is a userdata with luaL_check_type.
Then lua_getmetatable pushes the metatable for im on top of the stack.
Then we make sure that our userdata is the right type by comparing the
metatable of im with upvalueindex(1).  You never now, some user might
have entered im.ColorAllocate(some_other_userdata,0,0,0).
If our userdata is the right type, then return a pointer to our
userdata.

Hope this helps.

- Peter