#include "console.h" namespace osgLua { /****************** Callback **********************/ class ConsoleCallback : public osgGA::GUIEventHandler { public: ConsoleCallback(Console *c) : _console(c) {} virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter&) { switch(ea.getEventType()) { case(osgGA::GUIEventAdapter::KEYDOWN): { int key = ea.getKey(); if (key >0 && key < 256) _console->addInputChar(key); else if (key==osgGA::GUIEventAdapter::KEY_Return) { _console->addInputChar('\n'); } else if (key==osgGA::GUIEventAdapter::KEY_BackSpace || key==osgGA::GUIEventAdapter::KEY_Delete) { _console->addInputChar(8); } return true; } default: return false; } } protected: osg::ref_ptr _console; }; /**************************************************/ /************* Lua print function *****************/ int console_print(lua_State *L) { Console *console = reinterpret_cast ( lua_touserdata(L,lua_upvalueindex(1)) ); int total = lua_gettop(L); std::string s = ""; if (total > 0) s = lua_tostring(L,1); for(int i = 2; i <= total; ++i) { s = s + " " + lua_tostring(L,i); } console->addText(s); return 0; } /**************************************************/ Console::Console(unsigned int nl) : _numLines(nl), _current(nl - 1) { setMatrix(osg::Matrix::ortho2D(0.0, 1.0, 0.0, 1.0 )); osg::MatrixTransform* mva = new osg::MatrixTransform; mva->setReferenceFrame(osg::Transform::ABSOLUTE_RF); mva->setMatrix(osg::Matrix::identity()); addChild( mva ); osg::Geode *textGeode = new osg::Geode; mva->addChild( textGeode ); std::string font("fonts/arial.ttf"); _text = new osg::ref_ptr[_numLines]; float lineHeight = 1.0f/(_numLines+2); for (unsigned int i = 0; i < _numLines; ++i) { _text[i] = new osgText::Text; textGeode->addDrawable( _text[i].get() ); _text[i]->setFont(font); _text[i]->setAlignment( osgText::Text::LEFT_BOTTOM ); _text[i]->setFontResolution(100,100); _text[i]->setCharacterSize( lineHeight ); _text[i]->setColor( osg::Vec4(1,1,0,1)); _text[i]->setPosition(osg::Vec3(0,(i+1)*1.0f/(_numLines+1),0)); } _input = new osgText::Text(); _input->setFont(font); _input->setAlignment( osgText::Text::LEFT_BOTTOM ); _input->setFontResolution(100,100); _input->setCharacterSize( lineHeight ); _input->setColor( osg::Vec4(1,1,1,1)); _input->setPosition(osg::Vec3(0,0,0)); _input->setText("> "); textGeode->addDrawable(_input.get()); osg::StateSet *sset = new osg::StateSet; sset->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF |osg::StateAttribute::OVERRIDE ); sset->setRenderBinDetails(11,"RenderBin"); setStateSet( sset ); _command[0] = 0; } void Console::addText(const std::string &s, Console::TextType tt) { std::string::size_type init = 0; std::string::size_type last = s.find_first_of("\n",init); while ( last != std::string::npos ) { _addText(s.substr(init,last - init), tt); init = last + 1; last = s.find_first_of("\n",init); } _addText(s.substr(init), tt); } void Console::_addText(const std::string &s, Console::TextType tt) { osg::Vec3 pos = _text[ (_current+1)%_numLines ]->getPosition(); for (unsigned int i = 0; i < _numLines - 1; ++i) { unsigned int p = (i + _current +1 )%_numLines; unsigned int next = (p + 1)%_numLines; _text[p]->setPosition( _text[next]->getPosition() ); } _text[_current]->setPosition(pos); _text[_current]->setText(s); switch( tt ) { case CONSOLE_NORMAL: _text[_current]->setColor(osg::Vec4(1,1,0,1)); break; case CONSOLE_ERROR: _text[_current]->setColor(osg::Vec4(1,0,0,1)); break; case CONSOLE_COMMAND: _text[_current]->setColor(osg::Vec4(1,1,1,1)); break; } _current = (_current + _numLines - 1)%_numLines; } void Console::addInputChar(char c) { size_t len = strlen(_command); if (c == '\n') { addText(std::string("> ")+_command, CONSOLE_COMMAND); exec(_command); _command[0] = 0; } else if (c == 8 ) { if (len > 0) _command[len-1] = 0; } else { if (len < 512) { _command[len] = c; _command[len+1] = 0; } } _input->setText(std::string(">") + std::string(_command)); } void Console::attachToViewer( osgViewer::Viewer *viewer) { // viewer->getEventHandlerList().push_front( new ConsoleCallback(this) ); const osg::DisplaySettings *ds = viewer->getDisplaySettings(); if (ds) { float aspect = ds->getScreenWidth()/(float)ds->getScreenHeight(); setMatrix(osg::Matrix::ortho2D(0.0, aspect, 0.0, 1.0 )); } } void Console::setScript(osgLua::Script *s) { if (_script.get() != s) { if (_script.valid()) { // restore the print function lua_State *L = _script->getLuaState(); lua_getfield(L, LUA_REGISTRYINDEX, "osgLua_print"); lua_setglobal(L, "print"); lua_pushnil(L); lua_setfield(L, LUA_REGISTRYINDEX, "osgLua_print"); } if (s) { lua_State *L = s->getLuaState(); // keep a copy of the print function lua_getglobal(L, "print"); lua_setfield(L, LUA_REGISTRYINDEX, "osgLua_print"); // replace the print function lua_pushlightuserdata(L, (void*)this); lua_pushcclosure(L, console_print, 1); lua_setglobal(L, "print"); _script = s; } } } bool Console::exec(const std::string &code) { try { _script->execute(code, 0, "user-input:"); } catch (osgLua::Exception &e) { addText(e.what(), CONSOLE_ERROR); return false; } return true; } } // end of osgLua namespace