summaryrefslogtreecommitdiffstats
path: root/src/uscxml/plugins
diff options
context:
space:
mode:
authorStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2013-02-25 12:28:05 (GMT)
committerStefan Radomski <radomski@tk.informatik.tu-darmstadt.de>2013-02-25 12:28:05 (GMT)
commit49c3c43d18c9cce6de305aae77cc8bd839506129 (patch)
treecfc4ea84416c76e8bbe3e27d2918321115b61e24 /src/uscxml/plugins
parent47956a35d11495f2ebf6988c7f9d9dffe0bd3a4b (diff)
downloaduscxml-49c3c43d18c9cce6de305aae77cc8bd839506129.zip
uscxml-49c3c43d18c9cce6de305aae77cc8bd839506129.tar.gz
uscxml-49c3c43d18c9cce6de305aae77cc8bd839506129.tar.bz2
Introduced postpone element and reorganized http request representation as events
Diffstat (limited to 'src/uscxml/plugins')
-rw-r--r--src/uscxml/plugins/element/postpone/PostponeElement.cpp97
-rw-r--r--src/uscxml/plugins/element/postpone/PostponeElement.h62
-rw-r--r--src/uscxml/plugins/element/response/ResponseElement.cpp38
-rw-r--r--src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.cpp48
-rw-r--r--src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.h40
-rw-r--r--src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp33
-rw-r--r--src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.cpp300
-rw-r--r--src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.h30
-rw-r--r--src/uscxml/plugins/invoker/http/HTTPServletInvoker.cpp13
-rw-r--r--src/uscxml/plugins/invoker/http/HTTPServletInvoker.h2
-rw-r--r--src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp7
-rw-r--r--src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h3
-rw-r--r--src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp19
13 files changed, 657 insertions, 35 deletions
diff --git a/src/uscxml/plugins/element/postpone/PostponeElement.cpp b/src/uscxml/plugins/element/postpone/PostponeElement.cpp
new file mode 100644
index 0000000..644cb1d
--- /dev/null
+++ b/src/uscxml/plugins/element/postpone/PostponeElement.cpp
@@ -0,0 +1,97 @@
+#include "PostponeElement.h"
+#include "uscxml/plugins/invoker/http/HTTPServletInvoker.h"
+#include <glog/logging.h>
+
+#ifdef BUILD_AS_PLUGINS
+#include <Pluma/Connector.hpp>
+#endif
+
+namespace uscxml {
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_CONNECTOR
+bool connect(pluma::Host& host) {
+ host.add( new PostponeElementProvider() );
+ return true;
+}
+#endif
+
+boost::shared_ptr<ExecutableContentImpl> PostponeElement::create(Interpreter* interpreter) {
+ boost::shared_ptr<PostponeElement> invoker = boost::shared_ptr<PostponeElement>(new PostponeElement());
+ invoker->_interpreter = interpreter;
+ return invoker;
+}
+
+void PostponeElement::enterElement(const Arabica::DOM::Node<std::string>& node) {
+ if (!_interpreter->getDataModel()) {
+ LOG(ERROR) << "Postpone element requires a datamodel";
+ return;
+ }
+
+ // under which condition will we postpone the current event?
+ if (HAS_ATTR(node, "cond")) {
+ std::string cond = ATTR(node, "cond");
+ try {
+ if (!_interpreter->getDataModel().evalAsBool(cond))
+ return;
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error in cond attribute of postpone element:" << std::endl << e << std::endl;
+ return;
+ }
+ }
+
+ // when will we refire the event?
+ if (!HAS_ATTR(node, "until")) {
+ LOG(ERROR) << "Postpone element requires until attribute ";
+ return;
+ }
+ std::string until = ATTR(node, "until");
+
+ Event currEvent = _interpreter->getCurrentEvent();
+ Resubmitter::postpone(currEvent, until, _interpreter);
+}
+
+void PostponeElement::exitElement(const Arabica::DOM::Node<std::string>& node) {
+}
+
+void PostponeElement::Resubmitter::postpone(const Event& event, std::string until, Interpreter* interpreter) {
+ Resubmitter* resubmitter = getInstance(interpreter);
+ resubmitter->_postponedEvents.push_back(std::make_pair(until, event));
+}
+
+void PostponeElement::Resubmitter::onStableConfiguration(Interpreter* interpreter) {
+ std::list<std::pair<std::string, Event> >::iterator eventIter = _postponedEvents.begin();
+ while(eventIter != _postponedEvents.end()) {
+ try {
+ if (interpreter->getDataModel().evalAsBool(eventIter->first)) {
+ interpreter->receive(eventIter->second, true);
+ _postponedEvents.erase(eventIter);
+ break;
+ }
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error in until attribute of postpone element:" << std::endl << e << std::endl;
+ _postponedEvents.erase(eventIter++);
+ continue;
+ }
+ eventIter++;
+ }
+}
+
+void PostponeElement::Resubmitter::afterCompletion(Interpreter* interpreter) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(PostponeElement::Resubmitter::_accessLock);
+ _instances.erase(interpreter);
+ delete this; // committing suicide is ok if we are careful
+}
+
+std::map<Interpreter*, PostponeElement::Resubmitter*> PostponeElement::Resubmitter::_instances;
+tthread::recursive_mutex PostponeElement::Resubmitter::_accessLock;
+
+PostponeElement::Resubmitter* PostponeElement::Resubmitter::getInstance(Interpreter* interpreter) {
+ tthread::lock_guard<tthread::recursive_mutex> lock(PostponeElement::Resubmitter::_accessLock);
+ if (_instances.find(interpreter) == _instances.end()) {
+ _instances[interpreter] = new Resubmitter(interpreter);
+ }
+ return _instances[interpreter];
+}
+
+} \ No newline at end of file
diff --git a/src/uscxml/plugins/element/postpone/PostponeElement.h b/src/uscxml/plugins/element/postpone/PostponeElement.h
new file mode 100644
index 0000000..03aafde
--- /dev/null
+++ b/src/uscxml/plugins/element/postpone/PostponeElement.h
@@ -0,0 +1,62 @@
+#ifndef POSTPONEELEMENT_H_WN8EIYYI
+#define POSTPONEELEMENT_H_WN8EIYYI
+
+#include <uscxml/Interpreter.h>
+#include <list>
+
+#ifdef BUILD_AS_PLUGINS
+#include "uscxml/plugins/Plugins.h"
+#endif
+
+namespace uscxml {
+
+class PostponeElement : public ExecutableContentImpl {
+public:
+ PostponeElement() {}
+ virtual ~PostponeElement() {}
+ boost::shared_ptr<ExecutableContentImpl> create(Interpreter* interpreter);
+
+ std::string getLocalName() {
+ return "postpone";
+ }
+
+ std::string getNamespace() {
+ return "http://www.w3.org/2005/07/scxml";
+ }
+
+ bool processChildren() {
+ return false;
+ }
+
+ void enterElement(const Arabica::DOM::Node<std::string>& node);
+ void exitElement(const Arabica::DOM::Node<std::string>& node);
+
+protected:
+ // once per interpreter
+ class Resubmitter : public InterpreterMonitor {
+ public:
+ Resubmitter(Interpreter* interpreter) {
+ interpreter->addMonitor(this);
+ }
+
+ static Resubmitter* getInstance(Interpreter* interpreter);
+ static void postpone(const Event& event, std::string until, Interpreter* interpreter);
+
+ // InterpreterMonitor
+ void onStableConfiguration(Interpreter* interpreter);
+ void afterCompletion(Interpreter* interpreter);
+
+ std::list<std::pair<std::string, Event> > _postponedEvents;
+ static std::map<Interpreter*, Resubmitter*> _instances;
+ static tthread::recursive_mutex _accessLock;
+
+ };
+};
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_INHERIT_PROVIDER(PostponeElement, Element);
+#endif
+
+}
+
+#endif /* end of include guard: POSTPONEELEMENT_H_WN8EIYYI */
diff --git a/src/uscxml/plugins/element/response/ResponseElement.cpp b/src/uscxml/plugins/element/response/ResponseElement.cpp
index 814f726..7f1a479 100644
--- a/src/uscxml/plugins/element/response/ResponseElement.cpp
+++ b/src/uscxml/plugins/element/response/ResponseElement.cpp
@@ -23,6 +23,7 @@ boost::shared_ptr<ExecutableContentImpl> ResponseElement::create(Interpreter* in
}
void ResponseElement::enterElement(const Arabica::DOM::Node<std::string>& node) {
+ // try to get the request id
if (!HAS_ATTR(node, "request") && !HAS_ATTR(node, "requestexpr")) {
LOG(ERROR) << "Response element requires request or requestexpr";
return;
@@ -31,12 +32,9 @@ void ResponseElement::enterElement(const Arabica::DOM::Node<std::string>& node)
LOG(ERROR) << "Response element with requestexpr requires datamodel";
return;
}
- if (HAS_ATTR(node, "close")) {
-
- }
-
std::string requestId = (HAS_ATTR(node, "request") ? ATTR(node, "request") : _interpreter->getDataModel().evalAsString(ATTR(node, "requestexpr")));
+ // try to get the request object
HTTPServletInvoker* servlet = _interpreter->getHTTPServlet();
tthread::lock_guard<tthread::recursive_mutex> lock(servlet->getMutex());
@@ -44,19 +42,39 @@ void ResponseElement::enterElement(const Arabica::DOM::Node<std::string>& node)
LOG(ERROR) << "No matching HTTP request for response element";
return;
}
+ HTTPServer::Request httpReq = servlet->getRequests()[requestId];
+ HTTPServer::Reply httpReply(httpReq);
+ // get the status or default to 200
std::string statusStr = (HAS_ATTR(node, "status") ? ATTR(node, "status") : "200");
if (!isNumeric(statusStr.c_str(), 10)) {
LOG(ERROR) << "Response element with non-numeric status " << statusStr;
return;
}
- int status = strTo<int>(statusStr);
-
- HTTPServer::Request httpReq = servlet->getRequests()[requestId];
-
- HTTPServer::Reply httpReply(httpReq);
- httpReply.status = status;
+ httpReply.status = strTo<int>(statusStr);;
+
+ // extract the content
+ Arabica::XPath::NodeSet<std::string> contents = Interpreter::filterChildElements(_interpreter->getXMLPrefixForNS(getNamespace()) + "content", node);
+ if (contents.size() > 0) {
+ if (HAS_ATTR(contents[0], "expr")) {
+ if (_interpreter->getDataModel()) {
+ try {
+ std::string contentValue = _interpreter->getDataModel().evalAsString(ATTR(contents[0], "expr"));
+ httpReply.content = contentValue;
+ } catch (Event e) {
+ LOG(ERROR) << "Syntax error with expr in content child of response element:" << std::endl << e << std::endl;
+ }
+ } else {
+ LOG(ERROR) << "content element has expr attribute but no datamodel is specified.";
+ }
+ } else if (contents[0].hasChildNodes()) {
+ httpReply.content = contents[0].getFirstChild().getNodeValue();
+ } else {
+ LOG(ERROR) << "content element does not specify any content.";
+ }
+ }
+ // send the reply
HTTPServer::reply(httpReply);
servlet->getRequests().erase(requestId);
}
diff --git a/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.cpp b/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.cpp
new file mode 100644
index 0000000..05af363
--- /dev/null
+++ b/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.cpp
@@ -0,0 +1,48 @@
+#include "FFMPEGInvoker.h"
+#include <glog/logging.h>
+
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+
+#ifdef BUILD_AS_PLUGINS
+#include <Pluma/Connector.hpp>
+#endif
+
+namespace uscxml {
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_CONNECTOR
+bool connect(pluma::Host& host) {
+ host.add( new FFMPEGInvokerProvider() );
+ return true;
+}
+#endif
+
+FFMPEGInvoker::FFMPEGInvoker() {
+}
+
+FFMPEGInvoker::~FFMPEGInvoker() {
+};
+
+boost::shared_ptr<IOProcessorImpl> FFMPEGInvoker::create(Interpreter* interpreter) {
+ boost::shared_ptr<FFMPEGInvoker> invoker = boost::shared_ptr<FFMPEGInvoker>(new FFMPEGInvoker());
+ invoker->_interpreter = interpreter;
+ return invoker;
+}
+
+Data FFMPEGInvoker::getDataModelVariables() {
+ Data data;
+ return data;
+}
+
+void FFMPEGInvoker::send(const SendRequest& req) {
+}
+
+void FFMPEGInvoker::cancel(const std::string sendId) {
+}
+
+void FFMPEGInvoker::invoke(const InvokeRequest& req) {
+// AVIOContext* avCtx = avio_alloc_context();
+}
+
+} \ No newline at end of file
diff --git a/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.h b/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.h
new file mode 100644
index 0000000..9b1b0ca
--- /dev/null
+++ b/src/uscxml/plugins/invoker/ffmpeg/FFMPEGInvoker.h
@@ -0,0 +1,40 @@
+#ifndef FFMPEGINVOKER_H_VQD1V1C2
+#define FFMPEGINVOKER_H_VQD1V1C2
+
+#include <uscxml/Interpreter.h>
+
+#ifdef BUILD_AS_PLUGINS
+#include "uscxml/plugins/Plugins.h"
+#endif
+
+namespace uscxml {
+
+class FFMPEGInvoker : public InvokerImpl {
+public:
+ FFMPEGInvoker();
+ virtual ~FFMPEGInvoker();
+ virtual boost::shared_ptr<IOProcessorImpl> create(Interpreter* interpreter);
+
+ virtual std::set<std::string> getNames() {
+ std::set<std::string> names;
+ names.insert("ffmpeg");
+ names.insert("http://uscxml.tk.informatik.tu-darmstadt.de/#ffmpeg");
+ return names;
+ }
+
+ virtual Data getDataModelVariables();
+ virtual void send(const SendRequest& req);
+ virtual void cancel(const std::string sendId);
+ virtual void invoke(const InvokeRequest& req);
+
+protected:
+};
+
+#ifdef BUILD_AS_PLUGINS
+PLUMA_INHERIT_PROVIDER(FFMPEGInvoker, Invoker);
+#endif
+
+}
+
+
+#endif /* end of include guard: FFMPEGINVOKER_H_VQD1V1C2 */
diff --git a/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp b/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp
index 9486de3..e34517d 100644
--- a/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp
+++ b/src/uscxml/plugins/invoker/filesystem/dirmon/DirMonInvoker.cpp
@@ -1,6 +1,8 @@
#include "DirMonInvoker.h"
#include <glog/logging.h>
+#include "uscxml/config.h"
+
#ifdef BUILD_AS_PLUGINS
#include <Pluma/Connector.hpp>
#endif
@@ -111,13 +113,38 @@ void DirMonInvoker::handleFileAction(FW::WatchID watchid, const FW::String& dir,
case FW::Actions::Modified:
event.name = "file.modified";
break;
-
default:
break;
}
- event.data.compound["file"].compound["name"] = Data(filename, Data::VERBATIM);
- event.data.compound["file"].compound["dir"] = Data(dir, Data::VERBATIM);
+ std::string basename;
+ size_t lastSep;
+ if ((lastSep = filename.find_last_of(PATH_SEPERATOR)) != std::string::npos) {
+ lastSep++;
+ basename = filename.substr(lastSep, filename.length() - lastSep);
+ } else {
+ basename = filename;
+ }
+
+ std::string extension;
+ size_t lastDot;
+ if ((lastDot = basename.find_last_of(".")) != std::string::npos) {
+ lastDot++;
+ extension = basename.substr(lastDot, basename.length() - lastDot);
+ }
+
+ std::string relPath;
+ if (boost::algorithm::starts_with(filename, dir)) {
+ relPath = filename.substr(dir.length());
+ } else {
+ relPath = filename;
+ }
+
+ event.data.compound["file"].compound["name"] = Data(basename, Data::VERBATIM);
+ event.data.compound["file"].compound["path"] = Data(filename, Data::VERBATIM);
+ event.data.compound["file"].compound["relPath"] = Data(relPath, Data::VERBATIM);
+ event.data.compound["file"].compound["dir"] = Data(dir, Data::VERBATIM);
+ event.data.compound["file"].compound["extension"] = Data(extension, Data::VERBATIM);
event.data.compound["file"].compound["mtime"] = toStr(fileStat.st_mtime);
event.data.compound["file"].compound["ctime"] = toStr(fileStat.st_ctime);
diff --git a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.cpp b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.cpp
index 49c9ccb..726cd08 100644
--- a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.cpp
+++ b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.cpp
@@ -1,5 +1,12 @@
#include "OSGConverter.h"
#include <glog/logging.h>
+#include "uscxml/config.h"
+
+#include <osg/MatrixTransform>
+#include <osgDB/ReadFile>
+#include <osgDB/WriteFile>
+#include <osgDB/Registry>
+#include <osgGA/TrackballManipulator>
#ifdef BUILD_AS_PLUGINS
#include <Pluma/Connector.hpp>
@@ -15,10 +22,15 @@ bool connect(pluma::Host& host) {
}
#endif
-OSGConverter::OSGConverter() {
+OSGConverter::OSGConverter() : _isRunning(false) {
}
OSGConverter::~OSGConverter() {
+ _isRunning = false;
+ std::set<tthread::thread*>::iterator threadIter = _threads.begin();
+ while(threadIter != _threads.end()) {
+ (*threadIter)->join();
+ }
};
boost::shared_ptr<IOProcessorImpl> OSGConverter::create(Interpreter* interpreter) {
@@ -33,16 +45,294 @@ Data OSGConverter::getDataModelVariables() {
}
void OSGConverter::send(const SendRequest& req) {
- std::cout << req << std::endl;
- Event event;
- event.name = "error";
- returnEvent(event);
+
+ /**
+ * we have to resolve all datamodel dependent strings first as
+ * we cannot access the datamodel from within another thread without locking
+ */
+
+ // make a copy
+ SendRequest actualReq(req);
+
+ if (actualReq.params.find("source") == actualReq.params.end()) {
+ // no explicit source
+ if (actualReq.params.find("sourceexpr") != actualReq.params.end() && _interpreter->getDataModel()) {
+ actualReq.params.insert(std::make_pair("source", _interpreter->getDataModel().evalAsString(actualReq.params.find("sourceexpr")->second)));
+ } else {
+ LOG(ERROR) << "SendRequests for osginvoker missing source or sourceExpr and datamodel";
+ return;
+ }
+ }
+
+ if (actualReq.params.find("dest") == actualReq.params.end()) {
+ // no explicit destination
+ if (actualReq.params.find("destexpr") != actualReq.params.end() && _interpreter->getDataModel()) {
+ actualReq.params.insert(std::make_pair("dest", _interpreter->getDataModel().evalAsString(actualReq.params.find("destexpr")->second)));
+ } else {
+ LOG(ERROR) << "SendRequests for osginvoker missing dest or destExpr and datamodel";
+ return;
+ }
+ }
+
+ if (actualReq.params.find("format") == actualReq.params.end()) {
+ // no explicit format
+ if (actualReq.params.find("formatexpr") != actualReq.params.end() && _interpreter->getDataModel()) {
+ actualReq.params.insert(std::make_pair("format", _interpreter->getDataModel().evalAsString(actualReq.params.find("formatexpr")->second)));
+ } else {
+ std::string format;
+ size_t lastDot;
+ std::string dest = req.params.find("dest")->second;
+ if ((lastDot = dest.find_last_of(".")) != std::string::npos) {
+ lastDot++;
+ format = dest.substr(lastDot, dest.length() - lastDot);
+ }
+ if (format.length() == 0 || format.find_last_of(PATH_SEPERATOR) != std::string::npos) {
+ // empty format or pathseperator in format
+ format = "png";
+ }
+ actualReq.params.insert(std::make_pair("format", format));
+ }
+ }
+
+ if (actualReq.params.find("height") == actualReq.params.end()) {
+ // no explicit height
+ if (actualReq.params.find("heightexpr") != actualReq.params.end() && _interpreter->getDataModel()) {
+ actualReq.params.insert(std::make_pair("height", _interpreter->getDataModel().evalAsString(actualReq.params.find("heightexpr")->second)));
+ }
+ }
+
+ if (actualReq.params.find("width") == actualReq.params.end()) {
+ // no explicit width
+ if (actualReq.params.find("widthexpr") != actualReq.params.end() && _interpreter->getDataModel()) {
+ actualReq.params.insert(std::make_pair("width", _interpreter->getDataModel().evalAsString(actualReq.params.find("widthexpr")->second)));
+ }
+ }
+
+ _workQueue.push(actualReq);
}
void OSGConverter::cancel(const std::string sendId) {
}
void OSGConverter::invoke(const InvokeRequest& req) {
+ int nrThreads = 1;
+ if (req.params.find("threads") != req.params.end() && isNumeric(req.params.find("threads")->second.c_str(), 10)) {
+ nrThreads = strTo<int>(req.params.find("threads")->second);
+ }
+
+ _isRunning = true;
+ for (int i = 0; i < nrThreads; i++) {
+ _threads.insert(new tthread::thread(OSGConverter::run, this));
+ }
+}
+
+void OSGConverter::run(void* instance) {
+ OSGConverter* INSTANCE = (OSGConverter*)instance;
+ while(true) {
+ SendRequest req = INSTANCE->_workQueue.pop();
+ if (INSTANCE->_isRunning) {
+ INSTANCE->process(req);
+ } else {
+ return;
+ }
+ }
+}
+
+void OSGConverter::process(const SendRequest& req) {
+
+ int width = (req.params.find("width") != req.params.end() ? strTo<int>(req.params.find("width")->second) : 640);
+ int height = (req.params.find("height") != req.params.end() ? strTo<int>(req.params.find("height")->second) : 480);
+
+ assert(req.params.find("source") != req.params.end());
+ assert(req.params.find("dest") != req.params.end());
+ assert(req.params.find("format") != req.params.end());
+
+ std::string source = req.params.find("source")->second;
+ std::string dest = req.params.find("dest")->second;
+ std::string format = req.params.find("format")->second;
+
+ osg::ref_ptr<osg::Node> sceneGraph = setupGraph(source);
+
+ osgDB::ReaderWriter::WriteResult result;
+ if (osgDB::Registry::instance()->getReaderWriterForExtension(format) != NULL) {
+ // write as another 3D file
+ result = osgDB::Registry::instance()->writeNode(*sceneGraph, dest, osgDB::Registry::instance()->getOptions());
+ }
+
+ if (result.error()) {
+ // make a screenshot
+ osgViewer::ScreenCaptureHandler::CaptureOperation* cOp = new NameRespectingWriteToFile(dest,
+ format,
+ osgViewer::ScreenCaptureHandler::WriteToFile::OVERWRITE
+ );
+
+ osgViewer::ScreenCaptureHandler* captureHandler = new osgViewer::ScreenCaptureHandler(cOp, -1);
+
+ osgViewer::Viewer viewer;
+ viewer.setSceneData(sceneGraph);
+ viewer.setCameraManipulator(new osgGA::TrackballManipulator());
+ viewer.addEventHandler(captureHandler);
+ captureHandler->startCapture();
+
+ osg::DisplaySettings* ds = osg::DisplaySettings::instance().get();
+ osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits(ds);
+ traits->width = width;
+ traits->height = height;
+ traits->pbuffer = true;
+ osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());
+ GLenum pbuffer = gc->getTraits()->doubleBuffer ? GL_BACK : GL_FRONT;
+
+ viewer.getCamera()->setGraphicsContext(gc.get());
+ viewer.getCamera()->setViewport(new osg::Viewport(0,0,traits->width,traits->height));
+ viewer.getCamera()->setDrawBuffer(pbuffer);
+ viewer.getCamera()->setReadBuffer(pbuffer);
+
+ // set background color
+ viewer.getCamera()->setClearColor(osg::Vec4f(1.0f,1.0f,1.0f,1.0f));
+ viewer.getCamera()->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ ((osg::MatrixTransform*)sceneGraph.get())->setMatrix(requestToModelPose(req));
+ viewer.getCamera()->setViewMatrix(requestToCamPose(req));
+
+// viewer.home();
+
+ // perform one viewer iteration
+ viewer.realize();
+ viewer.frame();
+ }
+}
+
+osg::Matrix OSGConverter::requestToModelPose(const SendRequest& req) {
+ double pitch = (req.params.find("pitch") != req.params.end() ? strTo<int>(req.params.find("pitch")->second) : 0);
+ double roll = (req.params.find("roll") != req.params.end() ? strTo<int>(req.params.find("roll")->second) : 0);
+ double yaw = (req.params.find("yaw") != req.params.end() ? strTo<int>(req.params.find("yaw")->second) : 0);
+
+ return eulerToMatrix(pitch, roll, yaw);
+// osg::Matrix m;
+// m.makeIdentity();
+// return m;
+}
+
+osg::Matrix OSGConverter::requestToCamPose(const SendRequest& req) {
+ return eulerToMatrix(0, 0, 0);
+}
+
+osg::ref_ptr<osg::Node> OSGConverter::setupGraph(const std::string filename) {
+
+ /**
+ * root (model pose)
+ * - modelCenter (center model)
+ * - model (actual model)
+ */
+
+ long now = tthread::chrono::system_clock::now();
+
+ {
+ // get some privacy
+ tthread::lock_guard<tthread::recursive_mutex> lock(_cacheMutex);
+
+ // do we have it in the cache?
+ if (_models.find(filename) == _models.end()) {
+ osg::ref_ptr<osg::Node> model = osgDB::readNodeFile(filename);
+ if (!model.valid()) {
+ LOG(ERROR) << "Cannot load model from " << filename;
+ return new osg::MatrixTransform();
+ }
+ _models[filename] = std::make_pair(now, model);
+ }
+
+ // remove old models from cache
+ std::map<std::string, std::pair<long, osg::ref_ptr<osg::Node> > >::iterator modelIter = _models.begin();
+ while(modelIter != _models.end()) {
+ // delete every model unused for 1 minutes
+ if (now - modelIter->second.first > 60000) {
+ _models.erase(modelIter++);
+ } else {
+ modelIter++;
+ }
+ }
+ }
+
+ osg::ref_ptr<osg::MatrixTransform> root = new osg::MatrixTransform();
+
+ osg::ref_ptr<osg::Node> model = _models[filename].second;
+ _models[filename].first = now;
+
+ // translation matrix to move model into center
+ osg::ref_ptr<osg::MatrixTransform> modelCenter = new osg::MatrixTransform();
+ modelCenter->addChild(model);
+
+ // move bounding sphere center into origin
+ osg::BoundingSphere bs = model->getBound();
+ modelCenter->setMatrix(osg::Matrix::translate(bs.center() *= -1));
+
+ // add to model pose matrix
+ root->addChild(modelCenter);
+
+ return root;
+}
+
+osg::Matrix OSGConverter::eulerToMatrix(double pitch, double roll, double yaw) {
+ // see http://www.flipcode.com/documents/matrfaq.html#Q36
+ osg::Matrix m;
+ m.makeIdentity();
+
+ double A = cos(pitch);
+ double B = sin(pitch);
+ double C = cos(roll);
+ double D = sin(roll);
+ double E = cos(yaw);
+ double F = sin(yaw);
+
+ double AD = A * D;
+ double BD = B * D;
+
+ m(0,0) = C * E;
+ m(0,1) = -C * F;
+ m(0,2) = -D;
+ m(1,0) = -BD * E + A * F;
+ m(1,1) = BD * F + A * E;
+ m(1,2) = -B * C;
+ m(2,0) = AD * E + B * F;
+ m(2,1) = -AD * F + B * E;
+ m(2,2) = A * C;
+
+ m(0,3) = m(1,3) = m(2,3) = m(3,0) = m(3,1) = m(3,2) = 0;
+ m(3,3) = 1;
+
+ return m;
+}
+
+void OSGConverter::matrixToEuler(const osg::Matrix& m, double& pitch, double& roll, double& yaw) {
+ // see: http://www.flipcode.com/documents/matrfaq.html#Q37
+ double angle_x, angle_z;
+ double D = -1 * asin(m(0,2)); /* Calculate Y-axis angle */
+ double angle_y = D;
+ double C = cos(angle_y);
+
+ /* Gimball lock? */
+ if ( fabs( C ) > 0.005 ) {
+ double tr_x = m(2,2) / C; /* No, so get X-axis angle */
+ double tr_y = -1 * m(1,2) / C;
+ angle_x = atan2( tr_y, tr_x );
+ tr_x = m(0,0) / C; /* Get Z-axis angle */
+ tr_y = -1 * m(0,1) / C;
+ angle_z = atan2( tr_y, tr_x );
+ } else {
+ /* Gimball lock has occurred */
+ angle_x = 0; /* Set X-axis angle to zero */
+ double tr_x = m(1,1); /* And calculate Z-axis angle */
+ double tr_y = m(1,0);
+ angle_z = atan2( tr_y, tr_x );
+ }
+
+ pitch = fmod(angle_x, 2 * M_PI ); /* Clamp all angles to range */
+ roll = fmod( angle_y, 2 * M_PI );
+ yaw = fmod( angle_z, 2 * M_PI );
+}
+
+void OSGConverter::NameRespectingWriteToFile::operator()(const osg::Image& image, const unsigned int context_id) {
+ osgDB::writeImageFile(image, _filename);
}
} \ No newline at end of file
diff --git a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.h b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.h
index c52b1ee..e96a4e9 100644
--- a/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.h
+++ b/src/uscxml/plugins/invoker/graphics/openscenegraph/OSGConverter.h
@@ -2,6 +2,8 @@
#define OSGCONVERTER_H_W09J90F0
#include <uscxml/Interpreter.h>
+#include <osg/Node>
+#include <osgViewer/ViewerEventHandlers>
#ifdef BUILD_AS_PLUGINS
#include "uscxml/plugins/Plugins.h"
@@ -29,7 +31,35 @@ public:
virtual void cancel(const std::string sendId);
virtual void invoke(const InvokeRequest& req);
+ osg::Matrix requestToModelPose(const SendRequest& req);
+ osg::Matrix requestToCamPose(const SendRequest& req);
+
+ static osg::Matrix eulerToMatrix(double pitch, double roll, double yaw);
+ static void matrixToEuler(const osg::Matrix& m, double& pitch, double& roll, double& yaw);
+
protected:
+ class NameRespectingWriteToFile : public osgViewer::ScreenCaptureHandler::WriteToFile {
+ public:
+ NameRespectingWriteToFile(const std::string& filename,
+ const std::string& extension,
+ SavePolicy savePolicy) : osgViewer::ScreenCaptureHandler::WriteToFile(filename, extension, savePolicy) {
+ }
+
+ virtual void operator()(const osg::Image& image, const unsigned int context_id);
+ };
+
+ uscxml::concurrency::BlockingQueue<SendRequest> _workQueue;
+ osg::ref_ptr<osg::Node> setupGraph(const std::string filename);
+
+ std::map<std::string, std::pair<long, osg::ref_ptr<osg::Node> > > _models;
+ tthread::recursive_mutex _cacheMutex;
+
+ std::set<tthread::thread*> _threads;
+
+ static void run(void*);
+ void process(const SendRequest& req);
+
+ bool _isRunning;
};
#ifdef BUILD_AS_PLUGINS
diff --git a/src/uscxml/plugins/invoker/http/HTTPServletInvoker.cpp b/src/uscxml/plugins/invoker/http/HTTPServletInvoker.cpp
index 78e3bea..753877c 100644
--- a/src/uscxml/plugins/invoker/http/HTTPServletInvoker.cpp
+++ b/src/uscxml/plugins/invoker/http/HTTPServletInvoker.cpp
@@ -117,25 +117,16 @@ void HTTPServletInvoker::httpRecvRequest(const HTTPServer::Request& req) {
_requests[toStr((uintptr_t)req.curlReq)] = req;
- Event event;
+ Event event = req;
if (_isInterpreterGlobal) {
- event.name = "http." + req.type;
+ event.name = "http." + event.data.compound["type"].atom;
event.origin = toStr((uintptr_t)req.curlReq);
} else {
event.name = _callback;
event.data.compound["reqId"] = Data(toStr((uintptr_t)req.curlReq), Data::VERBATIM);
}
- std::map<std::string, std::string>::const_iterator headerIter = req.headers.begin();
- while(headerIter != req.headers.end()) {
- event.data.compound["headers"].compound[headerIter->first] = Data(headerIter->second, Data::VERBATIM);
- headerIter++;
- }
-
- event.data.compound["content"] = Data(req.content, Data::VERBATIM);
- event.data.compound["type"] = Data(req.type, Data::VERBATIM);
-
returnEvent(event);
}
diff --git a/src/uscxml/plugins/invoker/http/HTTPServletInvoker.h b/src/uscxml/plugins/invoker/http/HTTPServletInvoker.h
index 4ac87e0..c9fe844 100644
--- a/src/uscxml/plugins/invoker/http/HTTPServletInvoker.h
+++ b/src/uscxml/plugins/invoker/http/HTTPServletInvoker.h
@@ -19,7 +19,7 @@ public:
virtual std::set<std::string> getNames() {
std::set<std::string> names;
- names.insert("httpserver");
+ names.insert("httpservlet");
names.insert("http://uscxml.tk.informatik.tu-darmstadt.de/#httpserver");
return names;
}
diff --git a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp
index 4f7d61d..b7d08c4 100644
--- a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp
+++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.cpp
@@ -54,9 +54,10 @@ void USCXMLInvoker::invoke(const InvokeRequest& req) {
}
}
-void USCXMLInvoker::push(Event& event) {
- event.invokeid = _invokeId;
- _parentInterpreter->receive(event);
+void USCXMLInvoker::push(const Event& event) {
+ Event copyEvent(event);
+ copyEvent.invokeid = _invokeId;
+ _parentInterpreter->receive(copyEvent);
}
} \ No newline at end of file
diff --git a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h
index 792cc5d..aedef32 100644
--- a/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h
+++ b/src/uscxml/plugins/invoker/scxml/USCXMLInvoker.h
@@ -23,6 +23,7 @@ public:
virtual boost::shared_ptr<IOProcessorImpl> create(Interpreter* interpreter);
virtual std::set<std::string> getNames() {
std::set<std::string> names;
+ names.insert("scxml");
names.insert("uscxml");
names.insert("http://www.w3.org/TR/scxml");
names.insert("http://www.w3.org/TR/scxml/");
@@ -34,7 +35,7 @@ public:
virtual void cancel(const std::string sendId);
virtual void invoke(const InvokeRequest& req);
- virtual void push(Event& event);
+ virtual void push(const Event& event);
protected:
Interpreter* _invokedInterpreter;
diff --git a/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp
index 1b58785..6c7a8fc 100644
--- a/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp
+++ b/src/uscxml/plugins/ioprocessor/basichttp/libevent/EventIOProcessor.cpp
@@ -67,10 +67,26 @@ Data EventIOProcessor::getDataModelVariables() {
}
void EventIOProcessor::httpRecvRequest(const HTTPServer::Request& req) {
- Event reqEvent;
+ Event reqEvent = req;
reqEvent.type = Event::EXTERNAL;
bool scxmlStructFound = false;
+ if (reqEvent.data.compound["header"].compound.find("_scxmleventstruct") != reqEvent.data.compound["header"].compound.end()) {
+ // TODO: this looses all other information
+ reqEvent = Event::fromXML(evhttp_decode_uri(reqEvent.data.compound["header"].compound["_scxmleventstruct"].atom.c_str()));
+ scxmlStructFound = true;
+ }
+ if (reqEvent.data.compound["header"].compound.find("_scxmleventname") != reqEvent.data.compound["header"].compound.end()) {
+ reqEvent.name = evhttp_decode_uri(reqEvent.data.compound["header"].compound["_scxmleventname"].atom.c_str());
+ }
+
+ std::map<std::string, Data>::iterator headerIter = reqEvent.data.compound["header"].compound.begin();
+ while(headerIter != reqEvent.data.compound["header"].compound.end()) {
+ reqEvent.data.compound[headerIter->first] = Data(evhttp_decode_uri(headerIter->second.atom.c_str()), Data::VERBATIM);
+ headerIter++;
+ }
+
+#if 0
std::map<std::string, std::string>::const_iterator headerIter = req.headers.begin();
while(headerIter != req.headers.end()) {
if (boost::iequals("_scxmleventstruct", headerIter->first)) {
@@ -84,6 +100,7 @@ void EventIOProcessor::httpRecvRequest(const HTTPServer::Request& req) {
}
headerIter++;
}
+#endif
if (reqEvent.name.length() == 0)
reqEvent.name = req.type;