308
edits
(Added note about WIP status) |
(add class to permit multiple instances of an MFD) |
||
Line 4: | Line 4: | ||
== Introduction == | == Introduction == | ||
There is a simple implementation of the basic support for an MFD (or MPCD, or PFD), or any device that is basically a set of pages with buttons around the outside to select the page that is displayed. | There is a simple implementation of the basic support for an MFD (or MPCD, or PFD), or any device that is basically a set of pages with buttons around the outside to select the page that is displayed. | ||
Line 11: | Line 9: | ||
This works with a SVG file that defines the menu label locations and has a group for each page. The framework manages the menu hierarchy and displays labels corresponding to the buttons. | This works with a SVG file that defines the menu label locations and has a group for each page. The framework manages the menu hierarchy and displays labels corresponding to the buttons. | ||
This is based around the http://wiki.flightgear.org/McDonnell_Douglas_F-15_Eagle#MPCD | This is based around the SpaceShuttle dispalys which are in turn based on the http://wiki.flightgear.org/McDonnell_Douglas_F-15_Eagle#MPCD | ||
The code as below will allow multiple instances of a particular display to be created. Towards the end of the code an array is populated with one MFD_device instance per display. All use the same SVG and do the same job - but can be on different devices (left, right, etc) in the cockpit. The 3d model must have the frame, bezel and buttons for each display. The model_index selects which buttons to use. The buttons are named sim/model/f15/controls/PFD/button-pressed0 - where this property contains the index of the button, and there is one property per display. | |||
[[File:f-15-cockpit-mpcd-armament.jpg|300px|MCPD Armament Top Level Menu]] | [[File:f-15-cockpit-mpcd-armament.jpg|300px|MCPD Armament Top Level Menu]] | ||
Line 20: | Line 20: | ||
<syntaxhighlight lang="nasal"> | <syntaxhighlight lang="nasal"> | ||
# | var MFD_Device = | ||
# ------ | { | ||
# | |||
# create new MFD device. This is the main interface (from our code) to the MFD device | |||
# Each MFD device will contain the underlying PFD device object, the SVG, and the canvas | |||
var | # Parameters | ||
# - designation - Flightdeck Legend for this | |||
# - model_element - name of the 3d model element that is to be used for drawing | |||
# - model_index - index of the device | |||
new : func(designation, model_element, model_index=0) | |||
{ | |||
var obj = {parents : [MFD_Device] }; | |||
obj.designation = designation; | |||
obj.model_element = model_element; | |||
var dev_canvas= canvas.new({ | |||
"name": designation, | |||
"size": [1758,1884], | |||
"view": [512,512], | |||
"mipmapping": 1 | |||
}); | |||
dev_canvas.addPlacement({"node": model_element}); | |||
dev_canvas.setColorBackground(0,0,0, 0); | |||
# Create a group for the parsed elements | # Create a group for the parsed elements | ||
obj.PFDsvg = dev_canvas.createGroup(); | |||
var pres = canvas.parsesvg(obj.PFDsvg, "Nasal/PFD/PFD.svg"); | |||
# Parse an SVG file and add the parsed elements to the given group | # Parse an SVG file and add the parsed elements to the given group | ||
printf("MFD : %s Load SVG %s",designation,pres); | |||
obj.PFDsvg.setTranslation (20, 30); | |||
# | # | ||
# | # create the object that will control all of this | ||
obj.PFD = PFD_Device.new(obj.PFDsvg, num_menu_buttons, "MI_"); | |||
obj.PFD._canvas = dev_canvas; | |||
obj.PFD.primary = primary_port; | |||
obj.PFD.secondary = secondary_port; | |||
obj.PFD.port_selected = selected_port; | |||
obj.PFD.dps_page_flag = 0; | |||
obj.PFD.designation = designation; | |||
obj.mfd_device_status = 1; | |||
obj.model_index = model_index; # numeric index (1 to 9, left to right) used to connect the buttons in the cockpit to the display | |||
obj.addPages(); | |||
return obj; | |||
}, | |||
addPages : func | |||
{ | |||
me.me.page1_1 = MPCD.addPage("Aircraft Menu", "me.page1_1"); | |||
me.page1_1.update = func | |||
{ | |||
var sec = getprop("instrumentation/clock/indicated-sec"); | |||
me.page1_1.time.setText(getprop("sim/time/gmt-string")~"Z"); | |||
var cdt = getprop("sim/time/gmt"); | |||
if (cdt != nil) | |||
me.page1_1.date.setText(substr(cdt,5,2)~"/"~substr(cdt,8,2)~"/"~substr(cdt,2,2)~"Z"); | |||
}; | |||
# Connect the buttons - using the provided model index to get the right ones from the model binding | |||
setlistener("sim/model/f15/controls/PFD/button-pressed"~me.model_index, func(v) | |||
{ | |||
if (v != nil) | |||
{ | |||
if (v.getValue()) | |||
me.pfd_button_pushed = v.getValue(); | |||
else | |||
{ | |||
printf("%s: Button %d",me.designation, me.pfd_button_pushed); | |||
me.PFD.notifyButton(me.pfd_button_pushed); | |||
me.pfd_button_pushed = 0; | |||
} | |||
} | |||
}); | |||
# Set listener on the PFD mode button; this could be an on off switch or by convention | |||
# it will also act as brightness; so 0 is off and anything greater is brightness. | |||
# ranges are not pre-defined; it is probably sensible to use 0..10 as an brightness rather | |||
# than 0..1 as a floating value; but that's just my view. | |||
setlistener("sim/model/f15/controls/PFD/mode"~me.model_index, func(v) | |||
{ | |||
if (v != nil) | |||
{ | |||
me.mfd_device_status = v.getValue(); | |||
print("MFD Mode ",me.designation," ",me.mfd_device_status); | |||
if (!me.mfd_device_status) | |||
me.PFDsvg.setVisible(0); | |||
else | |||
me.PFDsvg.setVisible(1); | |||
} | |||
}); | |||
me.PFD.pfd_button_pushed = 0; | |||
me.setupMenus(); | |||
me.selectPage(p1_1); | |||
}, | |||
# Add the menus to each page. | |||
setupMenus : func | |||
{ | |||
me.page1_1.addMenuItem(0, "ARMT", p1_2); | |||
me.page1_1.addMenuItem(1, "BIT", p1_2); | |||
me.page1_1.addMenuItem(2, "SIT", pjitds_1); | |||
me.page1_1.addMenuItem(3, "WPN", p1_2); | |||
me.page1_1.addMenuItem(4, "DTM", p1_2); | |||
me.page1_1.date = MPCDsvg.getElementById("page1_1_date"); | |||
me.page1_1.time = MPCDsvg.getElementById("page1_1_time"); | |||
}, | |||
if ( | update : func | ||
{ | |||
if(me.mfd_device_status) | |||
me.PFD.update(); | |||
}, | |||
}; | }; | ||
# the PFD object really should be called an MFD - we attach the port connections to the IDPs and the selection | |||
var MFD_array = []; | |||
# | |||
# | |||
# Create and append all of the MFDs in the cockpit. | |||
# - MFD_Device.new( Identity, Canvas3dSurface, model index) | |||
# | |||
append(MFD_array, MFD_Device.new("MFD-1", "MPCDImage",0)); | |||
= | # update only one display per frame to reduce load. This can easily be changed | ||
# to update all by looping around all of the displays in the MFD_array | |||
var frame_device_update_id = 0; | |||
var MFD_rtExec_update = func | |||
{ | |||
if (frame_device_update_id >= size(MDU_array)) | |||
frame_device_update_id = 0; | |||
if (frame_device_update_id < size(MDU_array)) | |||
MDU_array[frame_device_update_id].update(); | |||
frame_device_update_id += 1; | |||
MFD_rtExec_timer.restart(0.02); | |||
} | } | ||
var MFD_rtExec_timer = maketimer(6, MFD_rtExec_update); | |||
MFD_rtExec_timer.restart(6); | |||
</syntaxhighlight> | </syntaxhighlight> | ||
edits