]> git.mxchange.org Git - flightgear.git/commitdiff
Canvas: Allow using canvases as PUI widgets.
authorThomas Geymayer <tomgey@gmail.com>
Wed, 4 Jul 2012 11:15:12 +0000 (13:15 +0200)
committerThomas Geymayer <tomgey@gmail.com>
Tue, 31 Jul 2012 21:19:22 +0000 (23:19 +0200)
 - Add new widget type canvas
 - Set canvas view dimension from the gui xml.
 - Expose mouse events to canvas widget properties.

12 files changed:
src/Canvas/canvas.cxx
src/Canvas/canvas.hxx
src/Canvas/canvas_mgr.cxx
src/Canvas/canvas_mgr.hxx
src/GUI/CMakeLists.txt
src/GUI/CanvasWidget.cxx [new file with mode: 0644]
src/GUI/CanvasWidget.hxx [new file with mode: 0644]
src/GUI/FGPUIDialog.cxx
src/Instrumentation/od_gauge.hxx
src/Main/fg_init.cxx
src/Scripting/NasalSys.cxx
src/Scripting/NasalSys.hxx

index 7f2c8590296ccd1883ea5d7db38a6045ae0c4918..43878a124280f5ba6547bf67d878239b4096e69b 100644 (file)
 
 #include "canvas.hxx"
 #include "elements/group.hxx"
+
 #include <Canvas/property_helper.hxx>
+#include <Main/globals.hxx>
+#include <Viewer/renderer.hxx>
 
 #include <osg/Camera>
 #include <osg/Geode>
 #include <osgText/Text>
+#include <osgViewer/Viewer>
 
 #include <iostream>
 
@@ -97,13 +101,13 @@ Canvas::Canvas():
   _status(0),
   _sampling_dirty(false),
   _color_dirty(true),
-  _node(0)
+  _node(0),
+  _render_always(false)
 {
   setStatusFlags(MISSING_SIZE_X | MISSING_SIZE_Y);
 
-  CameraCullCallback *camera_callback = new CameraCullCallback;
-  _camera_callback = camera_callback;
-  _cull_callback = new PlacementCullCallback(this, camera_callback);
+  _camera_callback = new CameraCullCallback;
+  _cull_callback = new PlacementCullCallback(this, _camera_callback);
 }
 
 //------------------------------------------------------------------------------
@@ -254,6 +258,9 @@ void Canvas::update(double delta_time_sec)
       _cull_callback
     );
   }
+
+  if( _render_always )
+    _camera_callback->enableRendering();
 }
 
 //------------------------------------------------------------------------------
@@ -398,11 +405,38 @@ void Canvas::valueChanged(SGPropertyNode* node)
         || node->getNameString() == "coverage-samples"
         || node->getNameString() == "color-samples" )
       _sampling_dirty = true;
+    else if( node->getNameString() == "render-always" )
+      _render_always = node->getBoolValue();
   }
 
   _root_group->valueChanged(node);
 }
 
+//------------------------------------------------------------------------------
+GLuint Canvas::getTexId() const
+{
+  osg::Texture2D* tex = _texture.getTexture();
+  if( !tex )
+    return 0;
+
+  osgViewer::Viewer::Contexts contexts;
+  globals->get_renderer()->getViewer()->getContexts(contexts);
+
+  if( contexts.empty() )
+    return 0;
+
+  osg::State* state = contexts[0]->getState();
+  if( !state )
+    return 0;
+
+  osg::Texture::TextureObject* tobj =
+    tex->getTextureObject( state->getContextID() );
+  if( !tobj )
+    return 0;
+
+  return tobj->_id;
+}
+
 //------------------------------------------------------------------------------
 void Canvas::setStatusFlags(unsigned int flags, bool set)
 {
index 25f87012d3c98fafc3226093a3b6bfc90c7c4836..a10713bd4f78b414a28d99ccb72900fde7c089f7 100644 (file)
@@ -31,6 +31,7 @@ namespace canvas
   class Group;
 }
 
