diff --git a/Engine.cc b/Engine.cc new file mode 100644 index 0000000..a57da07 --- /dev/null +++ b/Engine.cc @@ -0,0 +1,381 @@ + +#include "ag.h" +#include "Video.h" +#include "Engine.h" +#include +#include /* exit() */ +#include +#include +#include +#include +#include +#include /* fabs() */ +#include +#include +using namespace std; + +Engine * g_engine; + +SDL_Event Engine::userEvent; + +Engine::Engine(const string & path) +{ + 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; + m_autoPhysics = true; + + size_t pos = path.find_last_of("\\/"); + m_engine_path = (pos != string::npos) ? string(path, 0, pos) : "."; + + /* setup redraw SDL event structure */ + userEvent.type = SDL_USEREVENT; + userEvent.user.code = 0; +#if 0 + /* start in windowed mode for debugging */ + m_video->start(0, 0, false, false); +#else + m_video->start(); +#endif +} + +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; + + /* look for the resource relative to the loaded script's directory */ + try_path = m_program_path + "/" + shortname; + if (fileExists(try_path)) + return try_path; + + /* next look for the resource in the engine's library directory */ + try_path = m_engine_path + "/lib/" + 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, bool is_static, float scale) +{ + int id = m_next_object_index++; + Object * o = createObject(is_static, obj->render(), scale); + m_objects[id] = o; + return id; +} + +void Engine::removeObject(int id) +{ + if (getObject(id) != NULL) + m_objects.erase(id); +} + +int Engine::cloneObject(const Engine::Object * obj) +{ + int id = m_next_object_index++; + Object * o = new Object(*obj); + m_objects[id] = o; + 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(25, &updateCallback, this); + + SDL_Event event; + while (SDL_WaitEvent(&event)) + { + switch (event.type) + { + case SDL_KEYDOWN: + if (event.key.keysym.sym == SDLK_ESCAPE) + { + goto RET; + } + break; + case SDL_QUIT: + goto RET; + break; + case SDL_USEREVENT: + if (event.user.code == 0) + { + update(); + } + break; + } + } +RET: + ; +} + +void Engine::update() +{ + m_drawing = true; + if (m_autoPhysics) + doPhysics(); + lua_getfield(m_luaState, LUA_GLOBALSINDEX, "update"); + if (lua_type(m_luaState, -1) == LUA_TFUNCTION) + { + /* call the update function - pops the function ref from the stack */ + int s = lua_pcall(m_luaState, 0, LUA_MULTRET, 0); + reportErrors(s); + } + else + { + lua_pop(m_luaState, 1); + } + m_drawing = false; +} + +void Engine::doPhysics() +{ + static Uint32 last_updated = 0; + Uint32 current_ticks = SDL_GetTicks(); + if (last_updated > 0) + { + Uint32 msec_steps = current_ticks - last_updated; + for (Uint32 i = 0; i < msec_steps; i++) + m_world.step(); + } + last_updated = current_ticks; +} + +void Engine::drawObjects() +{ + std::map::iterator it; + for (it = m_objects.begin(); it != m_objects.end(); it++) + { + it->second->draw(); + } +} + +Engine::Object::Object(bool is_static, OdeWorld & world, GLuint dl, float scale) +{ + m_ode_object = world.createObject(is_static, scale); + m_display_list = dl; + m_display_list_refcnt = new int; + *m_display_list_refcnt = 1; + m_is_visible = true; + m_scale = scale; + m_is_scaled = ! (fabs(scale - 1.0) < 0.0001); +} + +Engine::Object::Object(const Engine::Object & orig) +{ + m_is_visible = orig.m_is_visible; + m_ode_object = new OdeWorld::Object(*orig.m_ode_object); + m_display_list = orig.m_display_list; + m_display_list_refcnt = orig.m_display_list_refcnt; + (*m_display_list_refcnt)++; + m_scale = orig.m_scale; + m_is_scaled = orig.m_is_scaled; +} + +Engine::Object::~Object() +{ + delete m_ode_object; + (*m_display_list_refcnt)--; + if (*m_display_list_refcnt < 1) + { + /* we hold the last reference to the OpenGL display list */ + delete m_display_list_refcnt; + glDeleteLists(m_display_list, 1); + } +} + +void Engine::Object::draw() +{ + if (m_is_visible) + { + const dReal * pos = m_ode_object->getPosition(); + const dReal * rot = m_ode_object->getRotation(); + bool transform = (pos != NULL && rot != NULL); + + if (transform) + OdeWorld::pushTransform(pos, rot); + + if (m_is_scaled) + { + glPushAttrib(GL_TRANSFORM_BIT); + glEnable(GL_NORMALIZE); + glScalef(m_scale, m_scale, m_scale); + } + + glCallList(m_display_list); + + if (m_is_scaled) + glPopAttrib(); + + if (transform) + glPopMatrix(); + } +} diff --git a/Engine.h b/Engine.h new file mode 100644 index 0000000..8449f86 --- /dev/null +++ b/Engine.h @@ -0,0 +1,102 @@ + +#ifndef ENGINE_H +#define ENGINE_H + +#include +#include +#include +#include "Video.h" +#include "OdeWorld/OdeWorld.h" +#include "wfobj/WFObj.hh" + +class Engine +{ + public: + class Object + { + public: + Object(bool is_static, OdeWorld & world, GLuint dl, + float scale = 1.0f); + Object(const Object & orig); + ~Object(); + + void setPosition(double x, double y, double z) + { + m_ode_object->setPosition(x, y, z); + } + void getPosition(double * x, double * y, double * z) + { + m_ode_object->getPosition(x, y, z); + } + void loadPhy(const std::string & path) + { + m_ode_object->loadPhy(path); + } + void setVisible(bool visible) { m_is_visible = visible; } + bool getVisible() { return m_is_visible; } + + void draw(); + + protected: + OdeWorld::Object * m_ode_object; + GLuint m_display_list; + int * m_display_list_refcnt; + bool m_is_visible; + float m_scale; + bool m_is_scaled; + }; + + Engine(const std::string & path); + ~Engine(); + + std::string locateResource(const std::string & shortname); + Video * getVideo() { return m_video; } + bool load(const char * program); + void run(); + void reportErrors(int status); + OdeWorld & getWorld() { return m_world; } + int addObject(WFObj * obj, bool is_static, float scale = 1.0f); + void removeObject(int id); + int cloneObject(const Object * obj); + Object * getObject(int id); + void doPhysics(); + void drawObjects(); + void setAutoPhysics(bool autoPhysics) { m_autoPhysics = autoPhysics; } + bool getAutoPhysics() { return m_autoPhysics; } + + /* lua services */ + int startFrame(lua_State * L); + int endFrame(lua_State * L); + int setCamera(lua_State * L); + + protected: + static Uint32 updateCallback(Uint32 interval, void * param); + static SDL_Event userEvent; + + Uint32 updateCallback(Uint32 interval); + void registerLibraries(); + bool fileExists(const std::string & path); + void update(); + Object * createObject(bool is_static, GLuint display_list, + float scale = 1.0f) + { + return new Object(is_static, m_world, display_list, scale); + } + + lua_State * m_luaState; + Video * m_video; + std::string m_program_path; + std::string m_engine_path; + OdeWorld m_world; + std::map m_objects; + int m_next_object_index; + GLdouble m_eye[3]; + GLdouble m_center[3]; + GLdouble m_up[3]; + bool m_drawing; + bool m_autoPhysics; +}; + +extern Engine * g_engine; + +#endif diff --git a/ag.cc b/ag.cc index 0783f1d..ab5db3b 100644 --- a/ag.cc +++ b/ag.cc @@ -1,6 +1,7 @@ -#include "anaglym.h" #include "ag.h" +#include "anaglym.h" +#include "Engine.h" #include "Video.h" #include #include "wfobj/WFObj.hh" diff --git a/anaglym.cc b/anaglym.cc index 08a0279..4dd7e80 100644 --- a/anaglym.cc +++ b/anaglym.cc @@ -1,48 +1,23 @@ -#include "ag.h" #include "Video.h" #include "anaglym.h" -#include +#include "Engine.h" +#include "SDL.h" #include /* exit() */ -#include -#include -#include #include #include -#include /* fabs() */ -#include -#include using namespace std; static void usage(); -Engine * g_engine; -static string g_engine_path; - -SDL_Event Engine::userEvent; - static void usage() { cerr << "Usage: anaglym [options] program.lua[c]" << endl; exit(42); } -static void setupEnginePath(string path) -{ - size_t pos = path.find_last_of("\\/"); - if (pos != string::npos) - { - g_engine_path = string(path, 0, pos); - } - else - { - g_engine_path = "."; - } -} - int main(int argc, char * argv[]) { - setupEnginePath(argv[0]); const char * program = NULL; for (int i = 1; i < argc; i++) { @@ -55,12 +30,14 @@ int main(int argc, char * argv[]) else { cerr << "Warning: argument " << argv[i] << " ignored!" << endl; + usage(); } } else { cerr << "Warning: Unrecognized option '" << argv[i]+1 << "'" << endl; + usage(); } } @@ -69,369 +46,10 @@ int main(int argc, char * argv[]) usage(); } - g_engine = new Engine(); + g_engine = new Engine(argv[0]); 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; - m_autoPhysics = true; - - /* setup redraw SDL event structure */ - userEvent.type = SDL_USEREVENT; - userEvent.user.code = 0; -#if 0 - /* start in windowed mode for debugging */ - m_video->start(0, 0, false, false); -#else - m_video->start(); -#endif -} - -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; - - /* look for the resource relative to the loaded script's directory */ - try_path = m_program_path + "/" + shortname; - if (fileExists(try_path)) - return try_path; - - /* next look for the resource in the engine's library directory */ - try_path = g_engine_path + "/lib/" + 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, bool is_static, float scale) -{ - int id = m_next_object_index++; - Object * o = createObject(is_static, obj->render(), scale); - m_objects[id] = o; - return id; -} - -void Engine::removeObject(int id) -{ - if (getObject(id) != NULL) - m_objects.erase(id); -} - -int Engine::cloneObject(const Engine::Object * obj) -{ - int id = m_next_object_index++; - Object * o = new Object(*obj); - m_objects[id] = o; - 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(25, &updateCallback, this); - - SDL_Event event; - while (SDL_WaitEvent(&event)) - { - switch (event.type) - { - case SDL_KEYDOWN: - if (event.key.keysym.sym == SDLK_ESCAPE) - { - goto RET; - } - break; - case SDL_QUIT: - goto RET; - break; - case SDL_USEREVENT: - if (event.user.code == 0) - { - update(); - } - break; - } - } -RET: - ; -} - -void Engine::update() -{ - m_drawing = true; - if (m_autoPhysics) - doPhysics(); - lua_getfield(m_luaState, LUA_GLOBALSINDEX, "update"); - if (lua_type(m_luaState, -1) == LUA_TFUNCTION) - { - /* call the update function - pops the function ref from the stack */ - int s = lua_pcall(m_luaState, 0, LUA_MULTRET, 0); - reportErrors(s); - } - else - { - lua_pop(m_luaState, 1); - } - m_drawing = false; -} - -void Engine::doPhysics() -{ - static Uint32 last_updated = 0; - Uint32 current_ticks = SDL_GetTicks(); - if (last_updated > 0) - { - Uint32 msec_steps = current_ticks - last_updated; - for (Uint32 i = 0; i < msec_steps; i++) - m_world.step(); - } - last_updated = current_ticks; -} - -void Engine::drawObjects() -{ - std::map::iterator it; - for (it = m_objects.begin(); it != m_objects.end(); it++) - { - it->second->draw(); - } -} - -Engine::Object::Object(bool is_static, OdeWorld & world, GLuint dl, float scale) -{ - m_ode_object = world.createObject(is_static, scale); - m_display_list = dl; - m_display_list_refcnt = new int; - *m_display_list_refcnt = 1; - m_is_visible = true; - m_scale = scale; - m_is_scaled = ! (fabs(scale - 1.0) < 0.0001); -} - -Engine::Object::Object(const Engine::Object & orig) -{ - m_is_visible = orig.m_is_visible; - m_ode_object = new OdeWorld::Object(*orig.m_ode_object); - m_display_list = orig.m_display_list; - m_display_list_refcnt = orig.m_display_list_refcnt; - (*m_display_list_refcnt)++; - m_scale = orig.m_scale; - m_is_scaled = orig.m_is_scaled; -} - -Engine::Object::~Object() -{ - delete m_ode_object; - (*m_display_list_refcnt)--; - if (*m_display_list_refcnt < 1) - { - /* we hold the last reference to the OpenGL display list */ - delete m_display_list_refcnt; - glDeleteLists(m_display_list, 1); - } -} - -void Engine::Object::draw() -{ - if (m_is_visible) - { - const dReal * pos = m_ode_object->getPosition(); - const dReal * rot = m_ode_object->getRotation(); - bool transform = (pos != NULL && rot != NULL); - - if (transform) - OdeWorld::pushTransform(pos, rot); - - if (m_is_scaled) - { - glPushAttrib(GL_TRANSFORM_BIT); - glEnable(GL_NORMALIZE); - glScalef(m_scale, m_scale, m_scale); - } - - glCallList(m_display_list); - - if (m_is_scaled) - glPopAttrib(); - - if (transform) - glPopMatrix(); - } -} diff --git a/anaglym.h b/anaglym.h index 16d9a21..d5cc2cb 100644 --- a/anaglym.h +++ b/anaglym.h @@ -2,102 +2,6 @@ #ifndef ANAGLYM_H #define ANAGLYM_H -#include -#include -#include -#include "Video.h" -#include "OdeWorld/OdeWorld.h" -#include "wfobj/WFObj.hh" - #define FILENAME_SAFE_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-" -class Engine -{ - public: - class Object - { - public: - Object(bool is_static, OdeWorld & world, GLuint dl, - float scale = 1.0f); - Object(const Object & orig); - ~Object(); - - void setPosition(double x, double y, double z) - { - m_ode_object->setPosition(x, y, z); - } - void getPosition(double * x, double * y, double * z) - { - m_ode_object->getPosition(x, y, z); - } - void loadPhy(const std::string & path) - { - m_ode_object->loadPhy(path); - } - void setVisible(bool visible) { m_is_visible = visible; } - bool getVisible() { return m_is_visible; } - - void draw(); - - protected: - OdeWorld::Object * m_ode_object; - GLuint m_display_list; - int * m_display_list_refcnt; - bool m_is_visible; - float m_scale; - bool m_is_scaled; - }; - - Engine(); - ~Engine(); - - std::string locateResource(const std::string & shortname); - Video * getVideo() { return m_video; } - bool load(const char * program); - void run(); - void reportErrors(int status); - OdeWorld & getWorld() { return m_world; } - int addObject(WFObj * obj, bool is_static, float scale = 1.0f); - void removeObject(int id); - int cloneObject(const Object * obj); - Object * getObject(int id); - void doPhysics(); - void drawObjects(); - void setAutoPhysics(bool autoPhysics) { m_autoPhysics = autoPhysics; } - bool getAutoPhysics() { return m_autoPhysics; } - - /* lua services */ - int startFrame(lua_State * L); - int endFrame(lua_State * L); - int setCamera(lua_State * L); - - protected: - static Uint32 updateCallback(Uint32 interval, void * param); - static SDL_Event userEvent; - - Uint32 updateCallback(Uint32 interval); - void registerLibraries(); - bool fileExists(const std::string & path); - void update(); - Object * createObject(bool is_static, GLuint display_list, - float scale = 1.0f) - { - return new Object(is_static, m_world, display_list, scale); - } - - lua_State * m_luaState; - Video * m_video; - std::string m_program_path; - OdeWorld m_world; - std::map m_objects; - int m_next_object_index; - GLdouble m_eye[3]; - GLdouble m_center[3]; - GLdouble m_up[3]; - bool m_drawing; - bool m_autoPhysics; -}; - -extern Engine * g_engine; - #endif