Board index FlightGear Development Canvas

Dynamic duplication of elements

Canvas is FlightGear's new fully scriptable 2D drawing system that will allow you to easily create new instruments, HUDs and even GUI dialogs and custom GUI widgets, without having to write C++ code and without having to rebuild FlightGear.

Dynamic duplication of elements

Postby Gijs » Tue Oct 15, 2013 2:33 pm

Hi,

just wondering if it is possible to duplicate a SVG element in Nasal? I'd like to draw a symbol only once in the SVG and then place multiple instances of it on my display. They need to be unique elements, as I'd like to animate them independently. I've looked for "duplicate" or "copy" in the API, but didn't find anything...

Cheers,
Gijs
Airports: EHAM, EHLE, KSFO
Aircraft: 747-400
User avatar
Gijs
Moderator
 
Posts: 9544
Joined: Tue Jul 03, 2007 3:55 pm
Location: Delft, the Netherlands
Callsign: PH-GYS
Version: Git
OS: Windows 10

Re: Dynamic duplication of elements

Postby Hooray » Tue Oct 15, 2013 3:09 pm

We talked about that several times previously - basically, a way to easily instantiate a symbol/geometry/group multiple times, in a cached fashion, without eating up unnecessary memory for multiple independently-animated instances of a symbol:

Subject: Using a canvas map in the GUI

zakalawe wrote:Just to say, I am planning to convert the MapWidget to use this code too, and then the NavDisplay. Support for PNG/texture icons as symbols will be needed for that, and I will also expose the 'route path' which is generated by C++ to Nasal, so a Canvas Path can be created from it.

There's also a long-requested feature to use the replay-code to extract the historical aircraft position, which would be another kind of data to show.

Deciding an API for limiting symbols / databoxes is going to be very important - the NavDisplay and MapWidget already have different solutions for that. In particular there's a notion of symbol priority - basically I sort the available symbols by priority, and the display can be limited to the most important 10/50/100. This is also the approach taken by some real world map displays.

The MapWidget also checks to ensures data-boxes don't overlap where possible - I've no clue how to do that in the current canvas code, however.



Subject: Using a canvas map in the GUI

zakalawe wrote:
TheTom wrote in Mon Sep 24, 2012 9:40 pm:I'm thinking about using a separate canvas for each symbol so that every instance of it is just a textured quad. For efficiency reasons it would be good to draw all symbols to a single canvas/texture and put all quads into a single node. So probably I'll add a new element type for putting quads into a single element which are all rendered at once. Maybe we can even use a geometry shader to just copy the positions to the GPU and generate the full quads with the shader. Ideas and suggestions are always welcome :)


Hmm - that's possible. The issue there (at least based on the NavDisplay) is that there's quite high variance in the symbols, e.g. colour changes. For the ND I keep the symbols at greyscale, and colour them based on parameter data (active vs tuned vs inactive for navaids, for example)

Definitely needs some thought, but I think it can be an upgrade - we don't need to get the design right immediately! I do like the idea of the Canvas managing the symbol cache texture, however, since generating it by hand (as the TCAS and ND currently require) is annoying.


I haven't followed Tom's commits very closely, but I don't think that this is currently supported - but overall, SVG files are just XML files that are read by Nasal and turned into canvas properties, so you can simply use the APIs in props.nas to clone/copy a canvas group (SVG image) and parametrize it afterwards for customization purposes (changing color etc), see: https://gitorious.org/fg/fgdata/source/ ... s.nas#L184

Code: Select all
##
# Recursively copy property branch from source Node to
# destination Node. Doesn't copy aliases. Copies attributes
# if optional third argument is set and non-zero.
#


Tom has added some clever code to SG that emulates property-inheritance (for styling purposes), the same concept could be reused for caching repeated geometry/symbols at some point.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 12707
Joined: Tue Mar 25, 2008 9:40 am
Pronouns: THOU

Re: Dynamic duplication of elements

Postby zakalawe » Tue Oct 15, 2013 6:01 pm

I suspect that without some C++ level sharing of instanced elements, large numbers of complex (SVG path) symbols + DATA will be an issue. Of course based on my experience at FSWeekend last year, this is an issue in the real systems too - eg show WPT at > 80nm range!

Tom has mentioned a sprite cache for instancing, that would work great as a solution but I don't know if he or anyone else has worked on it.
zakalawe
 
Posts: 1259
Joined: Sat Jul 19, 2008 5:48 pm
Location: Edinburgh, Scotland
Callsign: G-ZKLW
Version: next
OS: Mac

