Luaを組み込むメモ
スクリプト言語による効率的ゲーム開発 C/C++へのLua組込み実践 (GAME DEVELOPER)
- 作者: 浜中誠
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2008/09/27
- メディア: 大型本
- 購入: 13人 クリック: 322回
- この商品を含むブログ (40件) を見る
サンプルゲームはいろいろと参考になる。
glutのアプリにluaを組み込んだ手順。
(glut, lua, tolua++が必要)
置き換え前
main.cpp
#ifdef _WIN32 #include <windows.h> #else #include <stdlib.h> #endif #include <GL/glut.h> #include <stdio.h> #include "glapp.h" #include "main.h" #include <iostream> #define SCREEN_WIDTH 640 #define SCREEN_HEIGHT 480 // opengl操作クラス GLApp g_gl; void resize(int w, int h) { g_gl.setViewPort(0, 0, w, h); g_gl.setProjection(w, h); } void display() { g_gl.draw(); glutSwapBuffers(); } void mouse(int button, int state, int x, int y) { if(button==GLUT_RIGHT_BUTTON){ switch (state) { case GLUT_UP: if(g_gl.onMouseRightUp(x, y)){ glutPostRedisplay(); } break; case GLUT_DOWN: if(g_gl.onMouseRightDown(x, y)){ glutPostRedisplay(); } break; default: break; } } } void motion(int x, int y) { if(g_gl.onMouseMove(x, y)){ glutPostRedisplay(); } } void keyboard(unsigned char key, int x, int y) { switch (key) { case 'q': case 'Q': case '\033': /* '\033' は ESC の ASCII コード */ exit(0); default: break; } } void initGlut(int *argc, char **argv) { // init glut glutInitWindowSize(320, 240); glutInit(argc, argv); glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE); glutCreateWindow(argv[0]); // init glut callbacks glutDisplayFunc(display); glutReshapeFunc(resize); glutMouseFunc(mouse); glutMotionFunc(motion); glutKeyboardFunc(keyboard); } int main(int argc, char *argv[]) { initGlut(&argc, argv); g_gl.initialize(); // ↓lua置き換え予定 VertexArray &object=g_gl.appendDrawable(); object.appendVertex(0.0, 1.0, 0.0); object.appendVertex(-1.0, -1.0, 0.0); object.appendVertex(1.0, -1.0, 0.0); object.appendColor(1.0, 0.0, 0.0); object.appendColor(0.0, 1.0, 0.0); object.appendColor(0.0, 0.0, 1.0); // ↑lua置き換え予定 // main loop glutMainLoop(); // ここには来ない return 1; }
glapp.h
#ifndef GLAPP_H #define GLAPP_H #include <vector> #include <GL/gl.h> class HeadPitchCamera { bool isMouseRightDown_; int mouseX_; int mouseY_; float head_; float pitch_; float distance_; public: HeadPitchCamera(); bool onMouseRightDown(int x, int y); bool onMouseRightUp(int x, int y); bool onMouseMove(int x, int y); void draw(); }; class VertexArray { std::vector<GLfloat> vertices_; std::vector<GLfloat> colors_; public: void draw(); void appendVertex(float x, float y, float z); void appendColor(float r, float g, float b); }; class GLApp { HeadPitchCamera camera_; std::vector<VertexArray> drawables_; public: void initialize(); void setViewPort(int left, int top, int width, int height); void setProjection(float w, float h); VertexArray& appendDrawable(); void draw(); bool onMouseRightDown(int x, int y); bool onMouseRightUp(int x, int y); bool onMouseMove(int x, int y); }; #endif // GLAPP_H
glapp.cpp
#include "glapp.h" #include <GL/glu.h> #include <algorithm> #include <boost/bind.hpp> HeadPitchCamera::HeadPitchCamera() : isMouseRightDown_(false), mouseX_(-1), mouseY_(-1) , head_(0), pitch_(0), distance_(10) {} bool HeadPitchCamera::onMouseRightDown(int x, int y) { isMouseRightDown_=true; mouseX_=x; mouseY_=y; return false; } bool HeadPitchCamera::onMouseRightUp(int x, int y) { isMouseRightDown_=false; return false; } bool HeadPitchCamera::onMouseMove(int x, int y) { if(!isMouseRightDown_){ return false; } head_+=(x-mouseX_); pitch_+=(y-mouseY_); mouseX_=x; mouseY_=y; return true; } void HeadPitchCamera::draw() { glTranslatef(0, 0, -distance_); glRotatef(head_, 0, 1, 0); glRotatef(pitch_, 1, 0, 0); } void VertexArray::draw() { glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); glColorPointer(3, GL_FLOAT, 0, &colors_[0]); glVertexPointer(3, GL_FLOAT, 0, &vertices_[0]); glDrawArrays(GL_TRIANGLES, 0, 3); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); } void VertexArray::appendVertex(float x, float y, float z) { vertices_.push_back(x); vertices_.push_back(y); vertices_.push_back(z); } void VertexArray::appendColor(float r, float g, float b) { colors_.push_back(r); colors_.push_back(g); colors_.push_back(b); } void GLApp::initialize() { glEnable(GL_TEXTURE_2D); glDisable(GL_CULL_FACE); glClearColor(0, 0, 0.5, 0); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } void GLApp::setViewPort(int left, int top, int width, int height) { glViewport(left, top, width, height); setProjection(width, height); } void GLApp::setProjection(float w, float h) { float aspect=w/h; glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0, aspect, 1, 1000); } VertexArray& GLApp::appendDrawable() { drawables_.push_back(VertexArray()); return drawables_.back(); } void GLApp::draw() { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); camera_.draw(); std::for_each(drawables_.begin(), drawables_.end() , boost::bind(&VertexArray::draw, _1)); glFlush(); } bool GLApp::onMouseRightDown(int x, int y) { return camera_.onMouseRightDown(x, y); } bool GLApp::onMouseRightUp(int x, int y) { return camera_.onMouseRightUp(x, y); } bool GLApp::onMouseMove(int x, int y) { return camera_.onMouseMove(x, y); }
TARGET=lua_sample LDFLAGS=-lglut -lGLU -lGL $(TARGET): main.o glapp.o gcc -o $@ $^ $(LDFLAGS) .cpp.o: gcc -c -o $@ $< $(CFLAGS)
lua vmの組み込み
main.cppへの追加
// ヘッダ #include <lua.hpp> // VM lua_State *g_L; void finalize() { luaL_dostring(g_L, "print('end lua')"); lua_close(g_L); } int main(int argc, char **argv) { // VM g_L=lua_open(); atexit(finalize); // 標準ライブラリの読み込み luaL_openlibs(g_L); luaL_dostring(g_L, "print('start lua')"); // 省略 // main loop glutMainLoop(); return 1; }
Makefileの修正
LDFLAGS=-lglut -lGLU -lGL -llua
tolua++の仕込み
luafunc.pkgを作成。
// まだ空
$ tolua++ -h usage: tolua++ [options] input_file # help抜粋 Command line options are: -o file : set output file; default is stdout. -H file : create include file. -n name : set package name; default is input file root name.
toluaでソース生成。
$ tolua++ -n luafunc -o luafunc_glue.cpp -H luafunc_glue.h luafunc.pkg
"-n"で指定したluafuncに対してtolua_luafunc_openという関数ができるので呼ぶようにする。
main.cpp
// 追加 #include "tolua++.h" #include "luafunc_glue.h" int main() { // luaL_openlibs(L);の次くらいに追加 tolua_luafunc_open(g_L); }
Makefile修正と追加。
LDFLAGS=-lglut -lGLU -lGL -ltolua++ -llua $(TARGET): main.o glapp.o luafunc_glue.o luafunc_glue.cpp: luafunc.pkg tolua++ -n $@ -o $@_glue.cpp -H $@_glue.h $<
tolua++でc++の要素をluaにバインドする
GLApp g_gl
をluaから操作できるようにする。
main.hにextern宣言を追加。
extern GLApp g_gl;
luafunc.pkgの中身を書く。
glapp.hから使う所だけ抜き出す。
(privateな部分やpublicでluaスクリプトから呼ばない部分は書かない)
$#include "glapp.h" $#include "main.h" module cfunc { class VertexArray { void appendVertex(float x, float y, float z); void appendColor(float r, float g, float b); }; class GLApp { VertexArray& appendDrawable(); }; extern GLApp g_gl; }
luaに処理を移す
main.cpp
// init scene VertexArray &object=g_gl.appendDrawable(); object.appendVertex(0.0, 1.0, 0.0); object.appendVertex(-1.0, -1.0, 0.0); object.appendVertex(1.0, -1.0, 0.0); object.appendColor(1.0, 0.0, 0.0); object.appendColor(0.0, 1.0, 0.0); object.appendColor(0.0, 0.0, 1.0);
↓
if(argc>1){ std::cout << "luaL_dofile: " << argv[1] << "..."; // スクリプト実行 int ret=luaL_dofile(g_L, argv[1]); // error処理 if(ret){ std::cout << "error: " << lua_tostring(g_L, -1); } std::cout << std::endl; }
scene.lua
object=cfunc.g_gl:appendDrawable() object:appendVertex(0.0, 1.0, 0.0); object:appendVertex(-1.0, -1.0, 0.0); object:appendVertex(1.0, -1.0, 0.0); object:appendColor(1.0, 0.0, 0.0); object:appendColor(0.0, 1.0, 0.0); object:appendColor(0.0, 0.0, 1.0);
実行
$ ./lua_sample scene.lua
ここまででシーンへの形状配置をスクリプト化した。