|Started in||05/2012 (Available since FlightGear 2.8)|
|Description||Dynamic 2D drawing at runtime using the property tree and scripting (for instruments, HUDs, GUIs)|
|Contributor(s)||TheTom (since 02/2012)|
|Status||Under active development as of 02/2013|
| The FlightGear forum has a
subforum related to: Canvas
In FlightGear, a Canvas is a dynamically created image (OpenGL texture) that can be created and modified (drawn to) at runtime by using the Property Tree, i.e. via the built-in scripting language Nasal and setting a few properties via or its object-oriented wrapper props.nas.
Canvas is all about rendering to a texture and updating it dynamically at run-time by modifying a sub-tree in the property tree that represents the texture (RTT) - its primary rendering primitives are:
- text (via osgText)
- vector graphics (via shivaVG/OpenVG)
- static raster images (or dynamic images via osg::Image represented as another Canvas)
- groups/maps - for grouping/nesting elements to arbitrary depths, and selectively controlling/transforming/clipping each sub-tree
Canvas itself maintains a FBO (frame buffer object ) for each texture, which is also the mechanism in use by Rembrandt. In other words, Canvas is an abstraction mechanism for RTT/FBO management via conventional FlightGear properties. A Canvas texture can optionally also respond to common GUI events to support keyboard/mouse interactions (e.g. drag&drop, hot-keys).
It is a good idea to learn more about OOP (object oriented programming) and how to use that in Nasal.
Next, you will probably want to look at some of the existing Canvas sources - i.e. $FG_ROOT/Nasal/canvas/* (especially api.nas)
And then, you need to understand that Canvas works in form of primitives that form the primitives/ "building blocks" for all instruments.
Namely: text handling, raster images, OpenVG Paths
Everything else is built on top of these primitives (well, except for Maps, but that's a different topic). For learning purposes, you could play with the examples that can be found in the Canvas snippets article on the wiki: Canvas Snippets Note that you need to understand OOP, and especially method chaining, to understand how those examples work behind the scenes.
Canvas textures can be used for a number of different purposes, such as creating fully-scripted avionics (airliner/bizjet -style/MFD glass cockpits) but also custom HUDs and custom GUI textures, even fully interactive GUI widgets (scheduled for FG 4.2+) and interactive scenery elements (e.g. VDGS).
You can use any arbitrary shape to place a canvas onto. For a HUD you just need to create an arbitrarily shaped polygon with your favorite 3d modeling software and place a canvas onto it. As everything drawn onto the canvas goes to an offscreen texture first, only the parts placed onto the 3d model are shown.
You can also draw transparent paths. With the correct blending mode you can just replace all existing contents. It's not named mask, but you can use every canvas element as a mask:
# replace everything already drawn with the pixels of the path path.set("blend-source", "one") .set("blend-destination", "zero");
Currently only rectangular clipping regions are possible (and will be for the next time). You can still get rounded corners if you just draw them in black (or any other background color) on top of the clipped region.
The canvas subsystem is entirely implemented on top of the FlightGear Property Tree, it makes use of property listeners to watch a sub tree of the property tree for canvas-related events (e.g. drawing commands or events to load an image from disk), so that textures can be dynamically instantiated and modified by setting properties in the property tree. This method is not specific to Nasal scripting, the same system can be used by other subsystems (such as the Telnet or HTTP daemons) to create and modify textures without directly using Nasal. The Canvas makes use of OpenVG for 2D rendering.
As of 08/2012, the Canvas system is still under active development and nothing is set in stone yet. See Canvas Properties for further information.
The first prototype of the canvas system became available in FlightGear 2.8, this lacked some features currently under development (notably the Nasal API, support for raster and vector images)- it is expected that a more feature-rich version will be available in the following release, i.e. FlightGear 3.0+ - possibly replacing the entire existing PUI GUI with a fully Canvas-driven implementation in scripting space (one of the primary long-term goals is to modernize the FlightGear GUI).
Future FlightGear versions will contain reimplementations of currently hard-coded instruments such as the wxradar, tcas or navdisplay using the canvas system, so that these can be easily maintained as part of the base package, and so that the same backend code can be also used for creating sophisticated dialogs using the Canvas system, such as ATC displays like ATC-FS, sharing a single backend - without having to re-implement logic for otherwise identical purposes (currently, we have code that implements a navigational display, while another piece of code renders a conceptually identical Map dialog).
Among other advantages, this will also provide for an opportunity to run Canvas-based instruments and GUI elements in another process, or even on another computer, analogous to FGPanel (see FGCanvas).
The canvas system allows you to use SVG images drawn with Inkscape, and easily use raster images and even commpletely custom drawing commands using OpenVG paths.
However, please do note that the canvas cannot currently be run in a standalone/FGPanel-fashion - there's been some talk about that, but that will at least take another 1-2 releases probably. That being said, you could certainly come up with a canvas instrument panel, and then simply use in a dedicated fgfs instance, which is slaved to a corresonding master instance.
Also, there's currently work ongoing to port the old 2D panel and HUD systems to the new Canvas system, using custom Nasal wrappers reimplementing the old behavior and turning the textures into canvas properties.
Requirements and Limitations
Beginning with 2.8, up to 2.99+, all FlightGear versions require FBO support for the canvas system to work properly . In particular, this means that very old GPUs such as Intel 910/915 cards are currently not supported (FBO support is obviously also required for Rembrandt to work), people without FBO support are likely to just get "white" Canvas textures.
Unless render-to-texture (RTT) support can be provided through some form of fallback mode for hardware without FBO support, we we might need to consider officially un-supporting such old hardware from 3.0 (since we can already detect the vendor as Intel).
It seems 940-class chips are okay, and the 2000/3000/4000HD versions seem to work, but the earlier 9xx and before are going to be problematic for the time being . At the moment, it isn't clear if telling the od_gauge/OSG backend code to use pbuffer rendering instead of FBOs would already help solve the problem .
Latest Canvas Efforts
- Canvas EFIS Framework (2020/02): jsb
- Canvas MapStructure (2013/2014: Philosopher & Hooray)
- NavDisplay (2013/2014: Gijs, Hyde)
- Canvas GUI (2013-2015: TheTom)
- Canvas MCDU Framework (2012: TheTom)
Canvas and Nasal
Using the Canvas in non-FG projects
The canvas system has been refactored such that it can be more easily re-used in other programs, this included moving the Canvas component from FlightGear to SimGear and releasing the canvas code under SimGear's license (LGPL).
It is now possible to use the Canvas in projects unrelated to FlightGear, but you will obviously benefit from using certain FlightGear-related technologies, such as an * property tree
- SGSubsystem/Mgr-based main loop
- an osgviewer-based main window
- Nasal scripting
Icecode's FGRadar project is such a completely separate code base from FG, which uses SG/FG components to simplify code reuse, without re-inventing the wheel.
For this very purpose, FGRadar uses a custom "SGApplication" framework - so that existing FlightGear subsystems can be more easily reused in different projects. All that's needed is deriving your own class from "SGApplication" and implementing its interface. The whole idea behind "SGApplication" is to provide a scriptable framework for OpenGL applications, fully based on 1) OSG, 2) SGSubsystems, 3) Nasal scripting and 4) the Canvas.
|the whole purpose of SGApplication is to provide a SGSubsystem-based "architecture" so that Nasal + Canvas and the property tree code can be easily reused.
|the SGApplication stuff isn't really needed, we just came up with it to simplify working with the SG code. But at least it demonstrates how the whole SGSubsystemMgr stuff works.
|"fgpanel" is a code base that is using the "copy & paste" approach - so could serve as another example (beyond fgradar).
For additional info, see: http://forum.flightgear.org/viewtopic.php?f=71&t=18415
A short video demonstrating a possible usecase (C-130J AMU):
By using alphablending it can also be used to render the contents of a HUD:
In my branch there is now also support for using the canvas in a gui widget:
With the new map element it is also very easy to draw maps:
Using the new canvas.parsesvg function to use an SVG file to simulate an EICAS display:
Demonstrating how the new Canvas GUI wrapper can be used to create entirely custom, scripted GUI widgets using XML, SVG and Nasal:
Experimenting with selecting text and positioning a cursor inside the text. The visualization is all done using Nasal.
Since 07/2012, the canvas system also provides support for full window-drawing:
Omega95 has reimplemented the CDU of the ATR72 using the Canvas system:
Another video demonstrating window stacking and nested canvases:
Using Canvas mouse events to create animation of slider, wheel and knob