Re: Dynamic duplication of elements

Postby Hooray » Tue Oct 15, 2013 6:28 pm

I suspect that without some C++ level sharing of instanced elements, large numbers of complex (SVG path) symbols + DATA will be an issue.


There's been quite a bit of public and private discussion on various possible caching techniques in the past, some of them are to be found in the wiki - and while I agree that this would be important at some point, the real issue is that keeping the property tree the sole storage mechanism is incredibly powerful and going to be really important, like Tom mentioned various times. I am no longer convinced that we need to get really fancy here... despite counter-examples like the taxiways at KNUQ :D

In contrast, introducing clever caching schemes in C++ space (e.g. by having an OSG texture for caching and aliasing groups while maintaining a refcount and animating each instance individually), makes some things pretty tricky eventually - for instance, all od_gauge-based instruments have zero understanding of master/slave setups, like those common at FSWeekend or LinuxTag - yet this is an increasingly important use-case for serious or professional users - similarly, support for multiple windows (or even screens) isn't well-integrated with the rest of FlightGear. Proper support for multiple GPUs is another issue.

While most of this applies admittedly also to the Canvas system currently, fixing these, would be fairly straightforward and self-contained (in comparison to touching dozens of places to fix up the 2D panel code, HUDs and C++ instruments etc) - as long as the property tree remains the sole storage (and transport) mechanism, as it applies to the canvas currently - without any fancy form of caching that /might/ break in advanced setups.

Likewise, we've been talking about having a FGCanvas mode built right into the fgfs binary at some point, analogous to how FGPanel works - just as an integrated part of the main code base, while not only supporting 2D panels, but also MFD-style cockpits and even GUI elements.

Realistically, it is only feasible to support such use-cases by having a single common backend that knows how to deal with multiple windows, rendering contexts, GPUs or multiple fgfs instances.

A while ago, I played around with showing canvas instruments in a slaved fgfs instance - and it actually worked pretty well just by using the existing telnet interface, the subscribe command and 20 lines of Nasal to fix up property path index numbers, while the telnet protocol isn't very fast - it was sufficient to show the airport selection map in a slave instance, as a cockpit texture - without any C++ changes. We once had a long discussion about necessary changes to "mount" remote property trees in a local property tree to replicate state - but the experiment showed that even a crude synchronization mechanism like the props protocol works well-enough for a single instrument.

In summary, we really need to make sure that whatever form of caching/optimizations are introduced, that they can work in master/slave setups, and that is automatically the case as long as the property tree is the sole storage and transport mechanism, so if there is some form of cache, it needs to be local and transparent to the property tree - so that slaved instances get their chance to update their local cache, rather than cross-referencing cached items in multiple interlinked instances.

While it may not seem important right now, because most other simulator features are similarly broken or "crippled", the canvas system is the most feasible chance to address these once and for all.

Either way, caching is going to be important, simply because the GUI is going to be 100% canvas at some point - and having multiple instances of a widget seems like one of the most common use-cases, even when not flying.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 12707
Joined: Tue Mar 25, 2008 9:40 am
Pronouns: THOU

Re: Dynamic duplication of elements

Postby TheTom » Wed Oct 16, 2013 10:13 am

Copying the according branch of the property tree is probably the way to go. There is no special function in the Nasal API yet, but in the meantime you can just copy the property tree manually (using props.copy). For an example have a look at the SVG parser, as I have implemented the svg <use> tag using this method. Just be aware that no event handler is copied, and that completely independend objects are created, so every handle to an element has to be retrieved again for the new branch.
TheTom
 
Posts: 322
Joined: Sun Oct 09, 2011 11:20 am

Re: Dynamic duplication of elements

Postby Hooray » Wed Oct 16, 2013 11:22 am

Gijs wrote in Tue Oct 15, 2013 2:33 pm:I'd like to draw a symbol only once in the SVG and then place multiple instances of it on my display. They need to be unique elements, as I'd like to animate them independently.

depending on the type of animations required, you can also set up all svg symbols as pre-created (separate) canvases and then just reference them as an image via canvas:// and independently transform/translate the corresponding raster images of each SVG.

If you have lots of symbols that only differ in color, orientation or position, that should be more efficient - even if it means having 10 different canvases as "templates".
Instead of having dozens of independent canvas/svg groups in the tree that need to be separately updated and triangulated/rasterized. However, labels should then obviously kept distinct, i.e. in another canvas group.

