Canvas sandbox

From FlightGear wiki
(Redirected from Canvas Sandbox)
Jump to navigation Jump to search
https://commons.wikimedia.org/wiki/File:Brainstorming.png


This article is intended to be a sandbox for Canvas related ideas/enhancements, including code snippets, patches and boilerplate code for integration layer changes to implement new elements. Readers are generally assumed to be familiar with Building FlightGear, Git for laymen and Canvas Development, as well as C++ and OpenSceneGraph basics.

Each element/idea shown below should have a "references" section, including an introductory paragraph explaining the motivation for the corresponding feature, linking back to the original discussions on the devel list/forum or issue tracker.

On the other hand, some elements/patches below are merely intended to serve as examples/reference for people interested in implementing similar functionality at some point. So just because an element is shown here, does not necessarily mean that it is required in FlightGear.

Also, each paragraph contains patched using the diff format, so that people should be familiar with applying patches to their SG/FG source trees respectively (using git apply).

Preferably, each paragraph should have a list of pointers (e.g. tutorials) to cover introductory topics (e.g. osg::Camera setup, rendering to a texture etc).

The topics covered below should be listed with ascending complexity, to ensure that the learning curve is not too step..

Most of these features/ideas are not yet ready for "prime time", but they have been repeatedly discussed by contributors, so that it makes sense to archive useful ideas/patches and let them grow over time.

People are invited to test these ideas/patches and get involved in developing these further, even if just by helping update the wiki accordingly.

CanvasAnimation


Note  For the time being this is probably the most important addition from a performance standpoint, because it will help dramatically reduce Nasal related overhead in the main loop, while also using native OSG data structures for handling animations.

Supporting native OSG animations will also be beneficial to Unifying the 2D rendering backend via canvas, i.e. for porting the existing HUD/2D panels legacy code to OSG.

Animations are currently not handled by any Canvas/OSG code directly - instead, Nasal callbacks (using timers and listeners) are used to emulate animations.

However, this is relatively expensive - on the one hand because it is using Nasal to update scene graph related data structures, and on the other hand because the resulting scenegraph itself is relatively low-level, i.e. OSG does not even know that the scenegraph is used for implementing an animation.

In other words, most Nasal code currently used to update Canvas elements/textures is basically about "animating" child nodes using Nasal callbacks, which is reflecting badly upon Canvas based features, because of the massive performance overhead due to all the required Nasal code.

On the other hand, OSG does provide built-in APIs to provide support for various kinds of animations, so it would make sense to expose this at the Canvas::Element level, so that people using Canvas to implement animations can stop using Nasal, and instead use native OSG code.

The de-facto reference are the animation related child classes inheriting from osg::Group: http://trac.openscenegraph.org/documentation/OpenSceneGraphReferenceDocs/a00357.html

Specifically, these are:

Using just these three APIs, we can come up with a single Canvas::Animation class that supports all important animations, without going through Nasal space unnecessarily.

In addition, it would be possible to map animation callbacks to property rules to use C++ instead of Nasal for more sophisticated purposes.


You will want to add a new Canvas::Element subclass whenever you want to add support for features which cannot be currently expressed easily (or efficiently) using existing means/canvas drawing primitives (i.e. via existing elements and scripting space frameworks).

For example, this may involve projects requiring camera support, i.e. rendering scenery views to a texture, rendering 3D models to a texture or doing a complete moving map with terrain elevations/height maps (even though the latter could be implemented by sub-classing Canvas::Image to some degree).

Another good example for implementing new elements is rendering file formats like PDF, 3d models or ESRI shape files.

To create a new element, you need to create a new child class which inherits from Canvas::Element base class (or any of its child-classes, e.g. Canvas::Image) and implement the interface of the parent class by providing/overriding the correspond virtual methods.

To add a new element, these are the main steps:

  • Set up a working build environment (including simgear): Building FlightGear
  • update/pull simgear,flightgear and fgdata
  • check out a new set of topic branches for each repo: git checkout -b topic/canvas-Animation
  • Navigate to $SG_SRC/canvas/elements
  • Create a new set of files Animation.cxx/.hxx (as per Adding a new Canvas element)
  • add them to $SG_SRC/canvas/elements/CMakeLists.txt (as per Developing using CMake)
  • edit $SG_SRC/canvas/elements/CanvasGroup.cxx to register your new element (header and staticInit)
  • begin replacing the stubs with your own C++ code
  • map the corresponding OSG/library APIs to properties/events understood by the Canvas element (see the valueChanged() and update() methods)
  • alternatively, consider using dedicated Nasal/CppBind bindings

