Read canvas image by HTTP: Difference between revisions

Jump to navigation Jump to search
Line 184: Line 184:


== Patches ==
== Patches ==
=== SimGear ===
<syntaxhighlight lang="diff">
--- /simgear/simgear/canvas/Canvas.hxx 2016-05-17 02:40:01.297701130 +0200
+++ canvas/Canvas.hxx 2016-10-19 16:46:47.000000000 +0200
@@ -44,6 +44,14 @@
  class CanvasMgr;
  class MouseEvent;
+  class CanvasImageReadyListener {
+  public:
+    virtual void imageReady(osg::ref_ptr<osg::Image>) = 0;
+    virtual ~CanvasImageReadyListener()
+    {
+    }
+  };
+
  /**
    * Canvas to draw onto (to an off-screen render target).
    */
@@ -162,6 +170,9 @@
      void update(double delta_time_sec);
+      int subscribe(CanvasImageReadyListener * subscriber);
+      int unsubscribe(CanvasImageReadyListener * subscriber);
+
      bool addEventListener(const std::string& type, const EventListener& cb);
      bool dispatchEvent(const EventPtr& event);
</syntaxhighlight>
<syntaxhighlight lang="diff">
--- /simgear/simgear/canvas/Canvas.cxx 2016-05-17 02:40:01.297701130 +0200
+++ Canvas.cxx 2016-10-20 08:04:14.000000000 +0200
@@ -37,6 +37,66 @@
{
namespace canvas
{
+  class CanvasImageCallback : public osg::Camera::DrawCallback {
+  public:
+  osg::Image *_rawImage;
+
+  CanvasImageCallback(osg::Image *rawImage)
+  : _min_delta_tick(1.0 / 8.0) {
+    _previousFrameTick = osg::Timer::instance()->tick();
+    _rawImage = rawImage;
+  }
+
+  virtual void operator()(osg::RenderInfo& renderInfo/*const osg::Camera& camera*/) const {
+    osg::Timer_t n = osg::Timer::instance()->tick();
+    double dt = osg::Timer::instance()->delta_s(_previousFrameTick, n);
+    if (dt < _min_delta_tick)
+      return;
+    _previousFrameTick = n;
+
+    bool hasSubscribers = false;
+    {
+      OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_lock);
+      hasSubscribers = !_subscribers.empty();
+    }
+    if (hasSubscribers) {
+      //Make sure image can be overwritten by next frame while it is still returned to the client
+      osg::Image* image = new osg::Image(*_rawImage, osg::CopyOp::DEEP_COPY_ALL);
+      {
+        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_lock);
+        while (!_subscribers.empty()) {
+          try {
+            SG_LOG(SG_GENERAL,SG_INFO,"CanvasImageCallback image ready for subscriber");
+            CanvasImageReadyListener *subs = _subscribers.back();
+            if (subs){
+              subs->imageReady(image);
+            }else{
+              SG_LOG(SG_GENERAL,SG_WARN,"CanvasImageCallback subscriber null");
+            }
+          } catch (...) { }
+          _subscribers.pop_back();
+        }
+      }
+    }
+  }
+
+  void subscribe(CanvasImageReadyListener * subscriber) {
+    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_lock);
+    _subscribers.push_back(subscriber);
+  }
+
+  void unsubscribe(CanvasImageReadyListener * subscriber) {
+    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_lock);
+    _subscribers.remove(subscriber);
+  }
+
+  private:
+    mutable list<CanvasImageReadyListener*> _subscribers;
+    mutable OpenThreads::Mutex _lock;
+    mutable double _previousFrameTick;
+    double _min_delta_tick;
+  };
+
  //----------------------------------------------------------------------------
  Canvas::CullCallback::CullCallback(const CanvasWeakPtr& canvas):
@@ -251,6 +311,22 @@
      osg::Camera* camera = _texture.getCamera();
+      const char *canvasname = _node->getStringValue("name");
+      int rendertoimage = _node->getBoolValue("rendertoimage");
+      if (camera && rendertoimage && canvasname) {
+        SG_LOG(SG_GENERAL,SG_INFO,"rendertoimage of canvas "<<  rendertoimage);
+
+        CanvasImageCallback *_screenshotCallback = dynamic_cast<CanvasImageCallback*> (camera->getFinalDrawCallback());
+        if (!_screenshotCallback) {
+          osg::Image* shot = new osg::Image();
+          shot->allocateImage(getSizeX(), getSizeY(), 24, GL_RGB, GL_UNSIGNED_BYTE);
+          camera->attach(osg::Camera::COLOR_BUFFER, shot);
+          camera->setFinalDrawCallback(new CanvasImageCallback(shot));
+          SG_LOG(SG_GENERAL,SG_INFO,"attached");
+        }
+      }
+
+
      // TODO Allow custom render order? For now just keep in order with
      //      property tree.
      camera->setRenderOrder(osg::Camera::PRE_RENDER, _node->getIndex());
@@ -350,6 +426,36 @@
    }
  }
+  int Canvas::subscribe(CanvasImageReadyListener * subscriber) {
+    if (!_node->getBoolValue("rendertoimage")) {
+      SG_LOG(SG_GENERAL,SG_INFO,"Setting rendertoimage");
+      _node->addChild("rendertoimage", 0)->setBoolValue(1);
+      setStatusFlags(STATUS_DIRTY, true);
+    }
+
+    osg::Camera* camera = _texture.getCamera();
+    SG_LOG(SG_GENERAL,SG_INFO,"Canvas: subscribe to camera "<< camera);
+    CanvasImageCallback *_screenshotCallback = dynamic_cast<CanvasImageCallback*> (camera->getFinalDrawCallback());
+    if (_screenshotCallback) {
+      SG_LOG(SG_GENERAL,SG_INFO,"Canvas: really subscribe to camera ");
+      _screenshotCallback->subscribe(subscriber);
+      // TODO: check: Is this the correct way to ensure the canvas will be available?
+      enableRendering(true);
+    }
+    return 0;
+  }
+
+  int Canvas::unsubscribe(CanvasImageReadyListener * subscriber) {
+    osg::Camera* camera = _texture.getCamera();
+    SG_LOG(SG_GENERAL,SG_INFO,"CanvasImage: unsubscribe from camera "<< camera);
+    CanvasImageCallback *cb = dynamic_cast<CanvasImageCallback*> (camera->getFinalDrawCallback());
+    if (cb) {
+      SG_LOG(SG_GENERAL,SG_INFO,"CanvasImage: unsubscribe ");
+      cb->unsubscribe(subscriber);
+    }
+    return 0;
+  }
+
  //----------------------------------------------------------------------------
  bool Canvas::addEventListener( const std::string& type,
                                  const EventListener& cb )
</syntaxhighlight>
=== FlightGear ===
=== FlightGear ===
<syntaxhighlight lang="diff">
<syntaxhighlight lang="diff">
183

edits

Navigation menu