I have never tried it, and I don't know if Tom has implemented the code for this (in the nested canvas mode) - but you should theoretically be able to use even a single canvas as the symbol cache by using texture mapping: http://wiki.flightgear.org/Howto:Using_ ... xture_Maps

Basically, you would set up all symbols once in a single canvas, just using different coordinates for each group - and then reference the right symbol by using canvas:// and using the setSourceRect() method to get the proper raster image out of the main texture. You should be able to use the property tree to look up the bounding box of each group, so that you know the parameters for each texture mapped element

So assuming that the canvas code handles nested canvases just as conventional raster images, you can easily set up a simple caching scheme for frequently used symbols like this.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 12707
Joined: Tue Mar 25, 2008 9:40 am
Pronouns: THOU

Re: Dynamic duplication of elements

Postby Philosopher » Wed Oct 23, 2013 2:20 pm

Tom: is there a way to create a new object from a position in a property tree? Mainly the ghost, since it is needed for the API wrapper. If so, than duplication would be as simple as copying the props and creating a new API object. What are the ghosts used for, anyways? Also, how much parent/child information is stored, can I (for example) get the 5th text element child, or get the parent of a current element?
Philosopher
 
Posts: 1593
Joined: Sun Aug 12, 2012 7:29 pm

Re: Dynamic duplication of elements

Postby TheTom » Wed Oct 23, 2013 2:53 pm

Philosopher wrote in Wed Oct 23, 2013 2:20 pm: What are the ghosts used for, anyways?

Ghosts are lightweight wrappers around C/C++ objects/pointers. When using Nasal hashs all information maybe needed by the user has to be written into the hash - even if the user never uses it. A ghost is basically just a wrapper around a C pointer which is very cheap. Only if a user requests a certain member, a request for it is forwarded to the C/C++ code which then returns the requested data.

Philosopher wrote in Wed Oct 23, 2013 2:20 pm:is there a way to create a new object from a position in a property tree? Mainly the ghost, since it is needed for the API wrapper. If so, than duplication would be as simple as copying the props and creating a new API object.

One possiblity is to create a new group, store its new ghost/API object and then copy the property tree branch over it (The group object will still be valid).

The other possiblity is to use element._getChild(node._g) and wrap the returned ghost into an API object (Group._wrapElement is doing exactly what I've just described). You can access also access any child by using this method. Retrieving a parent is currently not easily possible. You can only use the property node of the element, extract the canvas, and move down the tree by using _getChild on each intermediate group.
TheTom
 
Posts: 322
Joined: Sun Oct 09, 2011 11:20 am

Re: Dynamic duplication of elements

Postby Hooray » Wed Oct 23, 2013 3:16 pm

TheTom wrote in Wed Oct 23, 2013 2:53 pm:Retrieving a parent is currently not easily possible. You can only use the property node of the element, extract the canvas, and move down the tree by using _getChild on each intermediate group.


Maybe I am missing something, but couldn't that be accomplished by using the property tree's support for aliasing properties, i.e. adding an aliased element to each group/element that refers to the parent, would that work or not ?
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 12707
Joined: Tue Mar 25, 2008 9:40 am
Pronouns: THOU

Re: Dynamic duplication of elements

Postby Philosopher » Wed Oct 23, 2013 3:20 pm

See #1175: children can't be aliased (yet).
Philosopher
 
Posts: 1593
Joined: Sun Aug 12, 2012 7:29 pm

Re: Dynamic duplication of elements

Postby TheTom » Wed Oct 23, 2013 3:24 pm

Hooray wrote in Wed Oct 23, 2013 3:16 pm:i.e. adding an aliased element to each group/element that refers to the parent, would that work or not ?

The problem is not to get the parent node, but the parent element (ghost). As there is no global list of elements it is only possible to get an element from a group by matching the property node of this element. So to do this from Nasal one needs to get a group above the element and move down until reaching the parent element. I will extend the API to allow easy access to the parent (which will be about one line of code).
TheTom
 
Posts: 322
Joined: Sun Oct 09, 2011 11:20 am

Re: Dynamic duplication of elements

Postby TheTom » Wed Oct 23, 2013 4:36 pm

Update sg/fg/fgdata and use canvas.Element.getParent() :-)
TheTom
 
Posts: 322
Joined: Sun Oct 09, 2011 11:20 am


Return to Canvas

Who is online

Users browsing this forum: No registered users and 5 guests