+class CameraCullCallback;
 class Canvas:
   public SGPropertyChangeListener
 {
@@ -71,6 +72,8 @@ class Canvas:
                                SGPropertyNode * child );
     virtual void valueChanged (SGPropertyNode * node);
 
+    GLuint getTexId() const;
+
   private:
 
     Canvas(const Canvas&); // = delete;
@@ -93,8 +96,11 @@ class Canvas:
     SGPropertyNode_ptr              _node;
     std::vector<SGPropertyNode_ptr> _color_background;
 
-    osg::ref_ptr<osg::NodeCallback> _camera_callback;
+    osg::ref_ptr<CameraCullCallback> _camera_callback;
     osg::ref_ptr<osg::NodeCallback> _cull_callback;
+
+    bool _render_always; //<! Used to disable automatic lazy rendering (culling)
+
     std::vector<SGPropertyNode*> _dirty_placements;
     std::vector<Placements> _placements;
 
index 72db55fd0dea11c6f4d6fff7f3818e14a6909baa..b8300654a669ee18275ca552a931b988b7a573bf 100644 (file)
@@ -107,6 +107,16 @@ void CanvasMgr::childRemoved( SGPropertyNode * parent,
   }
 }
 
+//------------------------------------------------------------------------------
+unsigned int CanvasMgr::getCanvasTexId(size_t index) const
+{
+  if(    index >= _canvases.size()
+      || !_canvases[index] )
+    return 0;
+
+  return _canvases[index]->getTexId();
+}
+
 //------------------------------------------------------------------------------
 void CanvasMgr::textureAdded(SGPropertyNode* node)
 {
@@ -119,10 +129,8 @@ void CanvasMgr::textureAdded(SGPropertyNode* node)
 
     _canvases.resize(index + 1);
   }
-  else
-  {
+  else if( _canvases[index] )
     SG_LOG(SG_GL, SG_WARN, "texture[" << index << "] already exists!");
-  }
 
   _canvases[index].reset( new Canvas() );
   _canvases[index]->reset(node);
index 893b50e887e7fc77c094671034e27518611bbfef..d1ae926032ab63b785ab71263bfc7245db27c5e1 100644 (file)
@@ -50,6 +50,14 @@ class CanvasMgr:
     virtual void childRemoved( SGPropertyNode * parent,
                                SGPropertyNode * child );
 
+    /**
+     * Get OpenGL texture name for given canvas
+     *
+     * @param Index of canvas
+     * @return OpenGL texture name
+     */
+    unsigned int getCanvasTexId(size_t index) const;
+
   private:
 
     /** Root node for everything concerning the canvas system */
