背景

我使用带有luaglut的Lua来做一些OpenGL的工作。 luaglut API与gl / glut C API几乎相同。有时,gl函数需要一个指向某些数据的指针,例如:

 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
    GL_UNSIGNED_BYTE, oh_crap_a_pointer)
 


在这种情况下,luaglut绑定会获取包含指针的轻量用户数据。在luaglut演示中,一个名为memarray的小型示例库完成了建立C数组并以轻型用户数据返回指向它的指针的工作。

您可以使用“ memarray”之类的东西:

 require 'memarray'
function loadTexture(filename)
  local file = assert(io.open(filename, 'rb'))
  local data = file:read('*a')
  file:close()
  local array = memarray('uchar', #data)
  array:from_str(data)

  return array
end

-- ... later

local texture = loadTexture('whatever.rgba')
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, GL_RGBA,
    GL_UNSIGNED_BYTE, texture:ptr())
 


这让我开始思考,为什么我们完全需要内存数组? Lua字符串应该是二进制安全的;我们真正需要的只是获得一个指向
file:read('*a')返回的字符串的指针,作为轻量级的userdata。看起来像这样:

 function loadTexture(filename)
  local file = assert(io.open(filename, 'rb'))
  local data = file:read('*a')
  file:close()

  return data
end

-- ... later

local stringpointer = require 'stringpointer'
local texture = loadTexture('whatever.rgba')
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, GL_RGBA,
    GL_UNSIGNED_BYTE, stringpointer.get(texture))
 


当然我们传递字符串而不是指针,因为如果没有更多引用,GC可以释放字符串所在的内存,从而使指针无效。在内部,Lua字符串是不可变的,并且无论如何都可以通过引用传递,因此这没什么大不了的。

代码

 #include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

int get_pointer(lua_State *L)
{
    luaL_checktype(L, 1, LUA_TSTRING);
    lua_pushlightuserdata(L, (void *)lua_tostring(L, 1));
    return 1;
}

int luaopen_stringpointer(lua_State *L)
{
    const luaL_Reg api[] = {
        {"get", get_pointer},
        {NULL, NULL}
    };

#if LUA_VERSION_NUM == 501
    luaL_register(L, "stringpointer", api);
#else
    luaL_newlib(L, api);
#endif

    return 1;
}
 


它很小,但是我的C生锈了,所以也许我做了一些愚蠢的事情。到目前为止,它似乎工作正常。欢迎任何输入。

评论

为什么有int get_pointer(lua_State * L)和int luaopen_stringpointer(lua_State * L)不是void函数的原因?我无法从上下文判断它们是否必须返回int。

@bazola get_pointer返回的int是从Lua调用它时给出的返回值的数量。这意味着返回堆栈上的最后一件事,将lightuserdata压入之前的行。

luaopen_stringpointer是Lua在需要“ stringpointer”时寻找的功能。返回值在那里具有相同的含义,它返回一个值,一个包含“ get”函数的表。

glTexImage2D对传递给它的字符串数据有什么作用?它拥有它吗?它释放它吗?它会立即使用吗?它会在某个未指定的较晚日期使用它吗?

@EtanReisner它复制数据并在以后使用该副本。它不会尝试在传入的指针处释放内存。它并不是真正的字符串数据,它采用其余参数描述的某种任意格式。

#1 楼

我不是Lua专家,但我至少可以为您提供有关您的C代码的指针(无双关语)。

您的get_pointer函数看起来不错,但可以做得更多简洁! Lua提供了结合了luaL_checkstringluaL_checktypeluaL_tostring函数。因此,您可以这样做:

int get_pointer(lua_State *L)
{
    lua_pushlightuserdata(L, (void *) luaL_checkstring(L, 1));
    return 1;
}