#include "ag.h" #include "Video.h" #include "anaglym.h" #include #include /* exit() */ #include #include #include #include #include #include #include using namespace std; static void usage(); Engine * g_engine; SDL_Event Engine::userEvent; static void usage() { cerr << "Usage: anaglym [options] program.lua[c]" << endl; exit(42); } int main(int argc, char * argv[]) { const char * program = NULL; for (int i = 1; i < argc; i++) { if (argv[i][0] != '-') { if (program == NULL) { program = argv[i]; } else { cerr << "Warning: argument " << argv[i] << " ignored!" << endl; } } else { cerr << "Warning: Unrecognized option '" << argv[i]+1 << "'" << endl; } } if (program == NULL) { usage(); } g_engine = new Engine(); if (g_engine->load(program)) g_engine->run(); delete g_engine; return 0; } Engine::Engine() { m_video = new Video(); m_next_object_index = 1; m_eye[0] = 0; m_eye[1] = -1; m_eye[2] = 0; m_center[0] = 0; m_center[1] = 0; m_center[2] = 0; m_up[0] = 0; m_up[1] = 0; m_up[2] = 1; m_drawing = false; /* setup redraw SDL event structure */ userEvent.type = SDL_USEREVENT; userEvent.user.code = 0; m_video->start(); } Engine::~Engine() { m_video->stop(); lua_close(m_luaState); for (std::map::iterator it = m_objects.begin(); it != m_objects.end(); it++) { delete it->second; } delete m_video; } bool Engine::load(const char * program) { m_program_path = program; size_t pos = m_program_path.find_last_of("/\\"); m_program_path = (pos != string::npos) ? m_program_path.substr(0, pos) : "."; m_luaState = lua_open(); registerLibraries(); int s = luaL_loadfile(m_luaState, program); if (s == 0) { // execute Lua program s = lua_pcall(m_luaState, 0, LUA_MULTRET, 0); } else { cerr << "Warning: problem loading '" << program << "'" << endl; return false; } if (s != 0) { reportErrors(s); return false; } return true; } void Engine::reportErrors(int status) { if (status != 0) { cerr << "Engine: Error: " << lua_tostring(m_luaState, -1) << endl; lua_pop(m_luaState, 1); // remove error message } } void Engine::registerLibraries() { /* Load the Lua string library */ lua_pushcfunction(m_luaState, luaopen_string); lua_pcall(m_luaState, 0, 0, 0); /* Load the Lua math library */ lua_pushcfunction(m_luaState, luaopen_math); lua_pcall(m_luaState, 0, 0, 0); /* Load the Lua table library */ lua_pushcfunction(m_luaState, luaopen_table); lua_pcall(m_luaState, 0, 0, 0); ag::register_functions(m_luaState); } string Engine::locateResource(const string & shortname) { string try_path; try_path = m_program_path + "/" + shortname; if (fileExists(try_path)) return try_path; return ""; } bool Engine::fileExists(const string & path) { struct stat st; if (stat(path.c_str(), &st) == 0) { return S_ISREG(st.st_mode) && (st.st_size > 0); } return false; } int Engine::addObject(WFObj * obj) { int id = m_next_object_index; Object * o = new Object(); o->wfobj = obj; o->display_list = obj->render(); /* TODO: stl map insertion valid like this? */ m_objects[id] = o; m_next_object_index++; return id; } Engine::Object * Engine::getObject(int id) { return m_objects.find(id) != m_objects.end() ? m_objects[id] : NULL; } int Engine::startFrame(lua_State * L) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(m_eye[0], m_eye[1], m_eye[2], m_center[0], m_center[1], m_center[2], m_up[0], m_up[1], m_up[2]); return 0; } int Engine::endFrame(lua_State * L) { SDL_GL_SwapBuffers(); return 0; } int Engine::setCamera(lua_State * L) { int argc = lua_gettop(L); vector args; for (int i = 1; i <= argc; i++) { int type = lua_type(L, i); if (type == LUA_TNUMBER || type == LUA_TSTRING) args.push_back(lua_tonumber(L, i)); else args.push_back(0); } if (argc >= 3) { m_eye[0] = args[0]; m_eye[1] = args[1]; m_eye[2] = args[2]; } if (argc >= 6) { m_center[0] = args[3]; m_center[1] = args[4]; m_center[2] = args[5]; } if (argc >= 9) { m_up[0] = args[6]; m_up[1] = args[7]; m_up[2] = args[8]; } return 0; } /* called by SDL when the update timer expires */ Uint32 Engine::updateCallback(Uint32 interval, void * param) { Engine * engine = (Engine *) param; return engine->updateCallback(interval); } /* member update function to be called by our registered * SDL callback non-member function */ Uint32 Engine::updateCallback(Uint32 interval) { if (!m_drawing) { SDL_PushEvent(&userEvent); } return interval; } void Engine::run() { /* register a screen redrawing SDL event */ SDL_AddTimer(20, &updateCallback, this); SDL_Event event; while (SDL_WaitEvent(&event)) { switch (event.type) { case SDL_KEYDOWN: switch (event.key.keysym.sym) { case SDLK_ESCAPE: goto RET; break; } break; case SDL_QUIT: goto RET; break; case SDL_USEREVENT: if (event.user.code == 0) { update(); } break; } } RET: ; } void Engine::update() { m_drawing = true; lua_getfield(m_luaState, LUA_GLOBALSINDEX, "update"); if (lua_type(m_luaState, -1) == LUA_TFUNCTION) { int s = lua_pcall(m_luaState, 0, 0, 0); reportErrors(s); } lua_pop(m_luaState, 1); m_drawing = false; } void Engine::Object::loadPhy(const std::string & path, bool static_data) { geoms = g_engine->m_world.loadPhy(path, &body, static_data); } void Engine::Object::setPosition(double x, double y, double z) { if (body != 0) { dBodySetPosition(body, x, y, z); } } void Engine::Object::getPosition(double * x, double * y, double * z) { if (body != 0) { const dReal * pos = dBodyGetPosition(body); *x = pos[0]; *y = pos[1]; *z = pos[2]; } }