以前C++で書いたコードをLuaを使って実現させてみた。
学習中ということもありかなり力わざでどうにかしています。
まず、GLUTをLuaから扱えるようするコードを書きます。
今回はこころみということで、イベントは表示とキー入力とタイマだけ、表示できるのはラインだけにしてます。
#include "lua.h" #include "lauxlib.h" #include <GLUT/glut.h> #include <stdlib.h> static lua_State *G_L; static int interval = 200; static int width = 320; static int height = 240; int vertex2i(lua_State *L) { int x = luaL_checkinteger(L, 1); int y = luaL_checkinteger(L, 2); glVertex2i(x, y); return 0; } void display() { glClear(GL_COLOR_BUFFER_BIT); glColor3d(0.0, 0.0, 0.0); glBegin(GL_LINES); lua_getfield(G_L, 1, "display"); if(lua_isfunction(G_L, -1)) { lua_call(G_L, 0, 0); } lua_settop(G_L, 1); glEnd(); glFlush(); } void resize(int w, int h) { glViewport(0, 0, w, h); width = w; height = h; glLoadIdentity(); glOrtho(-0.5, w - 0.5, h - 0.5, -0.5, -1.0, 1.0); } void keyboard(unsigned char key, int x, int y) { lua_getfield(G_L, 1, "keyboard"); if(lua_isfunction(G_L, -1)) { lua_pushinteger(G_L, key); lua_pushinteger(G_L, x); lua_pushinteger(G_L, y); lua_call(G_L, 3, 0); } lua_settop(G_L, 1); } void timer(int n) { lua_getfield(G_L, 1, "timer"); if(lua_isfunction(G_L, -1)) { lua_call(G_L, 0, 0); } lua_settop(G_L, 1); glColor3d(0.0, 0.0, 0.0); glBegin(GL_LINES); lua_getfield(G_L, 1, "display"); if(lua_isfunction(G_L, -1)) { lua_call(G_L, 0, 0); } lua_settop(G_L, 1); glEnd(); glFlush(); glutTimerFunc(interval, timer, 0); } static int main_loop(lua_State *L) { int argc = 0; char* argv[] = { 0 }; G_L = L; lua_getfield(G_L, 1, "width"); if(lua_isnumber(G_L, -1)) { width = lua_tointeger(G_L, -1); } lua_getfield(G_L, 1, "height"); if(lua_isnumber(G_L, -1)) { height = lua_tointeger(G_L, -1); } lua_getfield(G_L, 1, "interval"); if(lua_isnumber(G_L, -1)) { interval = lua_tointeger(G_L, -1); } lua_settop(G_L, 1); glutInitWindowPosition(100, 100); glutInitWindowSize(width, height); glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA); glutCreateWindow(argv[0]); glutDisplayFunc(display); glutReshapeFunc(resize); glutKeyboardFunc(keyboard); glutTimerFunc(interval, timer, 0); glClearColor(1.0, 1.0, 1.0, 1.0); glutMainLoop(); return 0; } static const luaL_Reg glutlib[] = { { "vertex2i", vertex2i }, { "main_loop", main_loop }, { NULL, NULL } }; LUALIB_API int luaopen_glut(lua_State *L) { luaL_register(L, "glut", glutlib); return 1; }
次にlinit.cを書き換えて上記のコードをライブラリとして組み込みます。
LUALIB_API int luaopen_glut(lua_State *L); /* これを追加 */ static const luaL_Reg lualibs[] = { {"", luaopen_base}, {LUA_LOADLIBNAME, luaopen_package}, {LUA_TABLIBNAME, luaopen_table}, {LUA_IOLIBNAME, luaopen_io}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, {LUA_MATHLIBNAME, luaopen_math}, {LUA_DBLIBNAME, luaopen_debug}, {"glut", luaopen_glut}, /* これを追加 */ {NULL, NULL} };
ビルドをする際にはOpenGL、GLUTのライブラリもリンクする必要があります。今回はMac OS X (Lepard)上のXcodeで試しているので、プロジェクトにGLUT.frameworkとOpenGL.frameworkを追加してビルドしました。
今回は機能の追加だけなので、ビルドして実行すると、標準の機能の範囲ではかわりありません。
で、次のようなスクリプトを書いて実行させてみます。
CTRL_C = 3 p1 = { x = 10, y = 10, vx = 8, vy = -2 } p2 = { x = 75, y = 55, vx = -6, vy = 4 } interval = 100 width = 160 height = 120 function on_key(key, x, y) print(key, x, y) if key == CTRL_C then os.exit() end end function on_display() glut.vertex2i(p1.x, p1.y) glut.vertex2i(p2.x, p2.y) end function on_timer() p1.x = p1.x + p1.vx p1.y = p1.y + p1.vy p2.x = p2.x + p2.vx p2.y = p2.y + p2.vy if (p1.x < 0) or (width < p1.x) then p1.vx = -p1.vx end if (p1.y < 0) or (height < p1.y) then p1.vy = -p1.vy end if (p2.x < 0) or (width < p2.x) then p2.vx = -p2.vx end if (p2.y < 0) or (height < p2.y) then p2.vy = -p2.vy end end glut.main_loop { width = width, height = height, interval = interval, keyboard = on_key, display = on_display, timer = on_timer }
実行結果。内容としては元にしたC++のプログラムと一緒です。
Ctrl+Cで終了するようにしていますが、終了手続きとか一切無視してプログラムを終了しているのでこれで大丈夫なのか、まだ確認できてません。