Added initial cut of basic scripting support, introducing an osg::Script object to wrap up the individual scripts, osg::ScriptCallback for assigning a Script as node callback and an osg::ScriptEngine base class that plugins implement to provided support for specific scripting languages.

Provided are lua, python and V8 (for javascript) plugins that just open up enough of a link to the respective libs to run a script, there is no scene graph <-> script communication in current implementation.
This commit is contained in:
Robert Osfield
2013-08-09 16:51:06 +00:00
parent babd6e0ee7
commit bd7ec9c5f7
21 changed files with 849 additions and 244 deletions

View File

@@ -6,6 +6,8 @@
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/ScriptEngine>
#include <osg/UserDataContainer>
#include <osgDB/ReadFile>
#include <osgDB/FileUtils>
@@ -13,162 +15,6 @@
#include <osgGA/TrackballManipulator>
#include <osgViewer/Viewer>
// hacky experiment with create lua, v8 and python to run scripts.
#ifdef USE_LUA
extern "C" {
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
void runLua(const std::string& str)
{
OSG_NOTICE<<std::endl<<"runLua("<<str<<")"<<std::endl;
lua_State* lua = lua_open();
luaL_openlibs(lua);
std::string filePath = str;
if(osgDB::fileExists(filePath))
{
if(luaL_dofile(lua, filePath.c_str()))
{
OSG_NOTICE << "LuaEngine::runFile - " << lua_tostring(lua, -1) << std::endl;
}
}
else
{
OSG_NOTICE<<" parameter="<<filePath<<" not a valid file."<<std::endl;
}
lua_close(lua);
}
#endif
#ifdef USE_PYTHON
#include <Python.h>
void runPython(const std::string& str)
{
OSG_NOTICE<<std::endl<<"runPython("<<str<<")"<<std::endl;
Py_InitializeEx(0);
PyObject* py_main = PyModule_GetDict(PyImport_AddModule("__main__"));
std::string filePath = str;
if(osgDB::fileExists(filePath))
{
FILE* f = fopen(filePath.c_str(), "r");
PyObject* r = PyRun_File(f, filePath.c_str(), Py_file_input, py_main, py_main);
fclose(f);
if(!r) {
r = PyErr_Occurred();
if(r) {
// The following snippet lets us get the return code. That is: if the
// script is stopped with sys.exit() or similar. We could use this
// return code to do something sensible... later.
if(PyErr_ExceptionMatches(PyExc_SystemExit)) {
PyObject* ty = 0;
PyObject* er = 0;
PyObject* tr = 0;
PyErr_Fetch(&ty, &er, &tr);
Py_DECREF(ty);
Py_DECREF(er);
Py_DECREF(er);
}
else {
PyErr_Print();
PyErr_Clear();
}
}
}
}
Py_Finalize();
}
#endif
#ifdef USE_V8
#include <v8.h>
void runV8(const std::string& str)
{
OSG_NOTICE<<std::endl<<"runV8("<<str<<")"<<std::endl;
v8::Isolate* isolate = v8::Isolate::New();
{
v8::Locker locker(isolate);
v8::Isolate::Scope isolate_scope(isolate);
// Create a stack-allocated handle scope.
v8::HandleScope handle_scope;
v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
v8::Persistent<v8::Context> globalContext = v8::Context::New(NULL, global);
v8::Persistent<v8::ObjectTemplate> globalTemplate = v8::Persistent<v8::ObjectTemplate>::New(global);
std::string filePath = str;
if(osgDB::fileExists(filePath))
{
std::string js_source;
std::ifstream fin(filePath.c_str());
if (fin)
{
// read file in the crude way.
while(fin)
{
int c = fin.get();
if (c>=0 && c<=255)
{
js_source.push_back(c);
}
}
// Create a nested handle scope
v8::HandleScope local_handle_scope;
// Enter the global context
v8::Context::Scope context_scope(globalContext);
// Create a string containing the JavaScript source code.
v8::Handle<v8::String> source = v8::String::New(js_source.c_str());
// Compile the source code.
v8::Handle<v8::Script> script = v8::Script::Compile(source);
// Run the script to get the result.
v8::Handle<v8::Value> result = script->Run();
// Convert the result to an ASCII string and print it.
v8::String::AsciiValue ascii(result);
printf("%s\n", *ascii);
}
}
globalTemplate.Dispose();
globalContext.Dispose();
}
isolate->Dispose();
}
#endif
int main(int argc, char** argv)
{
@@ -176,33 +22,77 @@ int main(int argc, char** argv)
osgViewer::Viewer viewer(arguments);
std::string str;
typedef std::list< osg::ref_ptr<osg::Script> > Scripts;
Scripts scripts;
#ifdef USE_LUA
while (arguments.read("--lua",str))
std::string filename;
while(arguments.read("--script",filename))
{
runLua(str);
osg::ref_ptr<osg::Script> script = osgDB::readFile<osg::Script>(filename);
if (script.valid()) scripts.push_back(script.get());
}
#endif
#ifdef USE_V8
while (arguments.read("--js",str))
{
runV8(str);
}
#endif
#ifdef USE_PYTHON
while (arguments.read("--python",str))
{
runPython(str);
}
#endif
// create the model
osg::ref_ptr<osg::Node> model = osgDB::readNodeFiles(arguments);
if (!model) return 1;
// assgin script engine to scene graphs
model->getOrCreateUserDataContainer()->addUserObject(osgDB::readFile<osg::ScriptEngine>("ScriptEngine.lua"));
model->getOrCreateUserDataContainer()->addUserObject(osgDB::readFile<osg::ScriptEngine>("ScriptEngine.python"));
model->getOrCreateUserDataContainer()->addUserObject(osgDB::readFile<osg::ScriptEngine>("ScriptEngine.js"));
// assign scripts to scene graph
for(Scripts::iterator itr = scripts.begin();
itr != scripts.end();
++itr)
{
model->addUpdateCallback(new osg::ScriptCallback(itr->get()));
}
#if 0
std::string str;
osg::ref_ptr<osg::ScriptEngine> luaScriptEngine = osgDB::readFile<osg::ScriptEngine>("ScriptEngine.lua");
if (luaScriptEngine.valid())
{
while (arguments.read("--lua", str))
{
osg::ref_ptr<osg::Script> script = osgDB::readFile<osg::Script>(str);
if (script.valid())
{
luaScriptEngine->run(script.get());
}
}
}
osg::ref_ptr<osg::ScriptEngine> v8ScriptEngine = osgDB::readFile<osg::ScriptEngine>("ScriptEngine.V8");
if (v8ScriptEngine.valid())
{
while (arguments.read("--js",str))
{
osg::ref_ptr<osg::Script> script = osgDB::readFile<osg::Script>(str);
if (script.valid())
{
v8ScriptEngine->run(script.get());
}
}
}
osg::ref_ptr<osg::ScriptEngine> pythonScriptEngine = osgDB::readFile<osg::ScriptEngine>("ScriptEngine.python");
if (pythonScriptEngine.valid())
{
while (arguments.read("--python",str))
{
osg::ref_ptr<osg::Script> script = osgDB::readFile<osg::Script>(str);
if (script.valid())
{
pythonScriptEngine->run(script.get());
}
}
}
#endif
viewer.setSceneData( model.get() );
return viewer.run();
}