Canvas ND framework

From FlightGear wiki
Revision as of 16:53, 29 November 2013 by Hooray (talk | contribs) (Created page with "{{WIP}} === NavDisplay === The revised design is currently all in Hooray's gitorious clone - there's a separate navdisplay.mfd file in $FG_ROOT/Nasal/canvas/map - the integra...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
WIP.png Work in progress
This article or section will be worked on in the upcoming hours or days.
See history for the latest developments.

NavDisplay

The revised design is currently all in Hooray's gitorious clone - there's a separate navdisplay.mfd file in $FG_ROOT/Nasal/canvas/map - the integration layer is in 744/Models/Cockpit/Instruments/ND/ND.nas - we started refactoring things so that the ND can be more easily implemented in other aircraft.

We are hoping to merge this upstream soon, so that Gijs can also continue his work to implement missing features, which would then be found in navdisplay.mfd (just a normal Nasal file, with a different extension).

Also, Philosopher is planning on coming up with an improved mapping abstraction for Nasal called MapStructure - so that's currently being worked on. In the meantime, you can definitely already use navdisplay.mfd - you really only need to:

  • add Hooray's fgdata clone/repo as a remote to your fgdata clone
  • check out the branch named "topics/nd-integration-wip"
  • and then have a look at the code in the 744 folder

To implement this in a new aircraft, like the 777, you only need to copy the ND.nas file to the 777 folder, rename the properties in the "myCockpit_switches" hash at the top of the file to match your own properties (range selector, mode selector etc) and everything should work directly.

That's the only thing you need to do right now. Gijs' changes will be in navdisplay.mfd and will be automatically available to you once they're committed/merged, no changes needed in ND.nas at all.

However, if you want to add new features to the navdisplay.mfd code, you need to open that file and map an SVG element to a callback routine - that's how everything is working currently.

There's a "configuration hash" called "NDStyles" at the top of the file. Each aircraft can have its own entry in NDStyles, such as NDStyles["B747-400"] or NavDisplay["777"]. Then, all the required canvas callbacks are listed there, i.e. the font mapper etc.

There's also an entry for a custom SVG filename. Lines 52-131 set up existing layers, which are now shared with the GUI code - so that is where new layers are added. Aircraft specific SVG elements are added at the end, after line 132

For now, I suggest to directly use the 744 ND - but the framework is now prepared to easily style & customize it for different aircraft, we will probably add a tutorial to the wiki to explain how things are hanging together there. The constructor and init methods may still need some work to generalize things there, because they are basically still Gijs' original code.

So to replace the 747 ND, these are the steps:

  • add a new entry to the NDStyles hash, for example "777-200"
  • you can simply copy the configuration stuff from the 747 to get started
  • start customizing things there
  • open the SVG file in inkscape and change it as required, save it
  • change the SVG filename in your NDStyles["777-200"] hash entry to match your own file name
  • provide animation callbacks for any 777 specific elements
  • open your own copy of ND.nas
  • change the constructor call .new() to specify the name of your new NDStyles entry
  • by default, this is 747-400 for the time being, for example:
var NDCpt = ND.new("instrumentation/efis", myCockpit_switches, "777-200" );

the "777-200" part needs to match the identifier used in the NDStyles hash.

To get started, just copy the whole 747-400 section in NDStyles and rename it to match your needs. Once that is working (getting a 744 ND via the 777-200 identifier), you can simply replace the SVG file name and add your own update handlers to incrementally come up with your own ND.

It would be also nice if you could prepare your cockpit to support two independent NDs, including displays and different switches - you can simply use a different location in the property tree, something like /instrumentation/efis[0] (captain) and /instrumentation/efis[1] (copilot).

that is something that I am missing in the 747, because I have now prepared the code to support multiple (many!) instances and it helps improving the code when generalizing it.

It's not important in the beginning, but just using different locations for the two sets of switches would help with this later on.

Each instance would then gets its own property branch for switches:

var NdCpt = ND.new("instrumentation/efis[0]", myCockpit_switches, "777-200");

var NDFo = ND.new("instrumentation/efis[1]", myCockpit_switches, "777-200");


##
# storage container for all ND instances 
var nd_display = {};

###
# entry point, this will set up all ND instances

setlistener("sim/signals/fdm-initialized", func() {

##
# configure aircraft specific cockpit/ND switches here
# these are to be found in the property branch you specify 
# via the NavDisplay.new() call
# the backend code in navdisplay.mfd should NEVER contain any aircraft-specific
# properties, or it will break other aircraft using different properties
# instead, make up an identifier (hash key) and map it to the property used 
# in your aircraft, relative to your ND root in the backend code, only ever 
# refer to the handle/key instead via the me.get_switch('toggle_range') method
# which would internally look up the matching aircraft property, e.g. '/instrumentation/efis'/inputs/range-nm'
#
# note: it is NOT sufficient to just add new switches here, the backend code in navdisplay.mfd also
# needs to know what to do with them !
# refer to incomplete symbol implementations to learn how they work (e.g. WXR, STA)

      var myCockpit_switches = {
	# symbolic alias : relative property (as used in bindings), initial value, type
	'toggle_range': 	{path: '/inputs/range', value:40, type:'INT'},
	'toggle_weather': 	{path: '/inputs/wxr', value:0, type:'BOOL'},
	'toggle_airports': 	{path: '/inputs/arpt', value:0, type:'BOOL'},
	'toggle_stations': 	{path: '/inputs/sta', value:0, type:'BOOL'},
	'toggle_waypoints': 	{path: '/inputs/wpt', value:0, type:'BOOL'},
	'toggle_position': 	{path: '/inputs/pos', value:0, type:'BOOL'},
	'toggle_data': 		{path: '/inputs/data',value:0, type:'BOOL'},
	'toggle_terrain': 	{path: '/inputs/terr',value:0, type:'BOOL'},
	'toggle_traffic': 	{path: '/inputs/tcas',value:0, type:'BOOL'},
	'toggle_display_mode': 	{path: '/mfd/display-mode', value:'MAP', type:'STRING'},
	# add new switches here
      };


	# get a handle to the NavDisplay in canvas namespace (for now), see $FG_ROOT/Nasal/canvas/map/navdisplay.mfd
	var ND = canvas.NavDisplay;

	## TODO: We want to support multiple independent ND instances here!
	# foreach(var pilot; var pilots = [ {name:'cpt', path:'instrumentation/efis',
	#				     name:'fo',  path:'instrumentation[1]/efis']) {


	##
	# set up a  new ND instance, under 'instrumentation/efis' and use the 
	# myCockpit_switches hash to map control properties
	var NDCpt = ND.new("instrumentation/efis", myCockpit_switches, "777");
	
	nd_display.cpt = canvas.new({
		"name": "ND",
		"size": [1024, 1024],
		"view": [1024, 1024],
		"mipmapping": 1
	});

	# TODO: rename the FO ND screen, and use separate button names for F/O side
	nd_display.cpt.addPlacement({"node": "ND.screen"});
	var group = nd_display.cpt.createGroup();
	NDCpt.newMFD(group);
	NDCpt.update();

		
}); # fdm-initialized listener callback


var showNd = func(pilot='cpt') {
	# The optional second arguments enables creating a window decoration
	var dlg = canvas.Window.new([400, 400], "dialog");
	dlg.setCanvas( nd_display[pilot] );
}