Below, you can find patches illustrating how to approach each of these steps using boilerplate code, which you will need to customize/replace accordingly:







CanvasShape

Screen shot showing a custom canvas element wrapping osg::Shape

As a simple proof-of-concept, we can begin by exposing osg::Shape as a dedicated Canvas element:

osg::Shape* sphere = new osg::Sphere(osg::Vec3(10.0f, 10.0f, 10.0f), 5.0f);
osg::ShapeDrawable* sphereDrawable = new osg::ShapeDrawable(sphere);
osg::Geode* sphereGeode = new osg::Geode();
sphereGeode->addDrawable(sphereDrawable);

Compared to SVG/OpenVG (ShivaVG) based drawing, the main benefit is that we can create and display 3D objects, using correct orientation/projection in a 3D scene, including even custom texturing by using images from disk, or other Canvas textures.

In addition, OSG provides support for a shapeDrawable based heightfield class that can be used for generating terrain meshes procedurally.

The code shown above, can simple be added to the constructor of the canvas element, but we will want to render it to a texture using a PositionAttitudeTransformMatric and map those to properties in the sub-tree of the canvas element.


You will want to add a new Canvas::Element subclass whenever you want to add support for features which cannot be currently expressed easily (or efficiently) using existing means/canvas drawing primitives (i.e. via existing elements and scripting space frameworks).

For example, this may involve projects requiring camera support, i.e. rendering scenery views to a texture, rendering 3D models to a texture or doing a complete moving map with terrain elevations/height maps (even though the latter could be implemented by sub-classing Canvas::Image to some degree).

Another good example for implementing new elements is rendering file formats like PDF, 3d models or ESRI shape files.

To create a new element, you need to create a new child class which inherits from Canvas::Element base class (or any of its child-classes, e.g. Canvas::Image) and implement the interface of the parent class by providing/overriding the correspond virtual methods.

To add a new element, these are the main steps:

  • Set up a working build environment (including simgear): Building FlightGear
  • update/pull simgear,flightgear and fgdata
  • check out a new set of topic branches for each repo: git checkout -b topic/canvas-Shape
  • Navigate to $SG_SRC/canvas/elements
  • Create a new set of files Shape.cxx/.hxx (as per Adding a new Canvas element)
  • add them to $SG_SRC/canvas/elements/CMakeLists.txt (as per Developing using CMake)
  • edit $SG_SRC/canvas/elements/CanvasGroup.cxx to register your new element (header and staticInit)
  • begin replacing the stubs with your own C++ code
  • map the corresponding OSG/library APIs to properties/events understood by the Canvas element (see the valueChanged() and update() methods)
  • alternatively, consider using dedicated Nasal/CppBind bindings

Below, you can find patches illustrating how to approach each of these steps using boilerplate code, which you will need to customize/replace accordingly:







CanvasShapefile

See also [2] (GDAL/OGR support in SimGear)

Cquote1.png When we have vector road data at runtime, we can do the following:
  • render it in moving-map displays - either real ones (Garmin G1000 / G430) or the map dialog
  • use it to drive building outline creation as Thomas was suggesting
  • animate traffic on the roads, as point lights at night or even meshes in daytime (the important one...)
  • generate tile overlay textures dynamically (and based on view distance) to show the roads on the terrain surface. (And the detail of this texture can include road markings / borders based on distance from the viewer / view angle / etc)

— James Turner (2014-11-21). Re: [Flightgear-devel] Future city terrain strategy.
(powered by Instant-Cquotes)
Cquote2.png



You will want to add a new Canvas::Element subclass whenever you want to add support for features which cannot be currently expressed easily (or efficiently) using existing means/canvas drawing primitives (i.e. via existing elements and scripting space frameworks).

