Хорошо, загрузка фрагмента функции update () в глобальную переменную и наличие таблицы глобальных параметров в сценарии Lua - это путь к go. Я достиг этого , используя следующие рекомендации , и я опубликую подробные шаги ниже. По сути, загрузка скрипта полностью сначала гарантирует, что все глобальные переменные сохранятся в контексте C ++. Затем сохранение желаемой функции в виде индекса позволяет нам запустить ее снова, сохраняя при этом глобальные переменные в сценарии, развивающиеся самостоятельно.
Шаг 1
Первый вызов luaL_loadfile
один раз при инициализации
Шаг 2
Запуск скрипт один раз с использованием lua_pcall(_L, 0, 0, 0);
Это гарантирует, что глобальные переменные, которые используются в качестве параметров в скрипте Lua, находятся в памяти.
Шаг 3
Сохраните функцию Lua. Мне удалось сделать это с помощью следующего кода C ++:
void matrix::store(char * function)
{
lua_newtable(_L); // create table for functions
_idx = luaL_ref(_L, LUA_REGISTRYINDEX); // store said table in pseudo-registry
lua_rawgeti(_L, LUA_REGISTRYINDEX, _idx); // retrieve table for functions
lua_getglobal(_L, function); // retrieve function to store
if (lua_isfunction(_L, -1)) {
_f = luaL_ref(_L, -2); // store a function in the function table
}
else {
lua_pop(_L, 1);
std::cout << "can't find " << function << std::endl;
}
// table is two places up the current stack counter
lua_pop(_L, 1); // we are done with the function table, so pop it
std::cout << "idx: " << _idx << ", function: " << _f << std::endl;
}
Шаг 4
Вызовите сохраненную функцию снова при рендеринге с использованием следующей функции C ++:
void matrix::run()
{
int status;
if (_f == -1) {
std::cout << "invalid function index " << _f << std::endl;
}
else {
lua_rawgeti(_L, LUA_REGISTRYINDEX, _idx); // retrieve function table
lua_rawgeti(_L, -1, _f); // retrieve function
//use function
status = lua_pcall(_L, 0, 0, 0); // 0 arguments, 0 results
if (status != LUA_OK) {
std::cout << "error running function" << lua_error(_L) << std::endl;
}
//don't forget to pop the function table from the stack
lua_pop(_L, 1);
}
}
Шаг 5 (необязательно)
Если мы установим все параметры Lua в глобальной таблице, мы можем получить их динамически на C ++, используя следующий фрагмент кода :
void matrix::get_params(char * p)
{
lua_getglobal(_L, p);
lua_pushnil(_L);
int i = 0;
while(lua_next(_L,-2))
{
const char * key = lua_tostring(_L,-2);
double value = lua_tonumber(_L,-1);
lua_pop(_L,1);
std::cout << key << " = " << value << std::endl;
_h[i].key.assign(key);
_h[i].value = value;
i++;
}
lua_pop(_L, 1);
}
Где _h
- это простая структура Dynami c, определенная как таковая:
typedef struct {
std::string key;
float value;
} hash;
Я использую только float, поэтому эта простая структура достаточно удобна для моих нужд , и позволяет мне добавлять множество переменных в мой сценарий Lua, не беспокоясь об определении структуры на C ++. Таким образом, я могу добавить столько параметров в свою таблицу Lua и производить вычисления при обновлении.
Шаг 6
Настройте скрипт Lua навсегда! Et voila:
p = {
amplitude = 1.5,
frequency = 500,
phase = 0.0
}
function transform(m)
r = {}
for i = 1, #m do
r[i] = {}
for j = 1, #m[i] do
if (i % 2) then
r[i][j] = p.amplitude * math.sin(m[i][j] + p.phase)
else
r[i][j] = -p.amplitude * math.sin(m[i][j] + p.phase)
end
p.phase = p.phase + 0.001
end
end
return r
end
-- called by c++
function update()
m = pull()
r = transform(m)
push(r)
end
Это решение соответствует моим потребностям, но кажется очень сложным и неэффективным. Но в любом случае это был отличный хакерский сеанс.