Canvas properties: Difference between revisions

From FlightGear wiki
Jump to navigation Jump to search
m (Robot: Cosmetic changes)
m (Johan G moved page Canvas Properties to Canvas properties: Sentence case title)
 
(137 intermediate revisions by 6 users not shown)
Line 1: Line 1:
{{Stub}}
<!--
{{WIP|Update: As of 05/2012 this is being worked on as part of some merge requests and [[Howto: Create a 2D drawing API for FlightGear]].}}
-->


Proposal for a property-driven 2D drawing API for FlightGear
{{Template:Canvas Navigation}}
A property-driven 2D drawing API for [[FlightGear]].


== Status 07/2013 ==


This proposal is based on a number of related discussions and/or recent developments, for more detail please see:
Tom is currently working on a 2D drawing API. The basic idea is to draw arbitrary 2D shapes and text to a texture and place this texture on some model in the scene (eg. display, HUD,...). This so called canvas should be controlled only by using the property tree.
* [[FlightGear Glass Cockpits]] (introduces the need for a 2D drawing API for use in Nasal)
* [[Plan-zakalawe]] (suggests a [http://en.wikipedia.org/wiki/Canvas_element HTML5/canvas] based approach for a 2D drawing API in FlightGear)
* [[Map]] (a compelling prototype implementation of a navigational display implemented as a custom PUI widget)
* [[Modularizing, parallelizing and distributing FlightGear]] (a discussion that focuses on establishing the property tree as the standard and preferred mechanism for doing subsystem communications)


Core developers acknowledge the fact that FlightGear needs a 2D drawing API to implement Head Up Displays (HUD) and Multi Function Displays (MFD) (see [http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg05396.html]):
Currently it is possible to draw text, arbitrary OpenVG paths, use vector and raster images and transparently create geographic maps, transform them, change styles and all of this through the property tree. There's also a Nasal API which provides an object-orientated wrapper around the property tree interface to the canvas.


What we will need is some cairo/glitz like 2d api to draw the HUD and do some
In 07/2013, Tom added a decoration engine, and improved the C++ window manager to allow creating shadows and window decoration with a single line of Nasal code. Meanwhile, Canvas textures can be used in cockpits/aircraft, GUI windows and dialogs and as part of the scenery.
MFD's. I believe that this is even more apprioriate for such rendering areas
like issuing raw OpenGL commands.
With such an abstraction we are open to map that to an immediate more
rendering pass to a texture or if this is used to build up a part of the  
scenegraph in case we do not have RenderTexture available.


The long term idea is to eventually port some other 2D elements to this backend (eg the HUD and 2D panels) so they use OSG (and osgText) natively, and hence reduce the amount of C++ code we have for these jobs. (And increase our chances of working with never OpenGL versions that forbid old style GL calls) Long-term here means 'after 2.8 at least'.


Many of the previous discussions focus on a specific use case scenario for introducing a 2D drawing API to FlightGear, namely that of adding 2D drawing support for scripting glass cockpit functionality.  
In the meantime the more testing and feedback we can get the better. In particular this system should offer a much more efficient way to build CDU interfaces than many text animations, but as always it needs people to experiment and report what features are missing to make their life easier.
Creating a 'fgcanvas' client analogous to 'fgpanel' should be doable too, since the canvas simply renders to a single osg-Camera. Unlike fgpanel this will require OSG instead of raw GL of course, but that's the price we pay for unifying the rendering backend.


This discussion however focuses solely on the 2D drawing API itself, without any specific emphasis on a particular use case or manifestation.
=== Try it out ===
The latest information on the canvas subsystem can be found in {{flightgear source|path=docs-mini/README.canvas|text=README.canvas}}.


= Background =
[[File:Cessna 172P Canvas Demo.png|380px|thumb|Demonstration of the new Canvas drawing API on the Cessna 172P.]]
* "What we will need is some cairo/glitz like 2d api to draw the HUD and do some MFD's. I believe that this is even more apprioriate for such rendering areas like issuing raw OpenGL commands. With such an abstraction we are open to map that to an immediate more rendering pass to a texture or if this is used to build up a part of the scenegraph in case we do not have RenderTexture available."[http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg05396.html]


* "Although the FlightGear design fairly modular it's provided as a single binary.Everyone who wants to create a new I/O module must patch the FlightGear sources and compile the FlightGear binary from scratch. This may discourage those who want to use FlightGear as a tool and extend it in some way. Moreover, it's not always possible to include all functions in a single binary. Some functions may be mutually exclusive"[http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg22673.html]
# Launch FlightGear with the plane c172p-canvas (<code>--aircraft=c172p-canvas</code>)
# Observe a nice display in front of you with some animated text elements
# If it doesn't look like the picture on the right please report a bug (As comment on the merge request or on the Talk page)
# And if it works try out modifying the demo, integrate it into new planes, report more bugs and give me some feedback :)


* "IMHO the one important threading benefit is if we could get all of the rendering off the main simulation loop, meaning that the model runs independent of the presentation."[http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg22935.html]
=== Nasal API ===


* "I guess I'm thinking about how FG is pretty monolithic and wondering how much of an over-head there might be in making it more modular. Might also be worth thinking about parallelism aspects."[http://www.mail-archive.com/flightgear-devel@flightgear.org/msg33306.html]
* ''fgdata/Nasal/canvas/api.nas'' (Contains the implementation of the API)
* ''fgdata/Aircraft/Instruments-3d/canvas-test/canvas-test.nas'' (Demonstrates how to use the API)


* "enforcing subsystems to *only* communicate via the property tree [...] it would then become possible to run any 'clean' subsystem on a pool of worker threads (maybe just one, maybe more)."[http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg18063.html]
See also [[Howto:Add a 2D canvas instrument to your aircraft]]


== ChangeLog ==
* Support a Scenery Placement mode {{done}} (WIP: [{{flightgear url|commit=eba03b5e469824ee8f1494723fcddbbc56155a08|view=commit}}])
* Support drawing to textures for aircraft instruments {{Done}}
* Support drawing to aircraft HUDs {{Done}}
* Support drawing to GUI widgets {{Done}}
* Support creating GUI windows {{Done}}
* '''TheTom''': "If each widget/tool/whatever don't creates an own canvas, but instead just attaches itself to a given group infinite nesting of "canases" would be easily possible already with the current implementation."{{Done}}


= Proposal =
== Planned Features ==
Previous discussions about a 2D drawing API for FlightGear were mostly about providing such an API specifically to be accessed by the Nasal scripting interpreter (e.g. see [[FlightGear Glass Cockpits]]), this discussion instead focuses on using the FlightGear property tree as the common 2D drawing interface among FlightGear subsystems, which would make the 2D drawing API accessible to any FlightGear subsystem (including Nasal) or even external programs accessing FlightGear's property tree, while only adding a very small layer of indirection.
* Support implementing GUI widgets using Canvas/Nasal {{Pending}} (see [[Canvas Widgets]])
* [[#Images: Static Textures & Cascaded Canvases|Static image files]]: should be handled like any other element on the canvas. Only instead of specifying a path you'll have to set the file system path to an image which will be loaded with osg. {{Done}}
* Support placing canvas textures into the scenery, so that dynamic scenery features (i.e. a [http://en.wikipedia.org/wiki/Visual_Docking_Guidance_System visual docking guidance system] or runway skid marks) can be implemented using the canvas system (being discussed and planned as of 08/2012) {{Done}} [{{flightgear url|commit=eba03b5e469824ee8f1494723fcddbbc56155a08|view=commit}}] (WIP)
* '''Hooray''': "yes, sounds like the best and most powerful design to me, because everything would still be a canvas, but nesting/recursion would be supported, i.e. "piping" the output from one canvas into another canvas group, so that canvases can be reused and nested" {{Done}}
* '''TheTom''': "Maybe I should add means to define clipping regions to guarantee widgets can't draw outside their assigned regions, i.e. perform clipping only if there is actually a clipping region specified." {{Done}}
* '''Omega95''': "Supporting 3D objects to be projected onto canvas" [http://forum.flightgear.org/viewtopic.php?f=71&t=17278#p164260]


* allow textures to be instantiated by issuing writes to a corresponding branch in the property tree, e.g. /canvas-textures/texture[0]/size-x=128 and /canvas-textures/texture[0]/size-y=128 to dynamically create a 128x128 px texture (color depth could be equally configurable)
* allow primitives to be rendered to such a texture by adding corresponding "point", "line", "circle" (and so on) child nodes, along with relevant meta information (position-x,position-y, radius, color, width)
* allow nested hierarchies of "drawable" nodes, to draw complex shapes - each "drawable" may be composed of other drawables


=== Supporting distributed master/slave setups ===


== Goals ==
I'd just thought I'd share this, so that we are aware of some shortcomings, and ideas on addressing them:
* provide property tree driven "render to texture" support: create, modify and delete textures using properties
* generic enough to be usable by aircraft panels, GUI dialogs or scenery elements
* provide a 2D rendering API that may be invoked and parametrized by manipulating the property tree
* generic enough to be used for most 2D drawing needs in FlightGear (e.g. instruments, graphs, flight profile view, HUDs, chart views, flight path evaluation, custom UI widgets)
* provide support for basic drawing primitives (i.e. point, line, circle etc)
* make the 2D drawing API network accessible (which it is automatically by implementing it via the property tree)
* provide building blocks for creating new instrument types or developing experimental glass avionics
* with the long term goal of extending functionality to be able to re-implement hardcoded displays (agradar, wxradar, kln89, dclgps, render_area2d)
* allow for retained primitives
* allow for a high degree of configurability and customization (e.g. support styling of individual elements like CSS) by end users


= Canvas Properties =
There's a handful of threads where we talked about configuring multi-instance setups. This
"Canvas properties" would be conventional properties, the only difference being that a certain structure and hierarchy is internally expected to make them valid, so that they can be used to dynamically render to textures.


Creating and drawing to textures would be made possible by setting properties to a branch with registered listeners, that internally manage and implement the rendering aspect, transparently to other subsystems and the end user.  
We have a bunch of options for configuring multiple fgfs instances in a master/slave fashion, where an arbitrary number of slaves can be driven through a single master instance, important properties are sync'ed/replicated through a socket connection. Specific subsystems often have custom hard-coded protocols, for syncing certain state (joystick, fdm, controls etc)
This is an old feature, which is still working - but many more recent features do not properly/fully support it. The canvas being one of them.
However, it still is an important feature, that is also used at various event to demonstrate FlightGear to new users, such as e.g. FSWeekend and LinuxTag.


So that for example dynamically drawing a circle to a texture would be as simple as doing something along the lines of:
The underlying issue is pretty common in FG, can be seen in many places - such as clouds/weather not being in sync, AI traffic, animations/effects etc


# set up a texture for the canvas
Often, this requires lots of work to fix properly, because subsystems were not really designed to serialize internal state via the property tree, so there's lots of "private" state that never shows up in the tree, and there are no hooks to send events to sync things.
setprop("/canvas-textures/texture[0]/size-x",128);
setprop("/canvas-textures/texture[0]/size-y",128);
setprop("/canvas-textures/texture[0]/bpp",32);
# add a drawable child node
setprop("/canvas-textures/texture[0]/drawable[0]/type","circle");  # set the type
setprop("/canvas-textures/texture[0]/drawable[0]/position-x",0.5); # add type specific arguments
setprop("/canvas-textures/texture[0]/drawable[0]/position-y",0.5); # add type specific arguments
setprop("/canvas-textures/texture[0]/drawable[0]/radius",30);      # set radius for this type


This is pretty intuitive to work with and it would be straightforward to add a simple Nasal wrapper on top of it.  
However, the Canvas is a different "beast", because it is already built on top of the property tree, much moreso than any other subsystem probably.


Internally, the managing subsystem could for example convert each drawable to an OpenGL display list or vertex array to improve efficiency.
A while ago, we talked about the idea of supporting something like FGCanvas, analogous to FGPanel - which is also just about synchronizing properties in a master/slave fashion once you think about it.  
Once a drawable (or any of its child nodes) is modified, the drawable would be marked as "dirty" to trigger an update.


Back then, we briefly talked about the idea of "mounting" a property tree in a remote instance to sync state properly and to formalize master/slave relationships.


I have been able to get this somewhat working by using the telnet protocol, and its "subscribe" command to get updates for the /canvas branch in the main instance - the power of canvas & the property tree makes that pretty simple. However, it's really crude, because it will get all update notifications, without being selective - because instances don't know anything about the master, and about stuff that would be redundant to do.


== Approach ==
So, that's a use-case for which the canvas wasn't really designed obviously: basically, you end up with two canvas subsystems, without the 2nd/slaved system being aware that it is a slave, and that it should not do certain things, and instead rely on CERTAIN data from the master. Instead, the 2nd canvas system may override some received state, with its own internal state currently. In other words, I may be having multiple canvas instances in each fgfs instance, that is not aware of what the other one is doing, as long as it's a really simple instrument/dialog, it doesn't matter - but things fall quickly apart once things become more sophisticated.
Using property listeners, provide support for drawing basic primitives (i.e. points, lines, rectangles, circles) to dynamically created and updated textures by setting properties in a dedicated branch of the property tree.
This proposal integrates well with previously discussed plans to make FlightGear more modular by leveraging its property tree to handle IPC among all subsystems and related external programs.


To address this, I am thinking in terms of adding a property attribute to mark certain properties as master/slave, so that a sync/replication mechanism at the property tree level knows exactly which properties to send/request, and which ones to compute locally.


== Advantages ==
Also, I would want to formalize properties as being "input" or "output" properties, so that the canvas system knows for example that a certain property is a "readonly slave" property, i.e. comes from the master and cannot be affected locally.
While this adds a thin layer of indirection, it has many advantages:


* textures may be dynamically created and modified by arbitrary other FlightGear subsystems, simply by writing to a corresponding node in the property tree, so that new textures can be easily instantiated, and existing ones can be easily modified just by accessing child properties of a "canvas"
Even if we should not use a manual sync method, the HLA work will also benefit from subsystems having a concept of properties being "master" or "slave". Torsten's fgpanel work is another obvious example that would benefit from knowing more about properties being master or slave - equally, the multiplayer and replay/flight recorder subsystems could benefit from such info.
* a property driven 2D drawing API has the added benefit of being fully accessible to and usable from other programs accessing the FlightGear property tree, for example using the telnet interface
* this means that it would be perfectly possible to easily provide the infrastructure to allow users to recreate the functionality provided by projects like [[OpenGC]] or [[fggc]], because instantiating textures in FlightGear and drawing to these could be easily controlled from external programs
* this approach follows the MVC pattern, that is already in use in many other parts of FlightGear (e.g. FDM)
* this practice of using the property tree as an abstraction layer to generalize and channel access to a subsystem is already in place in other parts of FlightGear (i.e. FDM, GUI, Autopilot)
* all IPC across subsystems would be implicitly handled by writing to properties with registered listeners, no need to explicitly call other subsystems (the AI traffic system is an excellent example for a subsystem that can be largely controlled just by writing to properties)
* so following this approach has the advantage that more complex systems could be easily run outside the FlightGear process space, while still rendering to an OpenGL context shown in FlightGear
* there is a general consensus among FlightGear developers that having subsystems that exclusively communicate with other FlightGear systems using the property tree, will help make FlightGear more modular and more easily parallelizable (see [[Modularizing, parallelizing and distributing FlightGear]])
* by following this route, it will be very straightforward to run components in different threads or processes
* this would make it for example possible to do standalone rendering of certain panel instruments in a dedicated fgfs instance, driven by another one (dedicated instrument viewer)
* so a property driven 2D rendering API provides the infrastructure to facilitate the creation of such systems
* adding a thin layer of Nasal code to provide a wrapper would be very straightforward (similar to how the GUI system is currently wrapped by a corresponding Nasal module, which also just instantiates GUI dialogs by writing to the property tree)
* by using properties with registered listeners, there will be a high degree of configurability and customizability
* symbols would not need to be hardcoded, instead live in the base package and be contributed and maintained there
* serialization: automatically supported by storing everything in property tree XML format
* reusable drawables won't need to be hardcoded, instead they could be saved as XML file in the base package
* parametrization of drawables would make it possible to "derive" from a drawable (i.e. a VOR symbol) and customize it (e.g. by changing the color or size)


= Primitives =
IIRC you are using PropertyObjects<> - so my current idea would be to extend that class and allow such attributes to be specified via enums, i.e. to mark properties as master/slave and input/output, so that certain code paths can be made optional, because they should only be done on the master or slave side.
* Point (x,y)
 
* Line (x1,y1 - x2,y2)
The sync mechanism/protocol could then traverse the canvas tree and check which properties it needs to subscribe to from the master, and which ones are client-side
* Circle (x,y,r)
 
* Rectangle
Given that more and more systems are going to switch over to the canvas (HUD, instruments, MFDs), it would make sense to come up with a mechanism that allows multi-instance setups to be properly sync'ed - especially because this is something that all the hard-coded MFDs are also not very good at (NavDisplay, wxradar etc)
* Texture (image)
 
* Text (string)
In other words, the question would be how to better support use-cases where an aircraft that relies on canvas-MFDs, like zhr C130J for example, is simulated by multiple inter-connected fgfs instances - another valid scenario would be our existing "dual-pilot support", which goes to show that we should keep in mind such synchronized master/slave setups.
 
Thoughts / better ideas ?
 
=== Adressing modes: by-index, by-name (property mounting) ===
As a first step I've now moved /canvas/texture[x] to /canvas/by-index/texture[x]. Later we can than add links from eg. /canvas/gui/texture[x] to /canvas/by-index/texture[y]. I just don't know how to best link it yet. Either make /canvas/gui/texture[x] a string property which contains the path to the texture[y] node or an alias to a node inside the texture or even modify the property nodes to support real links (whith all its problems like loops and the like). Another possibililty is to add support for jumping to paths specified in properties in an enhanced property dialog.
 
Referring to [[Remote Properties]] and the mentioned "mounting" support:
 
For displaying one would just need to mount the canvas branch inside the remote EICAS FlightGear instance. If also interaction back to the main FG instance is needed it would also be needed to write to a remote tree. This can be handled the same if remote mounting also supports writing in all directions. So, yes with fill mounting support this would be possible
 
One would just have to decide on which instance of FG the calculations of the ECIAS and other displays should take place, but with full mounting support this should be easily distributable as computing power is available.
 
=== Serializing a canvas to a buffer or file ===
 
{{cquote|<nowiki>I am also thinking about some kind of one-time canvas, where the
contents are just rendered once and afterwards can be used in an other
canvas as a texture and maybe even stored on the hard disk an reused the
next time FlightGear is started up.</nowiki><ref>{{cite web |url=http://www.mail-archive.com/flightgear-devel@lists.sourceforge.net/msg38354.html|title=<nowiki>Airport Selection feedback</nowiki>|author=<nowiki>Thomas Geymayer</nowiki>|date=<nowiki>22-09-2012</nowiki>}}</ref>|<nowiki>Thomas Geymayer</nowiki>}}
 
<references/>
 
See [[FGPlot#Feature_Requests]]: provide a new Nasal API to serialize a canvas texture (or group) to an osg::Image in $FG_HOME, so that graphs can be easily saved and shared/posted without users having to take full screen shots and then having to edit the image [http://forum.flightgear.org/viewtopic.php?f=49&t=17540&hilit=gnuplot#p166472]
 
providing a hook to get a binary dump of the a canvas texture (i.e. as a PNG file)
 
By adding a hook (Nasal extension function) to access the texture of the canvas as a binary dump, Nasal scripts could not only write a canvas texture to the file system, but they could even mime-encode it and send it to the browser (via the built-in HTTP server), so that canvas textures could be shown inside the browser for example, basically canvas textures could be used outside the fgfs process by providing a handle to access the dump.
 
These two features alone would make it possible for people to draw to a canvas, save it to the file system and even chaining canvases by using the output of one canvas, as the input for another one (a while ago, we talked about the lack of support for chaining od_gauge systems).
 
And serializing a canvas is trivial because it's just a property tree, so it can be done via save_properties()
 
In addition, being able to serialize canvases to files on disk, would also help us keeping our docs (the manual) more up to date, because our GUI being canvas-driven, screen shots could be created in an automated/scripted fashion, so that the LaTex docs could automatically show the latest GUI dialogs.
 
Another use-case would be screen shots of individual dialogs, currently users need to capture the whole screen and then cut out the relevant part (see [https://code.google.com/p/flightgear-bugs/issues/detail?id=1192]) - it would be awesome if we could have some dedicated API to capture a canvas and write it to a file, so that only relevant stuff ends up in the file, rather than the whole screen.
 
=== Smart Labels for OSGText elements ===
Looking at the NavDisplay/Map code, the canvas system could use another text-placement mode which tries to be "smart" by using unoccupied screen space for labels, rather than cluttering the displays with lots of labels covering other labels and symbols. i.e. implicit rather than explicit label placement?
 
It's not yet sure how to address this easily, probably that would require bounding box calculations for existing "drawables", so that free spots can be found. Maybe there's a better way? Maybe OSG has some code to get the area required by a drawable ?
There's an open source code on codeproject, titled "Smart Labels"
 
:: Smart labels should probabaly be added as a "group-aware" element, so that they may look at other groups in order to come up with all bounding boxes for their drawables, so that free space can be found - taking into account certain groups ("layers"). Also, smart labels should probably be able to adjust font or background color, in order to be still readable when overlapping with other symbols?
 
::: Note that [http://pal.heig-vd.ch/index.php?page=about-pal PAL] requires [http://trac.osgeo.org/geos/ GEOS], both use an autotools based build system.
 
Also see: http://forum.flightgear.org/viewtopic.php?f=71&p=166909#p166909

Latest revision as of 00:25, 1 May 2021


A property-driven 2D drawing API for FlightGear.

Status 07/2013

Tom is currently working on a 2D drawing API. The basic idea is to draw arbitrary 2D shapes and text to a texture and place this texture on some model in the scene (eg. display, HUD,...). This so called canvas should be controlled only by using the property tree.

Currently it is possible to draw text, arbitrary OpenVG paths, use vector and raster images and transparently create geographic maps, transform them, change styles and all of this through the property tree. There's also a Nasal API which provides an object-orientated wrapper around the property tree interface to the canvas.

In 07/2013, Tom added a decoration engine, and improved the C++ window manager to allow creating shadows and window decoration with a single line of Nasal code. Meanwhile, Canvas textures can be used in cockpits/aircraft, GUI windows and dialogs and as part of the scenery.

The long term idea is to eventually port some other 2D elements to this backend (eg the HUD and 2D panels) so they use OSG (and osgText) natively, and hence reduce the amount of C++ code we have for these jobs. (And increase our chances of working with never OpenGL versions that forbid old style GL calls) Long-term here means 'after 2.8 at least'.

In the meantime the more testing and feedback we can get the better. In particular this system should offer a much more efficient way to build CDU interfaces than many text animations, but as always it needs people to experiment and report what features are missing to make their life easier. Creating a 'fgcanvas' client analogous to 'fgpanel' should be doable too, since the canvas simply renders to a single osg-Camera. Unlike fgpanel this will require OSG instead of raw GL of course, but that's the price we pay for unifying the rendering backend.

Try it out

The latest information on the canvas subsystem can be found in README.canvas.

Demonstration of the new Canvas drawing API on the Cessna 172P.
  1. Launch FlightGear with the plane c172p-canvas (--aircraft=c172p-canvas)
  2. Observe a nice display in front of you with some animated text elements
  3. If it doesn't look like the picture on the right please report a bug (As comment on the merge request or on the Talk page)
  4. And if it works try out modifying the demo, integrate it into new planes, report more bugs and give me some feedback :)

Nasal API

  • fgdata/Nasal/canvas/api.nas (Contains the implementation of the API)
  • fgdata/Aircraft/Instruments-3d/canvas-test/canvas-test.nas (Demonstrates how to use the API)

See also Howto:Add a 2D canvas instrument to your aircraft

ChangeLog

  • Support a Scenery Placement mode Done Done (WIP: [1])
  • Support drawing to textures for aircraft instruments Done Done
  • Support drawing to aircraft HUDs Done Done
  • Support drawing to GUI widgets Done Done
  • Support creating GUI windows Done Done
  • TheTom: "If each widget/tool/whatever don't creates an own canvas, but instead just attaches itself to a given group infinite nesting of "canases" would be easily possible already with the current implementation."Done Done

Planned Features

  • Support implementing GUI widgets using Canvas/Nasal Pending Pending (see Canvas Widgets)
  • Static image files: should be handled like any other element on the canvas. Only instead of specifying a path you'll have to set the file system path to an image which will be loaded with osg. Done Done
  • Support placing canvas textures into the scenery, so that dynamic scenery features (i.e. a visual docking guidance system or runway skid marks) can be implemented using the canvas system (being discussed and planned as of 08/2012) Done Done [2] (WIP)
  • Hooray: "yes, sounds like the best and most powerful design to me, because everything would still be a canvas, but nesting/recursion would be supported, i.e. "piping" the output from one canvas into another canvas group, so that canvases can be reused and nested" Done Done
  • TheTom: "Maybe I should add means to define clipping regions to guarantee widgets can't draw outside their assigned regions, i.e. perform clipping only if there is actually a clipping region specified." Done Done
  • Omega95: "Supporting 3D objects to be projected onto canvas" [3]


Supporting distributed master/slave setups

I'd just thought I'd share this, so that we are aware of some shortcomings, and ideas on addressing them:

There's a handful of threads where we talked about configuring multi-instance setups. This

We have a bunch of options for configuring multiple fgfs instances in a master/slave fashion, where an arbitrary number of slaves can be driven through a single master instance, important properties are sync'ed/replicated through a socket connection. Specific subsystems often have custom hard-coded protocols, for syncing certain state (joystick, fdm, controls etc) This is an old feature, which is still working - but many more recent features do not properly/fully support it. The canvas being one of them. However, it still is an important feature, that is also used at various event to demonstrate FlightGear to new users, such as e.g. FSWeekend and LinuxTag.

The underlying issue is pretty common in FG, can be seen in many places - such as clouds/weather not being in sync, AI traffic, animations/effects etc

Often, this requires lots of work to fix properly, because subsystems were not really designed to serialize internal state via the property tree, so there's lots of "private" state that never shows up in the tree, and there are no hooks to send events to sync things.

However, the Canvas is a different "beast", because it is already built on top of the property tree, much moreso than any other subsystem probably.

A while ago, we talked about the idea of supporting something like FGCanvas, analogous to FGPanel - which is also just about synchronizing properties in a master/slave fashion once you think about it.

Back then, we briefly talked about the idea of "mounting" a property tree in a remote instance to sync state properly and to formalize master/slave relationships.

I have been able to get this somewhat working by using the telnet protocol, and its "subscribe" command to get updates for the /canvas branch in the main instance - the power of canvas & the property tree makes that pretty simple. However, it's really crude, because it will get all update notifications, without being selective - because instances don't know anything about the master, and about stuff that would be redundant to do.

So, that's a use-case for which the canvas wasn't really designed obviously: basically, you end up with two canvas subsystems, without the 2nd/slaved system being aware that it is a slave, and that it should not do certain things, and instead rely on CERTAIN data from the master. Instead, the 2nd canvas system may override some received state, with its own internal state currently. In other words, I may be having multiple canvas instances in each fgfs instance, that is not aware of what the other one is doing, as long as it's a really simple instrument/dialog, it doesn't matter - but things fall quickly apart once things become more sophisticated.

To address this, I am thinking in terms of adding a property attribute to mark certain properties as master/slave, so that a sync/replication mechanism at the property tree level knows exactly which properties to send/request, and which ones to compute locally.

Also, I would want to formalize properties as being "input" or "output" properties, so that the canvas system knows for example that a certain property is a "readonly slave" property, i.e. comes from the master and cannot be affected locally.

Even if we should not use a manual sync method, the HLA work will also benefit from subsystems having a concept of properties being "master" or "slave". Torsten's fgpanel work is another obvious example that would benefit from knowing more about properties being master or slave - equally, the multiplayer and replay/flight recorder subsystems could benefit from such info.

IIRC you are using PropertyObjects<> - so my current idea would be to extend that class and allow such attributes to be specified via enums, i.e. to mark properties as master/slave and input/output, so that certain code paths can be made optional, because they should only be done on the master or slave side.

The sync mechanism/protocol could then traverse the canvas tree and check which properties it needs to subscribe to from the master, and which ones are client-side

Given that more and more systems are going to switch over to the canvas (HUD, instruments, MFDs), it would make sense to come up with a mechanism that allows multi-instance setups to be properly sync'ed - especially because this is something that all the hard-coded MFDs are also not very good at (NavDisplay, wxradar etc)

In other words, the question would be how to better support use-cases where an aircraft that relies on canvas-MFDs, like zhr C130J for example, is simulated by multiple inter-connected fgfs instances - another valid scenario would be our existing "dual-pilot support", which goes to show that we should keep in mind such synchronized master/slave setups.

Thoughts / better ideas ?

Adressing modes: by-index, by-name (property mounting)

As a first step I've now moved /canvas/texture[x] to /canvas/by-index/texture[x]. Later we can than add links from eg. /canvas/gui/texture[x] to /canvas/by-index/texture[y]. I just don't know how to best link it yet. Either make /canvas/gui/texture[x] a string property which contains the path to the texture[y] node or an alias to a node inside the texture or even modify the property nodes to support real links (whith all its problems like loops and the like). Another possibililty is to add support for jumping to paths specified in properties in an enhanced property dialog.

Referring to Remote Properties and the mentioned "mounting" support:

For displaying one would just need to mount the canvas branch inside the remote EICAS FlightGear instance. If also interaction back to the main FG instance is needed it would also be needed to write to a remote tree. This can be handled the same if remote mounting also supports writing in all directions. So, yes with fill mounting support this would be possible

One would just have to decide on which instance of FG the calculations of the ECIAS and other displays should take place, but with full mounting support this should be easily distributable as computing power is available.

Serializing a canvas to a buffer or file

Cquote1.png I am also thinking about some kind of one-time canvas, where the contents are just rendered once and afterwards can be used in an other canvas as a texture and maybe even stored on the hard disk an reused the next time FlightGear is started up.[1]
— Thomas Geymayer
Cquote2.png
  1. Thomas Geymayer (22-09-2012). Airport Selection feedback.

See FGPlot#Feature_Requests: provide a new Nasal API to serialize a canvas texture (or group) to an osg::Image in $FG_HOME, so that graphs can be easily saved and shared/posted without users having to take full screen shots and then having to edit the image [4]

providing a hook to get a binary dump of the a canvas texture (i.e. as a PNG file)

By adding a hook (Nasal extension function) to access the texture of the canvas as a binary dump, Nasal scripts could not only write a canvas texture to the file system, but they could even mime-encode it and send it to the browser (via the built-in HTTP server), so that canvas textures could be shown inside the browser for example, basically canvas textures could be used outside the fgfs process by providing a handle to access the dump.

These two features alone would make it possible for people to draw to a canvas, save it to the file system and even chaining canvases by using the output of one canvas, as the input for another one (a while ago, we talked about the lack of support for chaining od_gauge systems).

And serializing a canvas is trivial because it's just a property tree, so it can be done via save_properties()

In addition, being able to serialize canvases to files on disk, would also help us keeping our docs (the manual) more up to date, because our GUI being canvas-driven, screen shots could be created in an automated/scripted fashion, so that the LaTex docs could automatically show the latest GUI dialogs.

Another use-case would be screen shots of individual dialogs, currently users need to capture the whole screen and then cut out the relevant part (see [5]) - it would be awesome if we could have some dedicated API to capture a canvas and write it to a file, so that only relevant stuff ends up in the file, rather than the whole screen.

Smart Labels for OSGText elements

Looking at the NavDisplay/Map code, the canvas system could use another text-placement mode which tries to be "smart" by using unoccupied screen space for labels, rather than cluttering the displays with lots of labels covering other labels and symbols. i.e. implicit rather than explicit label placement?

It's not yet sure how to address this easily, probably that would require bounding box calculations for existing "drawables", so that free spots can be found. Maybe there's a better way? Maybe OSG has some code to get the area required by a drawable ? There's an open source code on codeproject, titled "Smart Labels"

Smart labels should probabaly be added as a "group-aware" element, so that they may look at other groups in order to come up with all bounding boxes for their drawables, so that free space can be found - taking into account certain groups ("layers"). Also, smart labels should probably be able to adjust font or background color, in order to be still readable when overlapping with other symbols?
Note that PAL requires GEOS, both use an autotools based build system.

Also see: http://forum.flightgear.org/viewtopic.php?f=71&p=166909#p166909