For example, this may involve projects requiring camera support, i.e. rendering scenery views to a texture, rendering 3D models to a texture or doing a complete moving map with terrain elevations/height maps (even though the latter could be implemented by sub-classing Canvas::Image to some degree).

Another good example for implementing new elements is rendering file formats like PDF, 3d models or ESRI shape files.

To create a new element, you need to create a new child class which inherits from Canvas::Element base class (or any of its child-classes, e.g. Canvas::Image) and implement the interface of the parent class by providing/overriding the correspond virtual methods.

To add a new element, these are the main steps:

  • Set up a working build environment (including simgear): Building FlightGear
  • update/pull simgear,flightgear and fgdata
  • check out a new set of topic branches for each repo: git checkout -b topic/canvas-Shapefile
  • Navigate to $SG_SRC/canvas/elements
  • Create a new set of files Shapefile.cxx/.hxx (as per Adding a new Canvas element)
  • add them to $SG_SRC/canvas/elements/CMakeLists.txt (as per Developing using CMake)
  • edit $SG_SRC/canvas/elements/CanvasGroup.cxx to register your new element (header and staticInit)
  • begin replacing the stubs with your own C++ code
  • map the corresponding OSG/library APIs to properties/events understood by the Canvas element (see the valueChanged() and update() methods)
  • alternatively, consider using dedicated Nasal/CppBind bindings

Below, you can find patches illustrating how to approach each of these steps using boilerplate code, which you will need to customize/replace accordingly:







CanvasHeightField

Cquote1.png can you give me an idea on how to use od_gauge to continuously render a camera view to texture? I don't really know much about it but then every says that Project Rembrandt involves continuous rendering to texture.And, is there a way to get terrain as a view? I mean, sorta like changing the color based on terrain. Oh, and I'd also need to place my own texture on the terrain, instead of the materials textures..So, that's not just using od_gauge, for a terrain view, I'd need to actually re-render the whole terrain with some extra stuff...
— omega95 (Mar 24th, 2012). Re: Jabiru J-170 (DEVELOPMENT).
(powered by Instant-Cquotes)
Cquote2.png
Cquote1.png Such a 3D view would be best accomplished by using a scenery child cam, and applying custom effects/shaders to it - but for that, we would need to expose effects/shaders to Canvas::Element.

Alternatively, it would also be possible to come up with a custom "heightfield" element using osg.:HeightField: http://trac.openscenegraph.org/documentation/OpenSceneGraphReferenceDocs/a00364.html

http://osghelp.com/?p=163 It would be relatively straightforward to turn this into a custom Canvas::Element and even hook it up to the built-in terrain presampler, using a configurable resolution.

Anybody familiar with building from source, using git and willing to work through a handful of OSG tutorials should be able to come up with a working "heightfield" element to support such synthetic terrain views.
— Hooray (Nov 12th, 2015). Synthetic terrain.
(powered by Instant-Cquotes)
Cquote2.png
Cquote1.png Instead of using the terrain sampler, it may be faster to create the mesh directly from the scenegraph in c++ space. we already do this in the LOD callback to place the random trees and buildings. We then have a triangle mesh.
— psadro_gm (Nov 12th, 2015). Re: Synthetic terrain.
(powered by Instant-Cquotes)
Cquote2.png



You will want to add a new Canvas::Element subclass whenever you want to add support for features which cannot be currently expressed easily (or efficiently) using existing means/canvas drawing primitives (i.e. via existing elements and scripting space frameworks).

For example, this may involve projects requiring camera support, i.e. rendering scenery views to a texture, rendering 3D models to a texture or doing a complete moving map with terrain elevations/height maps (even though the latter could be implemented by sub-classing Canvas::Image to some degree).

Another good example for implementing new elements is rendering file formats like PDF, 3d models or ESRI shape files.

To create a new element, you need to create a new child class which inherits from Canvas::Element base class (or any of its child-classes, e.g. Canvas::Image) and implement the interface of the parent class by providing/overriding the correspond virtual methods.

