Canvas view camera element: Difference between revisions

m
→‎Roadmap: add original proof-of-concept patches for future reference (should probably use bugman's collapsible template?)
m (→‎Roadmap: add original proof-of-concept patches for future reference (should probably use bugman's collapsible template?))
Line 20: Line 20:
* Missile/payload views
* Missile/payload views
* Prototyping/testing HUDs or PFDs requiring synthetic terrain to work properly
* Prototyping/testing HUDs or PFDs requiring synthetic terrain to work properly
== Proof of Concept ==
{{Note|This is based on code originally provided by F-JJTH, and subsequently reworked by Icecode GL and Hooray back in 2016}}
SimGear:
<syntaxhighlight lang="diff">
diff --git a/simgear/canvas/CanvasSystemAdapter.hxx b/simgear/canvas/CanvasSystemAdapter.hxx
index 43b3f780..0fb62170 100644
--- a/simgear/canvas/CanvasSystemAdapter.hxx
+++ b/simgear/canvas/CanvasSystemAdapter.hxx
@@ -35,11 +35,13 @@ namespace canvas
      virtual ~SystemAdapter() {}
      virtual FontPtr getFont(const std::string& name) const = 0;
-      virtual void addCamera(osg::Camera* camera) const = 0;
+      virtual void addCamera(osg::Camera* camera, bool useSceneData = false) const = 0;
      virtual void removeCamera(osg::Camera* camera) const = 0;
      virtual osg::ref_ptr<osg::Image> getImage(const std::string& path) const = 0;
+      virtual osg::Node* getModel(const std::string& path) const = 0;
      virtual SGSubsystem* getSubsystem(const std::string& name) const = 0;
      virtual HTTP::Client* getHTTPClient() const = 0;
+      virtual osg::Matrix getViewMatrix(int view_number, double dt) const = 0;
  };
} // namespace canvas
diff --git a/simgear/canvas/canvas_fwd.hxx b/simgear/canvas/canvas_fwd.hxx
index 3b1b4646..97e9bd64 100644
--- a/simgear/canvas/canvas_fwd.hxx
+++ b/simgear/canvas/canvas_fwd.hxx
@@ -24,6 +24,7 @@
#include <osg/ref_ptr>
#include <osgText/Font>
+#include <osg/Node>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
diff --git a/simgear/canvas/elements/CMakeLists.txt b/simgear/canvas/elements/CMakeLists.txt
index 2b537c0c..4eb1e955 100644
--- a/simgear/canvas/elements/CMakeLists.txt
+++ b/simgear/canvas/elements/CMakeLists.txt
@@ -7,6 +7,7 @@ set(HEADERS
  CanvasMap.hxx
  CanvasPath.hxx
  CanvasText.hxx
+  CanvasView.hxx
)
set(DETAIL_HEADERS
@@ -20,6 +21,7 @@ set(SOURCES
  CanvasMap.cxx
  CanvasPath.cxx
  CanvasText.cxx
+  CanvasView.cxx
)
simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}")
@@ -28,4 +30,4 @@ simgear_component(canvas-elements/detail canvas/elements/detail "" "${DETAIL_HEA
add_boost_test(canvas_element
  SOURCES canvas_element_test.cpp
  LIBRARIES ${TEST_LIBS}
-)
\ No newline at end of file
+)
diff --git a/simgear/canvas/elements/CanvasGroup.cxx b/simgear/canvas/elements/CanvasGroup.cxx
index c753c2e2..6cec072f 100644
--- a/simgear/canvas/elements/CanvasGroup.cxx
+++ b/simgear/canvas/elements/CanvasGroup.cxx
@@ -23,6 +23,7 @@
#include "CanvasMap.hxx"
#include "CanvasPath.hxx"
#include "CanvasText.hxx"
+#include "CanvasView.hxx"
#include <simgear/canvas/CanvasEventVisitor.hxx>
#include <simgear/canvas/events/MouseEvent.hxx>
@@ -66,6 +67,7 @@ namespace canvas
    add<Map  >(_child_factories);
    add<Path >(_child_factories);
    add<Text >(_child_factories);
+    add<View >(_child_factories);
  }
  //----------------------------------------------------------------------------
