Added osg::CallbackObject to be used to extend C++ class from scripting languages by providing callback objects assigned to the osg::Object UserDataContainer, with the CallbackObject's Name used to map the "method" provided by the CallbackObject. The CallbackObject is implemented by the script engine to provide the neccessary glue to invoking the script with the appropriate input parameters and handling the output parameters.
To the Lua plugin added support for assigned lua functions to C++ osg::Objects via the new osg::CallbackObject mechanism. To invoke the scripts function from C++ one must get the CallbackObject and call run on it. Renamed ScriptCallback to ScriptNodeCallback to avoid possibly confusion between osg::CallbackObject and the ScriptNodeCallback.
This commit is contained in:
@@ -58,7 +58,7 @@ int main(int argc, char** argv)
|
||||
itr != scripts.end();
|
||||
++itr)
|
||||
{
|
||||
model->addUpdateCallback(new osg::ScriptCallback(itr->get()));
|
||||
model->addUpdateCallback(new osg::ScriptNodeCallback(itr->get()));
|
||||
}
|
||||
|
||||
std::string str;
|
||||
@@ -441,7 +441,7 @@ int main(int argc, char** argv)
|
||||
osg::ref_ptr<osg::Script> script = osgDB::readFile<osg::Script>(str);
|
||||
if (script.valid())
|
||||
{
|
||||
presentation->addUpdateCallback(new osg::ScriptCallback(script.get(),"update"));
|
||||
presentation->addUpdateCallback(new osg::ScriptNodeCallback(script.get(),"update"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <osg/Object>
|
||||
#include <osg/NodeCallback>
|
||||
#include <osg/NodeVisitor>
|
||||
#include <osg/UserDataContainer>
|
||||
|
||||
namespace osg
|
||||
{
|
||||
@@ -27,6 +28,7 @@ typedef std::vector< osg::ref_ptr<osg::Object> > Parameters;
|
||||
// forward declare
|
||||
class ScriptEngine;
|
||||
|
||||
|
||||
/* Script class for wrapping a script and the language used in the script.*/
|
||||
class Script : public osg::Object
|
||||
{
|
||||
@@ -55,14 +57,41 @@ class Script : public osg::Object
|
||||
unsigned int _modifiedCount;
|
||||
};
|
||||
|
||||
/** Callback for attaching a script to a Node's via there UserDataContainer for the purpose of overriding class methods within scripts.*/
|
||||
class OSG_EXPORT CallbackObject : public osg::Object
|
||||
{
|
||||
public:
|
||||
CallbackObject() {}
|
||||
CallbackObject(const std::string& name) { setName(name); }
|
||||
CallbackObject(const CallbackObject& rhs, const osg::CopyOp copyop=osg::CopyOp::SHALLOW_COPY):osg::Object(rhs,copyop) {}
|
||||
META_Object(osg, CallbackObject);
|
||||
|
||||
inline bool run(osg::Object* object) const
|
||||
{
|
||||
osg::Parameters inputParameters;
|
||||
osg::Parameters outputParameters;
|
||||
return run(object, inputParameters, outputParameters);
|
||||
}
|
||||
|
||||
virtual bool run(osg::Object* object, osg::Parameters& inputParameters, osg::Parameters& outputParameters) const;
|
||||
|
||||
};
|
||||
|
||||
/** Convinience function for getting the CallbackObject associated with specificed name from an Object's UserDataContainer.*/
|
||||
inline CallbackObject* getCallbackObject(osg::Object* object, const std::string& name)
|
||||
{
|
||||
osg::UserDataContainer* udc = object->getUserDataContainer();
|
||||
return udc ? dynamic_cast<osg::CallbackObject*>(udc->getUserObject(name)) : 0;
|
||||
}
|
||||
|
||||
/** NodeCallback for attaching a script to a NodeCallback so that it can be called as an update or event callback.*/
|
||||
class OSG_EXPORT ScriptCallback : public osg::NodeCallback
|
||||
class OSG_EXPORT ScriptNodeCallback : public osg::NodeCallback
|
||||
{
|
||||
public:
|
||||
ScriptCallback(Script* script=0, const std::string& entryPoint="") : _script(script), _entryPoint(entryPoint) {}
|
||||
ScriptCallback(const ScriptCallback& rhs, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY): osg::NodeCallback(rhs,copyop), _script(rhs._script) {}
|
||||
ScriptNodeCallback(Script* script=0, const std::string& entryPoint="") : _script(script), _entryPoint(entryPoint) {}
|
||||
ScriptNodeCallback(const ScriptNodeCallback& rhs, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY): osg::NodeCallback(rhs,copyop), _script(rhs._script) {}
|
||||
|
||||
META_Object(osg, ScriptCallback)
|
||||
META_Object(osg, ScriptNodeCallback)
|
||||
|
||||
/** Set the script to call.*/
|
||||
void setScript(osg::Script* script) { _script = script; }
|
||||
@@ -81,7 +110,7 @@ class OSG_EXPORT ScriptCallback : public osg::NodeCallback
|
||||
|
||||
protected:
|
||||
|
||||
virtual ~ScriptCallback() {}
|
||||
virtual ~ScriptNodeCallback() {}
|
||||
|
||||
osg::ref_ptr<Script> _script;
|
||||
std::string _entryPoint;
|
||||
|
||||
@@ -16,7 +16,14 @@
|
||||
|
||||
using namespace osg;
|
||||
|
||||
ScriptEngine* ScriptCallback::getScriptEngine(osg::NodePath& nodePath)
|
||||
|
||||
bool CallbackObject::run(osg::Object* object, osg::Parameters& inputParameters, osg::Parameters& outputParameters) const
|
||||
{
|
||||
OSG_NOTICE<<"CallbackObject::run(object="<<object<<")"<<std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptEngine* ScriptNodeCallback::getScriptEngine(osg::NodePath& nodePath)
|
||||
{
|
||||
if (!_script) return 0;
|
||||
|
||||
@@ -35,7 +42,7 @@ ScriptEngine* ScriptCallback::getScriptEngine(osg::NodePath& nodePath)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ScriptCallback::operator()(Node* node, NodeVisitor* nv)
|
||||
void ScriptNodeCallback::operator()(Node* node, NodeVisitor* nv)
|
||||
{
|
||||
ScriptEngine* engine = getScriptEngine(nv->getNodePath());
|
||||
if (engine && _script.valid())
|
||||
|
||||
@@ -18,6 +18,53 @@
|
||||
|
||||
using namespace lua;
|
||||
|
||||
class LuaCallbackObject : public osg::CallbackObject
|
||||
{
|
||||
public:
|
||||
LuaCallbackObject(const std::string& methodName, const LuaScriptEngine* lse, int ref):_lse(lse),_ref(ref) { setName(methodName); }
|
||||
|
||||
virtual bool run(osg::Object* object, osg::Parameters& inputParameters, osg::Parameters& outputParameters) const
|
||||
{
|
||||
int topBeforeCall = lua_gettop(_lse->getLuaState());
|
||||
|
||||
lua_rawgeti(_lse->getLuaState(), LUA_REGISTRYINDEX, _ref);
|
||||
|
||||
int numInputs = 1;
|
||||
_lse->pushParameter(object);
|
||||
|
||||
for(osg::Parameters::iterator itr = inputParameters.begin();
|
||||
itr != inputParameters.end();
|
||||
++itr)
|
||||
{
|
||||
_lse->pushParameter(itr->get());
|
||||
++numInputs;
|
||||
}
|
||||
|
||||
if (lua_pcall(_lse->getLuaState(), numInputs, LUA_MULTRET,0)!=0)
|
||||
{
|
||||
OSG_NOTICE<<"Lua error : "<<lua_tostring(_lse->getLuaState(), -1)<<std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
int topAfterCall = lua_gettop(_lse->getLuaState());
|
||||
int numReturns = topAfterCall-topBeforeCall;
|
||||
for(int i=1; i<=numReturns; ++i)
|
||||
{
|
||||
outputParameters.insert(outputParameters.begin(), _lse->popParameterObject());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int getRef() const { return _ref; }
|
||||
|
||||
protected:
|
||||
|
||||
osg::ref_ptr<const LuaScriptEngine> _lse;
|
||||
int _ref;
|
||||
};
|
||||
|
||||
|
||||
static int getProperty(lua_State * _lua)
|
||||
{
|
||||
const LuaScriptEngine* lse = reinterpret_cast<const LuaScriptEngine*>(lua_topointer(_lua, lua_upvalueindex(1)));
|
||||
@@ -439,6 +486,8 @@ bool LuaScriptEngine::run(osg::Script* script, const std::string& entryPoint, os
|
||||
}
|
||||
}
|
||||
|
||||
int topBeforeCall = lua_gettop(_lua);
|
||||
|
||||
if (entryPoint.empty())
|
||||
{
|
||||
ScriptMap::iterator itr = _loadedScripts.find(script);
|
||||
@@ -460,7 +509,6 @@ bool LuaScriptEngine::run(osg::Script* script, const std::string& entryPoint, os
|
||||
pushParameter(itr->get());
|
||||
}
|
||||
|
||||
int topBeforeCall = lua_gettop(_lua);
|
||||
|
||||
if (lua_pcall(_lua, inputParameters.size(), LUA_MULTRET,0)!=0)
|
||||
{
|
||||
@@ -566,6 +614,15 @@ int LuaScriptEngine::pushPropertyToStack(osg::Object* object, const std::string&
|
||||
return 1;
|
||||
}
|
||||
|
||||
osg::CallbackObject* co = osg::getCallbackObject(object, propertyName);
|
||||
LuaCallbackObject* lco = dynamic_cast<LuaCallbackObject*>(co);
|
||||
if (lco)
|
||||
{
|
||||
lua_rawgeti(_lua, LUA_REGISTRYINDEX, lco->getRef());
|
||||
OSG_NOTICE<<"LuaScriptEngine::pushPropertyToStack("<<object<<", "<<propertyName<<") has callback object method need to call it, ref="<<lco->getRef()<<std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
OSG_NOTICE<<"LuaScriptEngine::pushPropertyToStack("<<object<<", "<<propertyName<<") no property found."<<std::endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -740,6 +797,16 @@ int LuaScriptEngine::setPropertyFromStack(osg::Object* object, const std::string
|
||||
osgDB::BaseSerializer::Type type;
|
||||
if (!_pi.getPropertyType(object, propertyName, type))
|
||||
{
|
||||
if (lua_type(_lua,-1)==LUA_TFUNCTION)
|
||||
{
|
||||
int ref = luaL_ref(_lua, LUA_REGISTRYINDEX);
|
||||
|
||||
OSG_NOTICE<<"LuaScriptEngine::setPropertyFromStack("<<object<<", "<<propertyName<<") need to handle lua function assigment, ref="<<ref<<std::endl;
|
||||
osg::ref_ptr<LuaCallbackObject> lco = new LuaCallbackObject(propertyName, this, ref);
|
||||
object->getOrCreateUserDataContainer()->addUserObject(lco.get());
|
||||
return 0;
|
||||
}
|
||||
|
||||
type = LuaScriptEngine::getType();
|
||||
}
|
||||
|
||||
|
||||
@@ -731,10 +731,10 @@ void SlideShowConstructor::addScriptToNode(ScriptCallbackType scriptCallbackType
|
||||
switch(scriptCallbackType)
|
||||
{
|
||||
case(UPDATE_SCRIPT) :
|
||||
node->addUpdateCallback(new osg::ScriptCallback(script_itr->second.get(), entry_point));
|
||||
node->addUpdateCallback(new osg::ScriptNodeCallback(script_itr->second.get(), entry_point));
|
||||
break;
|
||||
case(EVENT_SCRIPT) :
|
||||
node->addEventCallback(new osg::ScriptCallback(script_itr->second.get(), entry_point));
|
||||
node->addEventCallback(new osg::ScriptNodeCallback(script_itr->second.get(), entry_point));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user