To add a new element, these are the main steps:

  • Set up a working build environment (including simgear): Building FlightGear
  • update/pull simgear,flightgear and fgdata
  • check out a new set of topic branches for each repo: git checkout -b topic/canvas-Heightfield
  • Navigate to $SG_SRC/canvas/elements
  • Create a new set of files Heightfield.cxx/.hxx (as per Adding a new Canvas element)
  • add them to $SG_SRC/canvas/elements/CMakeLists.txt (as per Developing using CMake)
  • edit $SG_SRC/canvas/elements/CanvasGroup.cxx to register your new element (header and staticInit)
  • begin replacing the stubs with your own C++ code
  • map the corresponding OSG/library APIs to properties/events understood by the Canvas element (see the valueChanged() and update() methods)
  • alternatively, consider using dedicated Nasal/CppBind bindings

Below, you can find patches illustrating how to approach each of these steps using boilerplate code, which you will need to customize/replace accordingly:







CanvasMovingMap

Cquote1.png I'd really like to use the Atlas generated maps as a layer in the browser map. Is anybody out there looking for an adventure and is able to modify the Atlas map generator to generate maps on-the-fly? Input would be three parameters: z/x/y where z is the zoom level and x/y are numeric parameters describing latitude and longitude (based on image size). Output should be a generated tile of 256x256 and format png in a memory buffer.
— Torsten (Mon Mar 17). Re: Atlas still in use ?.
(powered by Instant-Cquotes)
Cquote2.png

a large benefit for using the raw DEM will be for moving maps - the elevation is pretty much displayable as-is.[1]


  1. psadro_gm  (Sep 10th, 2016).  Re: Next-generation scenery generating? .


You will want to add a new Canvas::Element subclass whenever you want to add support for features which cannot be currently expressed easily (or efficiently) using existing means/canvas drawing primitives (i.e. via existing elements and scripting space frameworks).

For example, this may involve projects requiring camera support, i.e. rendering scenery views to a texture, rendering 3D models to a texture or doing a complete moving map with terrain elevations/height maps (even though the latter could be implemented by sub-classing Canvas::Image to some degree).

Another good example for implementing new elements is rendering file formats like PDF, 3d models or ESRI shape files.

To create a new element, you need to create a new child class which inherits from Canvas::Element base class (or any of its child-classes, e.g. Canvas::Image) and implement the interface of the parent class by providing/overriding the correspond virtual methods.

To add a new element, these are the main steps:

  • Set up a working build environment (including simgear): Building FlightGear
  • update/pull simgear,flightgear and fgdata
  • check out a new set of topic branches for each repo: git checkout -b topic/canvas-MovingMap
  • Navigate to $SG_SRC/canvas/elements
  • Create a new set of files MovingMap.cxx/.hxx (as per Adding a new Canvas element)
  • add them to $SG_SRC/canvas/elements/CMakeLists.txt (as per Developing using CMake)
  • edit $SG_SRC/canvas/elements/CanvasGroup.cxx to register your new element (header and staticInit)
  • begin replacing the stubs with your own C++ code
  • map the corresponding OSG/library APIs to properties/events understood by the Canvas element (see the valueChanged() and update() methods)
  • alternatively, consider using dedicated Nasal/CppBind bindings

Below, you can find patches illustrating how to approach each of these steps using boilerplate code, which you will need to customize/replace accordingly:







CanvasGeoTIFF

You will want to add a new Canvas::Element subclass whenever you want to add support for features which cannot be currently expressed easily (or efficiently) using existing means/canvas drawing primitives (i.e. via existing elements and scripting space frameworks).

For example, this may involve projects requiring camera support, i.e. rendering scenery views to a texture, rendering 3D models to a texture or doing a complete moving map with terrain elevations/height maps (even though the latter could be implemented by sub-classing Canvas::Image to some degree).

Another good example for implementing new elements is rendering file formats like PDF, 3d models or ESRI shape files.

To create a new element, you need to create a new child class which inherits from Canvas::Element base class (or any of its child-classes, e.g. Canvas::Image) and implement the interface of the parent class by providing/overriding the correspond virtual methods.