diff --git a/simgear/canvas/elements/CanvasView.cxx b/simgear/canvas/elements/CanvasView.cxx
new file mode 100644
index 00000000..502e82d7
--- /dev/null
+++ b/simgear/canvas/elements/CanvasView.cxx
@@ -0,0 +1,91 @@
+#include <simgear/canvas/Canvas.hxx>
+#include <simgear/canvas/CanvasMgr.hxx>
+#include <simgear/canvas/CanvasSystemAdapter.hxx>
+
+#include <simgear/scene/util/OsgMath.hxx>
+
+#include "CanvasView.hxx"
+
+#include <iostream>
+#include <osg/io_utils>
+
+namespace simgear
+{
+namespace canvas
+{
+
+const std::string View::TYPE_NAME = "view";
+
+void View::staticInit()
+{
+    if ( isInit<View>() )
+        return;
+}
+
+View::View( const CanvasWeakPtr& canvas,
+              const SGPropertyNode_ptr& node,
+              const Style& parent_style,
+              ElementWeakPtr parent ) :
+    Element(canvas, node, parent_style, parent),
+    _width(512),
+    _height(512)
+{
+    staticInit();
+
+    _texture = new osg::Texture2D;
+    _texture->setDataVariance(osg::Object::DYNAMIC);
+    _texture->setTextureSize(_width, _height);
+    _texture->setInternalFormat(GL_RGBA);
+    _texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR);
+    _texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR);
+
+    _camera = new osg::Camera;
+    _camera->setDataVariance(osg::Object::DYNAMIC);
+    _camera->setViewport(0, 0, _width, _height);
+    _camera->setClearColor(osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
+    _camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+    _camera->setRenderOrder(osg::Camera::PRE_RENDER);
+    _camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::FRAME_BUFFER);
+    _camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
+    double aspect_ratio = (double)_width / _height;
+    _camera->setProjectionMatrixAsPerspective(85.0, aspect_ratio, 0.1, 120000.0);
+
+    _camera->attach(osg::Camera::COLOR_BUFFER, _texture.get());
+
+    if (Canvas::getSystemAdapter())
+        Canvas::getSystemAdapter()->addCamera(_camera.get(), true);
+
+    _quad = osg::createTexturedQuadGeometry(osg::Vec3(0.0,    0.0,    0.0),
+                                            osg::Vec3(_width, 0.0,    0.0),
+                                            osg::Vec3(0.0,    _height, 0.0),
+                                            // In Canvas (0,0) is the top left corner, while in OSG/OpenGL
+                                            // it's the bottom left corner.
+                                            0.0, 1.0, 1.0, 0.0);
+    _quad->getOrCreateStateSet()->setTextureAttributeAndModes(0, _texture.get(), osg::StateAttribute::ON);
+
+    setDrawable(_quad.get());
+}
+
+View::~View()
+{
+    if( _camera.valid() && Canvas::getSystemAdapter() )
+        Canvas::getSystemAdapter()->removeCamera(_camera.get());
+    _camera.release();
+    _texture.release();
+}
+
+void View::update(double dt)
+{
+    osg::Matrix view_matrix = Canvas::getSystemAdapter()->getViewMatrix(0, dt);
+    _camera->setViewMatrix(view_matrix);
+
+    Element::update(dt);
+}
+
+void View::resize(int width, int height)
+{
+
+}
+
+} // namespace canvas
+} // namespace simgear
diff --git a/simgear/canvas/elements/CanvasView.hxx b/simgear/canvas/elements/CanvasView.hxx
new file mode 100644
index 00000000..8cb3cc49
--- /dev/null
+++ b/simgear/canvas/elements/CanvasView.hxx
@@ -0,0 +1,39 @@
+#ifndef CANVAS_VIEW_HXX_
+#define CANVAS_VIEW_HXX_
+
+#include "CanvasElement.hxx"
+
+namespace simgear
+{
+namespace canvas
+{
+
+class View : public Element {
+public:
+    static const std::string TYPE_NAME;
+    static void staticInit();
+
+    View( const CanvasWeakPtr& canvas,
+          const SGPropertyNode_ptr& node,
+          const Style& parent_style = Style(),
+          ElementWeakPtr parent = 0 );
+    virtual ~View();
+
+    virtual void update(double dt);
+
+    virtual void resize(int width, int height);
+
+protected:
+
+    osg::ref_ptr<osg::Camera> _camera;
+    osg::ref_ptr<osg::Texture2D> _texture;
+
+    osg::ref_ptr<osg::Geometry> _quad;
+
+    int _width, _height;
+};
+
+} // namespace canvas
+} // namespace simgear
+
+#endif // CANVAS_VIEW_HXX_
</syntaxhighlight>
FlightGear
<syntaxhighlight lang="diff">    diff --git a/src/Canvas/FGCanvasSystemAdapter.cxx b/src/Canvas/FGCanvasSystemAdapter.cxx
    index 72b20747e..9e04dbd14 100644
    --- a/src/Canvas/FGCanvasSystemAdapter.cxx
    +++ b/src/Canvas/FGCanvasSystemAdapter.cxx
    @@ -23,9 +23,18 @@
    #include <Network/HTTPClient.hxx>
    #include <Viewer/renderer.hxx>
   
    +
    +#include <Viewer/view.hxx>
    +#include <Viewer/viewmgr.hxx>
    +#include <simgear/scene/util/OsgMath.hxx>
    +
    +
    +
    #include <osgDB/ReadFile>
    #include <stdexcept>
   
    +#include <simgear/scene/model/modellib.hxx>
    +
    namespace canvas
    {
      //----------------------------------------------------------------------------
    @@ -64,9 +73,9 @@ namespace canvas
      }
   
      //----------------------------------------------------------------------------
    -  void FGCanvasSystemAdapter::addCamera(osg::Camera* camera) const
    +  void FGCanvasSystemAdapter::addCamera(osg::Camera* camera, bool useSceneData) const
      {
    -    globals->get_renderer()->addCamera(camera, false);
    +    globals->get_renderer()->addCamera(camera, useSceneData);
      }
   
      //----------------------------------------------------------------------------
    @@ -100,6 +109,46 @@ namespace canvas
        return 0;
      }
   
    +    //----------------------------------------------------------------------------
    +    // From http://wiki.flightgear.org/Howto:Extending_Canvas_to_support_rendering_3D_models#Extending_FGCanvasSystemAdapter
    +    osg::Node* FGCanvasSystemAdapter::getModel(const std::string& path) const
    +    {
    +        const char *model_path = "Models/Geometry/glider.ac";
    +        SGPath p(SGPath::fromUtf8(path));
    +
    +        if( p.isAbsolute() )
    +        {
    +            SGPath valid_path = fgValidatePath(p, false);
    +            if( !valid_path.isNull() )
    +            try {
    +                std::string fullPath = simgear::SGModelLib::findDataFile(valid_path.local8BitStr());
    +                osg::Node * object = simgear::SGModelLib::loadDeferredModel(fullPath, globals->get_props());
    +                return object;
    +            } catch (const sg_throwable& t) {
    +                SG_LOG(SG_IO, SG_ALERT, "Error loading " << model_path << ":\n  " << t.getFormattedMessage() << t.getOrigin());
    +                return 0;
    +            } // error loading from absolute path
    +            SG_LOG(SG_IO, SG_ALERT, "canvas::Model: reading '" << path << "' denied");
    +        } // absolute path handling
    +        else
    +        {
    +            SGPath tpath = globals->resolve_resource_path(path);
    +            if( !tpath.isNull() )
    +            try {
    +                std::string fullPath = simgear::SGModelLib::findDataFile(path.c_str());
    +                osg::Node * object = simgear::SGModelLib::loadDeferredModel(fullPath, globals->get_props());
    +                return object;
    +            } catch (const sg_throwable& t) {
    +                SG_LOG(SG_IO, SG_ALERT, "Error loading " << model_path << ":\n  " << t.getFormattedMessage() << t.getOrigin());
    +                return 0;
    +            } // error loading from relative path
    +
    +            SG_LOG(SG_IO, SG_ALERT, "canvas::Model: No such model: '" << path << "'");
    +        } // relative path handling
    +
    +        return 0;
    +    }
    +
      //----------------------------------------------------------------------------
      SGSubsystem*
      FGCanvasSystemAdapter::getSubsystem(const std::string& name) const
    @@ -121,4 +170,16 @@ namespace canvas
        return 0;
      }
   
    +  osg::Matrix FGCanvasSystemAdapter::getViewMatrix(int view_number, double dt) const
    +  {
    +        flightgear::View *view = globals->get_viewmgr()->get_view(view_number);
    +        view->update(dt);
    +
    +        osg::Vec3f position( toOsg(view->getViewPosition()) );
    +        osg::Quat orientation( toOsg(view->getViewOrientation()) );
    +        osg::Matrix viewMatrix( osg::Matrix::translate(-position) * osg::Matrix::rotate(orientation.inverse()) );
    +
    +        return viewMatrix;
    +  }
    +
    }
    diff --git a/src/Canvas/FGCanvasSystemAdapter.hxx b/src/Canvas/FGCanvasSystemAdapter.hxx
    index 4c1fd6210..24ececb41 100644
    --- a/src/Canvas/FGCanvasSystemAdapter.hxx
    +++ b/src/Canvas/FGCanvasSystemAdapter.hxx
    @@ -28,11 +28,13 @@ namespace canvas
      {
        public:
          virtual simgear::canvas::FontPtr getFont(const std::string& name) const;
    -      virtual void addCamera(osg::Camera* camera) const;
    +      virtual void addCamera(osg::Camera* camera, bool useSceneData = false) const;
          virtual void removeCamera(osg::Camera* camera) const;
          virtual osg::ref_ptr<osg::Image> getImage(const std::string& path) const;
    +      virtual osg::Node* getModel(const std::string& path) const;
          virtual SGSubsystem* getSubsystem(const std::string& name) const;
          virtual simgear::HTTP::Client* getHTTPClient() const;
    +      virtual osg::Matrix getViewMatrix(int view_number, double dt) const;
      };
    }
   
    diff --git a/src/Viewer/renderer.cxx b/src/Viewer/renderer.cxx
    index d9e8f351f..b9b3fc6a0 100644
    --- a/src/Viewer/renderer.cxx
    +++ b/src/Viewer/renderer.cxx
    @@ -1845,6 +1845,8 @@ FGRenderer::setEventHandler(FGEventHandler* eventHandler_)
    void
    FGRenderer::addCamera(osg::Camera* camera, bool useSceneData)
    {
    +    if (useSceneData)
    +        camera->addChild(globals->get_scenery()->get_scene_graph());
        _viewerSceneRoot->addChild(camera);
    }
</syntaxhighlight>
<syntaxhighlight lang="diff">diff --git a/Nasal/canvas/api.nas b/Nasal/canvas/api.nas
index 3f7f5a17..433a41f9 100644
--- a/Nasal/canvas/api.nas
+++ b/Nasal/canvas/api.nas
@@ -1132,10 +1132,10 @@ var Image = {
  }
};
-var Model = {
+var View = {
  new: func(ghost)
  {
-    return {parents: [Model, Element.new(ghost)]};
+    return {parents: [View, Element.new(ghost)]};
  },
};
@@ -1146,7 +1146,7 @@ Group._element_factories = {
  "text": Text.new,
  "path": Path.new,
  "image": Image.new,
-  "model": Model.new
+  "view": View.new
};
# Canvas
</syntaxhighlight>


== Roadmap ==
== Roadmap ==