Canvas Concepts - an Introduction
|This article is a stub. You can help the wiki by|
Introduce important Canvas concepts and terminology, inspired by Thorsten's thread on the forum 
think of it like applying a texture to a model. That's all that canvas is doing. But you can move around bits of the texture. You can create an SVG, and name parts of it (think blender and objects, sort of), and then point the canvas file to an SVG image, and say "I want to move this piece here, and have it look like this." Outside of using an SVG file, you can also say in the canvas file "I want to draw a line here, and here and here, and a circle here, and they should move around like this," or "I want these numbers to be written here, and this is what those numbers say."
Canvas knows text elements, line segments (potentially combined into shapes filled with a color) and raster images. They may or may not form groups. Each element/group can be translated, rotated, scaled, hidden or clipped. For instance an airspeed tape is a filled rectangle shape with lines as the scale and text added, ideally combined into a group. The whole group is translated with an airspeed-dependent factor and placed into a clipping rectangle, so that only the portion just visible appears. An alphanumerical gauge is a text element placed at a screen position for which the text is set to the value of a property in every update cycle. A compass arrow is a filled closed path of lines which is translated from the compass center and then rotated with the heading. That's the idea of canvas in a nutshell. You can define all these elements in canvas directly, or you can create them on as SVG and read the SVG and then reference the elements by their name in the SVG file - after the parser stage, it's pretty much all the same, SVG elements end up being canvas elements.
Richard wrote an article on how to do an instrument using canvas : http://chateau-logic.com/content/flightgear-using-canvas-3d-instrument
the Canvas system itself really only provides a single top-level group (think FOLDER) per Canvas, which can contain other child elements, including raster images, text, OpenVG paths, maps or other groups - i.e. it's a fully recursive thing, groups can have groups can have groups. So you need to understand how the tree data structure works, and how it relates to the FlightGear property tree. The power behind the Canvas system in FlightGear is certainly not due to its documentation, but because it's using industry standards and concepts that people can easily read up on - without things having to be specific to FlightGear/SimGear. If you don't have a clue about these things, tinkering around with the Canvas Snippets article, the Nasal Console and a few tutorials may help you learn more.
Canvas is primarily a subsystem that works in terms of listeners, each element added to a Canvas, and all their child elements will monitor the tree for "events", i.e. property accesses/updates.
It basically maps a tiny subset of the property tree to OSG primitives, so is a property-driven state machine.
This may result in hundreds, or even thousands, of callbacks to be invoked recursively to propagate events properly.
Whenever an element-specific property is updated (think a color, translation etc changed), this results in the element-specific geode to be marked as "dirty", so that the geode is updated.
These updates can be minimized by not setting/updating certain properties, e.g. those of invariant canvas elements that will basically stay the same in between multiple frames - in such cases, the corresponding group/element-specific osg::Geode from the previous frame can be reused "as is" - which is not specific to Canvas, it's a general scenegraph thing to minimize unnecessary scenegraph traversals.
The Canvas-specific thing is that all this happening via listeners comes at a cost, which is why it is generally a good idea to check if reusing previously allocated data structures (as in, the elements/groups forming the geometry) can be reused, instead of clearing out the geometry and re-creating it from scratch - because at that point, you are throwing all optimization opportunities out of the window, because that will inevitably cause all code to re-run - whereas reusing parts of the scenegraph in the next frame, can simplify the workload tremendously - e.g. that is why we marked certain NavDisplay geometry as "static" and rendered that to a separate Canvas texture which we are treating as a texture map to get out relevant bits, at that point, it's just dealing with textured quads only - and no longer has to run any Canvas::Path or ShivaVG code to actually render the geometry.
the Canvas system really is a scenegraph - so if you have something that you'd like to be able to hide/show, clear or change selectively, just put it into a separate group and use that group as the "handle" to deal with the whole shebang (it really is a osg::Group under the hood, i.e. an osg::Transform IIRC, which is a child class inheriting from ::Group)
| The FlightGear forum has a
subforum related to: Canvas
What is a Canvas
Here's the main concept (found by googling "canvas 2D"): https://en.wikipedia.org/wiki/Canvas_element
In FlightGear, things are a bit different, mainly in that :
- a Canvas represents an actual off-screen OpenGL texture (2D) (FBO/RTT)
- is hardware-accelerated
- is using OSG for most of its features
- there is an actual scenegraph
What is a Canvas element