To add a new element, these are the main steps:

  • Set up a working build environment (including simgear): Building FlightGear
  • update/pull simgear,flightgear and fgdata
  • check out a new set of topic branches for each repo: git checkout -b topic/canvas-GeoTIFF
  • Navigate to $SG_SRC/canvas/elements
  • Create a new set of files GeoTIFF.cxx/.hxx (as per Adding a new Canvas element)
  • add them to $SG_SRC/canvas/elements/CMakeLists.txt (as per Developing using CMake)
  • edit $SG_SRC/canvas/elements/CanvasGroup.cxx to register your new element (header and staticInit)
  • begin replacing the stubs with your own C++ code
  • map the corresponding OSG/library APIs to properties/events understood by the Canvas element (see the valueChanged() and update() methods)
  • alternatively, consider using dedicated Nasal/CppBind bindings

Below, you can find patches illustrating how to approach each of these steps using boilerplate code, which you will need to customize/replace accordingly:








CanvasPDF

Checking the examples in the osg source tree, the demo rendering a PDF to a osg::Node is fairly compelling and extremely compact, requiring only ~15 lines of code github/openscenegraph/osg/examples/osgpdf/osgpdf.cpp


#include <osgWidget/PdfReader>
// ...

osg::ref_ptr<osgWidget::PdfReader> pdfReader = new osgWidget::PdfReader;
if (pdfReader->open(path)) {
 root->addChild(pdfReader.get());
}
Screenshot showing the unmodified osgpdf example which loads a pdf file, renders it to a surface and adds it to the osgviewer scene


So all that is needed is including the osgWidget/PdfReader header and editing the top-level CMakeListst.txt file in sgsrc/fgsrc to ensure that osgWidget is added as a required library in the find_package() call:

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5e3b905..c32f830 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -203,7 +203,7 @@ else()
         message(STATUS "Sound support: ENABLED")
     endif(ENABLE_SOUND)
 
-    find_package(OpenSceneGraph 3.2.0 REQUIRED osgText osgSim osgDB osgParticle osgGA osgViewer osgUtil)
+    find_package(OpenSceneGraph 3.2.0 REQUIRED osgText osgSim osgDB osgParticle osgGA osgViewer osgUtil osgWidget)
 endif(SIMGEAR_HEADLESS)
 
 find_package(ZLIB REQUIRED)

Next, we need to edit the constructor accordingly, and make sure that the osg::Node is added to the _transform member of the CanvasElement we are creating.

That will already give us a new element that renders a PDF file to the Cavas.

osgpdf demo wrapped in a CanvasElement, showing the FlightGear manual


To see how the file name can be changed/updated using properties, it makes sense to open CanvasImage.cxx and check how it is working there, so that we can copy/paste and adapt the code accordingly.

To turn this into a proper element, we can next open the header itself and check what methods are available, so that these can be exposed via Canvas properties


You will want to add a new Canvas::Element subclass whenever you want to add support for features which cannot be currently expressed easily (or efficiently) using existing means/canvas drawing primitives (i.e. via existing elements and scripting space frameworks).

For example, this may involve projects requiring camera support, i.e. rendering scenery views to a texture, rendering 3D models to a texture or doing a complete moving map with terrain elevations/height maps (even though the latter could be implemented by sub-classing Canvas::Image to some degree).

Another good example for implementing new elements is rendering file formats like PDF, 3d models or ESRI shape files.

To create a new element, you need to create a new child class which inherits from Canvas::Element base class (or any of its child-classes, e.g. Canvas::Image) and implement the interface of the parent class by providing/overriding the correspond virtual methods.

To add a new element, these are the main steps:

  • Set up a working build environment (including simgear): Building FlightGear
  • update/pull simgear,flightgear and fgdata
  • check out a new set of topic branches for each repo: git checkout -b topic/canvas-PDF
  • Navigate to $SG_SRC/canvas/elements
  • Create a new set of files PDF.cxx/.hxx (as per Adding a new Canvas element)
  • add them to $SG_SRC/canvas/elements/CMakeLists.txt (as per Developing using CMake)
  • edit $SG_SRC/canvas/elements/CanvasGroup.cxx to register your new element (header and staticInit)
  • begin replacing the stubs with your own C++ code
  • map the corresponding OSG/library APIs to properties/events understood by the Canvas element (see the valueChanged() and update() methods)
  • alternatively, consider using dedicated Nasal/CppBind bindings

Below, you can find patches illustrating how to approach each of these steps using boilerplate code, which you will need to customize/replace accordingly:







Next, we need to look at the OSG examples to see how a PDF file can be opened and rendered to a texture.



CanvasModel

1rightarrow.png See Howto:Extending Canvas to support rendering 3D models for the main article about this subject.

Screen shot showing a custom canvas element for loading/displaying arbitrary 3D models
Screen shot showing a custom canvas element for loading/displaying arbitrary 3D models (rotated perspective)


You will want to add a new Canvas::Element subclass whenever you want to add support for features which cannot be currently expressed easily (or efficiently) using existing means/canvas drawing primitives (i.e. via existing elements and scripting space frameworks).

For example, this may involve projects requiring camera support, i.e. rendering scenery views to a texture, rendering 3D models to a texture or doing a complete moving map with terrain elevations/height maps (even though the latter could be implemented by sub-classing Canvas::Image to some degree).

Another good example for implementing new elements is rendering file formats like PDF, 3d models or ESRI shape files.

To create a new element, you need to create a new child class which inherits from Canvas::Element base class (or any of its child-classes, e.g. Canvas::Image) and implement the interface of the parent class by providing/overriding the correspond virtual methods.

To add a new element, these are the main steps:

  • Set up a working build environment (including simgear): Building FlightGear
  • update/pull simgear,flightgear and fgdata
  • check out a new set of topic branches for each repo: git checkout -b topic/canvas-Model
  • Navigate to $SG_SRC/canvas/elements
  • Create a new set of files Model.cxx/.hxx (as per Adding a new Canvas element)
  • add them to $SG_SRC/canvas/elements/CMakeLists.txt (as per Developing using CMake)
  • edit $SG_SRC/canvas/elements/CanvasGroup.cxx to register your new element (header and staticInit)
  • begin replacing the stubs with your own C++ code
  • map the corresponding OSG/library APIs to properties/events understood by the Canvas element (see the valueChanged() and update() methods)
  • alternatively, consider using dedicated Nasal/CppBind bindings

Below, you can find patches illustrating how to approach each of these steps using boilerplate code, which you will need to customize/replace accordingly:







Next, we need to set up a separate camera to render a sub-scenegraph to a texture - the corresponding OSG code to accomplish this can be taken from existing OSG examples[3][4]/tutorials[5][6][7][8], or we can directly use the ODGauge code in Simgear:



CanvasOsgEarthMap

This article or section contains out-of-date information

Please help improve this article by updating it. There may be additional information on the talk page.

https://gitorious.org/fg/hoorays-simgear?p=fg:hoorays-simgear.git;a=commitdiff;h=7382ece6fd0861cf379006d283fe253e210bfc8f



CanvasNasal

1rightarrow.png See Canvas_Development#Canvas_Development#The_Future_of_Canvas_in_FlightGear for the main article about this subject.

This is not directly a new element, it's just an abstract base class that can be used to register a factory of Nasal-space elements (think elements of a MFD like screens, pages etc). While that may be considered problematic from a performance standpoint (implementing new elements in Nasal), the idea is to expose the CanvasElement interface to Nasal space, so that developers can more easily prototype new elements in scripting space, and register those with the main Canvas::Group manager, without having to be proficient in C++.

Primarily, this is about enforcing a well-defined interface using properties.

Hopefully, this will allow fgdata developers to come up with features that are reusable and agnostic to the concrete use-case, as well as support independent instances and styling.

Which are basically the main challenges Canvas adoption is seeing/causing in fgdata in the last 3 years, i.e. tons of useful features that are highly specific to a single aircraft/use case, without supporting other use-cases, and without being sufficiently flexible and customizable.

Preferably, fgdata developers would use inheritance, composition and aggregation to design their Canvas-based features. However, that point is hard to bring across, and the only Canvas-related features that satisfy these requirements, are native Canvas elements using the Canvas::Element interface.

The key thing here is that we want to ensure that the Canvas system, and OSG itself, know what an element is all about, without all this knowledge having to exist solely in scripting space.

This is also the prerequisite for supporting multi-instance or multiplayer setups where Canvas-specific state may need to be propagated to multiple fgfs instances for replication:

Cquote1.png I think of some kind of separation that will also be good if we would do HLA between a viewer and an application computing physical models or controlling an additional view hooking into a federate ...
— Mathias Fröhlich (Jul 1st, 2008). Re: [Flightgear-devel] RFC: changes to views and cameras.
(powered by Instant-Cquotes)
Cquote2.png
Cquote1.png I'm guessing it would be somewhat similar to ARINC661, and the actual arrangement of these widgets could be marked up in an XML file. The framework could render to a texture (for display in a 3D virtual cockpit), a memory buffer (for direct blitting onto the screen) or to a separate device context altogether (for an external display). Network support on this would be a really interesting feature -- allowing outboard 'dumb' cockpit displays to be run off a diskless thin client.
— R. van Steenbergen (Aug 3rd, 2008). Re: [Flightgear-devel] Cockpit displays (rendering, modelling).
(powered by Instant-Cquotes)
Cquote2.png
Cquote1.png The layout might be similar to a VM, with high-level instructions to represent points, lines, rectangles, text, etc. The advantage of this is that it will set a predefined interface for displaying geometry but not define the low-level implementation.
— R. van Steenbergen (Aug 4th, 2008). Re: [Flightgear-devel] Cockpit displays (rendering, modelling).
(powered by Instant-Cquotes)
Cquote2.png
Cquote1.png If we're rendering each display as an OSG sub-camera, extracting that logic and wrapping it in a stand-alone OSG viewer should be simplicity itself - and so long as it's driven by properties, those can be sent over a socket. That's an approach which seems a lot more bearable to me than sending per-frame pixel surfaces over shared memory or sockets / pipes.
Cquote2.png

Which is to say, in an interlinked FlightGear setup, we want to avoid having to replicate low-level scenegraph information, but deal with a high-level representation, e.g. sending information about update a "navaid layer" rather than a "VOR symbol" or even a much lower-level "SVG/OpenVG group".

Dealing with Canvas features at the element level is the only sane way of doing so, but is causing quite some traffic for low-level primitives, so that it makes sense to introduce higher level elements for specific use-cases.

While it may seem ironic at first that moving the implementation of new elements to Nasal, all the internal handling logic would directly use the proper interface of Canvas::element

In turn, this would mean, that we can prototype new elements, e.g. to add a dedicated "navaid-layer" element, which can make safe assumptions about its contents and purpose, including not just visible state, but also internal state (center of the map, range, symbols to be displayed etc).

Once new elements have been refined and once they are proven, they could be partially/completely re-implemented in native C++ code, without any of the front-end code having to be changed.


You will want to add a new Canvas::Element subclass whenever you want to add support for features which cannot be currently expressed easily (or efficiently) using existing means/canvas drawing primitives (i.e. via existing elements and scripting space frameworks).

For example, this may involve projects requiring camera support, i.e. rendering scenery views to a texture, rendering 3D models to a texture or doing a complete moving map with terrain elevations/height maps (even though the latter could be implemented by sub-classing Canvas::Image to some degree).

Another good example for implementing new elements is rendering file formats like PDF, 3d models or ESRI shape files.

To create a new element, you need to create a new child class which inherits from Canvas::Element base class (or any of its child-classes, e.g. Canvas::Image) and implement the interface of the parent class by providing/overriding the correspond virtual methods.

To add a new element, these are the main steps:

  • Set up a working build environment (including simgear): Building FlightGear
  • update/pull simgear,flightgear and fgdata
  • check out a new set of topic branches for each repo: git checkout -b topic/canvas-Nasal
  • Navigate to $SG_SRC/canvas/elements
  • Create a new set of files Nasal.cxx/.hxx (as per Adding a new Canvas element)
  • add them to $SG_SRC/canvas/elements/CMakeLists.txt (as per Developing using CMake)
  • edit $SG_SRC/canvas/elements/CanvasGroup.cxx to register your new element (header and staticInit)
  • begin replacing the stubs with your own C++ code
  • map the corresponding OSG/library APIs to properties/events understood by the Canvas element (see the valueChanged() and update() methods)
  • alternatively, consider using dedicated Nasal/CppBind bindings

Below, you can find patches illustrating how to approach each of these steps using boilerplate code, which you will need to customize/replace accordingly:







CanvasCamera

Note  There is a related patch available at https://forum.flightgear.org/viewtopic.php?f=71&t=23929#p317448


Cquote1.png I've been working on improving the camera configuration system in FG. It is almost done, but needs some cleanup before I can put up a merge request. Here is the list of new features:
  • Support for setting the rendering order of cameras
  • Can set the clear mask (color, depth and stencil buffer separately)
  • Can set the texture format in render-to-texture (which already was there, but had almost no use before this update), rgb, rgba, depth or depth-stencil at the moment.
  • Can set the texture type (normalied 2d or rectangle)
  • Support for multiple render targets, via just specifying multiple texture targets. This needs modification to shaders though, but works.
  • Can set whether camera uses scene data or a custom model (e.g. screen aligned quad)
  • Can bind render target textures to texture units for rendering to screen. (In the future should allow using these in models by specifying the texture name...)
    — Zan (Oct 14th, 2011). Improved camera configuration options.
    (powered by Instant-Cquotes)
Cquote2.png


You will want to add a new Canvas::Element subclass whenever you want to add support for features which cannot be currently expressed easily (or efficiently) using existing means/canvas drawing primitives (i.e. via existing elements and scripting space frameworks).

For example, this may involve projects requiring camera support, i.e. rendering scenery views to a texture, rendering 3D models to a texture or doing a complete moving map with terrain elevations/height maps (even though the latter could be implemented by sub-classing Canvas::Image to some degree).

Another good example for implementing new elements is rendering file formats like PDF, 3d models or ESRI shape files.

To create a new element, you need to create a new child class which inherits from Canvas::Element base class (or any of its child-classes, e.g. Canvas::Image) and implement the interface of the parent class by providing/overriding the correspond virtual methods.

To add a new element, these are the main steps:

  • Set up a working build environment (including simgear): Building FlightGear
  • update/pull simgear,flightgear and fgdata
  • check out a new set of topic branches for each repo: git checkout -b topic/canvas-Camera
  • Navigate to $SG_SRC/canvas/elements
  • Create a new set of files Camera.cxx/.hxx (as per Adding a new Canvas element)
  • add them to $SG_SRC/canvas/elements/CMakeLists.txt (as per Developing using CMake)
  • edit $SG_SRC/canvas/elements/CanvasGroup.cxx to register your new element (header and staticInit)
  • begin replacing the stubs with your own C++ code
  • map the corresponding OSG/library APIs to properties/events understood by the Canvas element (see the valueChanged() and update() methods)
  • alternatively, consider using dedicated Nasal/CppBind bindings

Below, you can find patches illustrating how to approach each of these steps using boilerplate code, which you will need to customize/replace accordingly:







Next, we need to look at $FG_SRC/Viewer/CameraGroup.cxx to see how slave cameras are set up:

OSG slave camera rendered to an TextureRectangle [1]

2D Plotting

1rightarrow.png See Howto:Extending Canvas to support MathGL for the main article about this subject.


Screen shot showing a Canvas GUI dialog with a custom MathGL element rendering a simple sine (proof-of-concept) - the point being, while simple stuff like this can certainly be renderered using our existing Canvas.Path element, more complex/mathematical expressions and functions are better handled by a dedicated plotting library, that is threaded and hardware accelerated (OpenGL+ GLSL).
This is the same custom MathGL Canvas element rendering a more complex 3D mesh/function, fully hardware accelerated using OpenGL and GLSL, including support for threaded number crunching in pthread-enabled MathGL builds


Cquote1.png Trivial graphs can certainly be plotted using Nasal/Canvas (as per the screen shots/examples discussed above), but anything more complex (think multiple 2d/3d graphs) are unlikely to benefit from the explicit nature of using Canvas (OpenVG) for plotting purposes, keep in mind all the property I/O and setup overhead for otherwise identical graphs.

So anybody really wanting to do 2D/3D plotting (analogous to gnuplot), inside the fgfs main process, would be well-advised to use an existing library like MathGL (GPL, multi-platform), or GNU Octave, and expose this to Canvas as a custom element, specifically dedicated to 2d/3d plotting - possibly with Nasal/CppBind support:

Cquote2.png