index 0a7fe3fb0b36892f79406fff49b43f624ac7aec0..b021d840b13c711aa42c51990ed9913ab1af7ee2 100644 (file)
@@ -2,6 +2,7 @@ include(FlightGearComponent)
 
 set(SOURCES
        AirportList.cxx
+       CanvasWidget.cxx
        MapWidget.cxx
        WaypointList.cxx
        dialog.cxx
@@ -21,6 +22,7 @@ set(SOURCES
 
 set(HEADERS
        AirportList.hxx
+       CanvasWidget.hxx
        MapWidget.hxx
        WaypointList.hxx
        dialog.hxx
diff --git a/src/GUI/CanvasWidget.cxx b/src/GUI/CanvasWidget.cxx
new file mode 100644 (file)
index 0000000..f1647d4
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * CanvasWidget.cxx
+ *
+ *  Created on: 03.07.2012
+ *      Author: tom
+ */
+
+#include "CanvasWidget.hxx"
+
+#include <Canvas/canvas_mgr.hxx>
+#include <Main/fg_os.hxx>      // fgGetKeyModifiers()
+#include <Scripting/NasalSys.hxx>
+
+//------------------------------------------------------------------------------
+CanvasWidget::CanvasWidget( int x, int y,
+                            int width, int height,
+                            SGPropertyNode* props,
+                            const std::string& module ):
+  puObject(x, y, width, height),
+  _canvas_mgr( dynamic_cast<CanvasMgr*>(globals->get_subsystem("Canvas")) ),
+  _tex_id(0),
+  _no_tex_cnt(0)
+{
+  if( !_canvas_mgr )
+  {
+    SG_LOG(SG_GENERAL, SG_ALERT, "CanvasWidget: failed to get canvas manager!");
+    return;
+  }
+
+  // Get the first unused canvas slot
+  SGPropertyNode* canvas_root = fgGetNode("/canvas", true);
+  for(int index = 0;; ++index)
+  {
+    if( !canvas_root->getChild("texture", index) )
+    {
+      int view[2] = {
+        // Get canvas viewport size. If not specified use the widget dimensions
+        props->getIntValue("view[0]", width),
+        props->getIntValue("view[1]", height)
+      };
+      _canvas = canvas_root->getChild("texture", index, true);
+      _canvas->setIntValue("size[0]", view[0] * 2); // use higher resolution
+      _canvas->setIntValue("size[1]", view[1] * 2); // for antialias
+      _canvas->setIntValue("view[0]", view[0]);
+      _canvas->setIntValue("view[1]", view[1]);
+      _canvas->setBoolValue("render-always", true);
+      _canvas->setStringValue( "name",
+                               props->getStringValue("name", "gui-anonymous") );
+      SGPropertyNode* input = _canvas->getChild("input", 0, true);
+      _mouse_x = input->getChild("mouse-x", 0, true);
+      _mouse_y = input->getChild("mouse-y", 0, true);
+      _mouse_down = input->getChild("mouse-down", 0, true);
+      _mouse_drag = input->getChild("mouse-drag", 0, true);
+
+      SGPropertyNode *nasal = props->getNode("nasal");
+      if( !nasal )
+        break;
+
+      FGNasalSys *nas =
+        dynamic_cast<FGNasalSys*>(globals->get_subsystem("nasal"));
+      if( !nas )
+        SG_LOG( SG_GENERAL,
+                SG_ALERT,
+                "CanvasWidget: Failed to get nasal subsystem!" );
+
+      const std::string file = std::string("__canvas:")
+                             + _canvas->getStringValue("name");
+
+      SGPropertyNode *load = nasal->getNode("load");
+      if( load )
+      {
+        const char *s = load->getStringValue();
+        nas->handleCommand(module.c_str(), file.c_str(), s, _canvas);
+      }
+      break;
+    }
+  }
+}
+
+//------------------------------------------------------------------------------
+CanvasWidget::~CanvasWidget()
+{
+  if( _canvas )
+    _canvas->getParent()
+           ->removeChild(_canvas->getName(), _canvas->getIndex(), false);
+}
+
+//------------------------------------------------------------------------------
+void CanvasWidget::doHit(int button, int updown, int x, int y)
+{
+  puObject::doHit(button, updown, x, y);
+
+  // CTRL allows resizing and SHIFT allows moving the window
+  if( fgGetKeyModifiers() & (KEYMOD_CTRL | KEYMOD_SHIFT) )
+    return;
+
+  _mouse_x->setIntValue(x - abox.min[0]);
+  _mouse_y->setIntValue(y - abox.min[1]);
+
+  if( updown == PU_DRAG )
+    _mouse_drag->setIntValue(button);
+  else if( updown == PU_DOWN )
+    _mouse_down->setIntValue(button);
+
+  if( button != active_mouse_button )
+    return;
+
+  if (updown == PU_UP)
+    puDeactivateWidget();
+  else if (updown == PU_DOWN)
+    puSetActiveWidget(this, x, y);
+}
+
+//------------------------------------------------------------------------------
+int CanvasWidget::checkKey(int key, int updown)
+{
+  return puObject::checkKey(key, updown);
+}
+
+//------------------------------------------------------------------------------
+void CanvasWidget::setSize(int w, int h)
+{
+  puObject::setSize(w, h);
+
+  _canvas->setIntValue("view[0]", w);
+  _canvas->setIntValue("view[1]", h);
+}
+
+//------------------------------------------------------------------------------
+void CanvasWidget::draw(int dx, int dy)
+{
+  if( !_tex_id )
+  {
+    _tex_id = _canvas_mgr->getCanvasTexId(_canvas->getIndex());
+
+    // Normally we should be able to get the texture after one frame. I don't
+    // know if there are circumstances where it can take longer, so we don't
+    // log a warning message until we have tried a few times.
+    if( !_tex_id )
+    {
+      if( ++_no_tex_cnt == 5 )
+        SG_LOG(SG_GENERAL, SG_WARN, "CanvasWidget: failed to get texture!");
+      return;
+    }
+    else
+    {
+      if( _no_tex_cnt >= 5 )
+        SG_LOG
+        (
+          SG_GENERAL,
+          SG_INFO,
+          "CanvasWidget: got texture after " << _no_tex_cnt << " tries."
+        );
+      _no_tex_cnt = 0;
+    }
+  }
+
+  glEnable(GL_TEXTURE_2D);
+  glBindTexture(GL_TEXTURE_2D, _tex_id);
+  glBegin( GL_QUADS );
+    glColor3f(1,1,1);
+    glTexCoord2f(0,0); glVertex2f(dx + abox.min[0], dy + abox.min[1]);
+    glTexCoord2f(1,0); glVertex2f(dx + abox.max[0], dy + abox.min[1]);
+    glTexCoord2f(1,1); glVertex2f(dx + abox.max[0], dy + abox.max[1]);
+    glTexCoord2f(0,1); glVertex2f(dx + abox.min[0], dy + abox.max[1]);
+  glEnd();
+  glDisable(GL_TEXTURE_2D);
+}
diff --git a/src/GUI/CanvasWidget.hxx b/src/GUI/CanvasWidget.hxx
new file mode 100644 (file)
index 0000000..7f4552c
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * CanvasWidget.hxx
+ *
+ *  Created on: 03.07.2012
+ *      Author: tom
+ */
+
+#ifndef CANVASWIDGET_HXX_
+#define CANVASWIDGET_HXX_
+
+#include <Main/fg_props.hxx>
+#include <plib/pu.h>
+
+class CanvasMgr;
+
+class CanvasWidget:
+  public puObject
+{
+  public:
+    CanvasWidget( int x, int y,
+                  int width, int height,
+                  SGPropertyNode* props,
+                  const std::string& module );
+    virtual ~CanvasWidget();
+
+    virtual void doHit (int button, int updown, int x, int y);
+    virtual int  checkKey(int key   , int updown);
+
+    virtual void setSize ( int w, int h );
+    virtual void draw(int dx, int dy);
+
+  private:
+
+    CanvasMgr  *_canvas_mgr; // TODO maybe we should store this in some central
+                             // location or make it static...
+
+    GLuint              _tex_id;    //<! OpenGL texture id if canvas
+    size_t              _no_tex_cnt;//<! Count since how many frames we were not
+                                    //   able to get the texture (for debugging)
+    SGPropertyNode_ptr  _canvas;    //<! Canvas root property node
+    SGPropertyNode     *_mouse_x,
+                       *_mouse_y,
+                       *_mouse_down,
+                       *_mouse_drag;
+};
+
+#endif /* CANVASWIDGET_HXX_ */
index 61bba82b680095f8ecc4cb55f5ae529bfd0e9d38..9b2bc232a47087d536cede2d0fc0e58b3aeb36c8 100644 (file)
@@ -18,6 +18,7 @@
 #include "property_list.hxx"
 #include "layout.hxx"
 #include "WaypointList.hxx"
+#include "CanvasWidget.hxx"
 #include "MapWidget.hxx"
 #include "FGFontCache.hxx"
 #include "FGColor.hxx"
@@ -827,6 +828,13 @@ FGPUIDialog::makeObject (SGPropertyNode *props, int parentWidth, int parentHeigh
         MapWidget* mapWidget = new MapWidget(x, y, x + width, y + height);
         setupObject(mapWidget, props);
         return mapWidget;
+    } else if (type == "canvas") {
+        CanvasWidget* canvasWidget = new CanvasWidget( x, y,
+                                                       x + width, y + height,
+                                                       props,
+                                                       _module );
+        setupObject(canvasWidget, props);
+        return canvasWidget;
     } else if (type == "combo") {
         fgComboBox *obj = new fgComboBox(x, y, x + width, y + height, props,
                 props->getBoolValue("editable", false));
index 902d20e6abb18bceb1bef16282509474ba534ec9..7d5ebf4ee1ba73d6804a4a5215138af225b8f9d9 100644 (file)
@@ -132,9 +132,9 @@ public:
     /**
      * Get the OSG camera for drawing this gauge.
      */
-    osg::Camera* getCamera() { return camera.get(); }
+    osg::Camera* getCamera() const { return camera.get(); }
 
-    osg::Texture2D* getTexture() { return texture.get(); }
+    osg::Texture2D* getTexture() const { return texture.get(); }
     //void setTexture(osg::Texture2D* t) { texture = t; }
 
     // Real initialization function. Bad name.
index 85dbbd4d67551d2c35dcff4e6ecce8778a77973d..55d5581a55c89e55fc55dbfea50d66f82e38b96f 100644 (file)
@@ -1163,7 +1163,7 @@ bool fgInitSubsystems() {
     ////////////////////////////////////////////////////////////////////
     // Initialize the canvas 2d drawing subsystem.
     ////////////////////////////////////////////////////////////////////
-    globals->add_subsystem("Canvas2D", new CanvasMgr, SGSubsystemMgr::DISPLAY);
+    globals->add_subsystem("Canvas", new CanvasMgr, SGSubsystemMgr::DISPLAY);
 
     ////////////////////////////////////////////////////////////////////
     // Initialise the ATIS Manager
index 1c3ec31cb2265a5e8f437d3f828ba697f23abad1..b65264a8be78a87da896542044c9fa6c4f1c770d 100644 (file)
@@ -816,11 +816,12 @@ naRef FGNasalSys::parse(const char* filename, const char* buf, int len)
     return naBindFunction(_context, code, _globals);
 }
 
-bool FGNasalSys::handleCommand(const SGPropertyNode* arg)
+bool FGNasalSys::handleCommand( const char* moduleName,
+                                const char* fileName,
+                                const char* src,
+                                const SGPropertyNode* arg )
 {
-    const char* nasal = arg->getStringValue("script");
-    const char* moduleName = arg->getStringValue("module");
-    naRef code = parse(arg->getPath(true).c_str(), nasal, strlen(nasal));
+    naRef code = parse(fileName, src, strlen(src));
     if(naIsNil(code)) return false;
 
     // Commands can be run "in" a module.  Make sure that module
@@ -845,6 +846,17 @@ bool FGNasalSys::handleCommand(const SGPropertyNode* arg)
     return true;
 }
 
+bool FGNasalSys::handleCommand(const SGPropertyNode* arg)
+{
+  const char* src = arg->getStringValue("script");
+  const char* moduleName = arg->getStringValue("module");
+
+  return handleCommand( moduleName,
+                        arg ? arg->getPath(true).c_str() : moduleName,
+                        src,
+                        arg );
+}
+
 // settimer(func, dt, simtime) extension function.  The first argument
 // is a Nasal function to call, the second is a delta time (from now),
 // in seconds.  The third, if present, is a boolean value indicating
index 5ca64f109ff18b006b9da2ffdd9cb6f0a6bd3ed0..0dad5fd530f1d7d413d4be6187c50cb257235609 100644 (file)
@@ -102,6 +102,10 @@ public:
     naRef cmdArgGhost();
 
     // Callbacks for command and timer bindings
+    virtual bool handleCommand( const char* moduleName,
+                                const char* fileName,
+                                const char* src,
+                                const SGPropertyNode* arg = 0 );
     virtual bool handleCommand(const SGPropertyNode* arg);
 
     bool createModule(const char* moduleName, const char* fileName,