Merge branch 'master' of gitorious.org:fg/fgdata
This commit is contained in:
commit
7f574f500d
30 changed files with 2551 additions and 3012 deletions
|
@ -45,159 +45,159 @@ var FT2M = 0.3048;
|
||||||
var NM2KM = 1.852;
|
var NM2KM = 1.852;
|
||||||
|
|
||||||
var my_maxrange = func(a) {
|
var my_maxrange = func(a) {
|
||||||
max_range = 0;
|
max_range = 0;
|
||||||
radar_range = 0;
|
radar_range = 0;
|
||||||
radar_area = 0;
|
radar_area = 0;
|
||||||
acname = aircraftData[a] or 0;
|
acname = aircraftData[a] or 0;
|
||||||
if ( acname ) {
|
if ( acname ) {
|
||||||
have_radar = radarData[acname][4];
|
have_radar = radarData[acname][4];
|
||||||
if ( have_radar != "none" and have_radar != "unknown") {
|
if ( have_radar != "none" and have_radar != "unknown") {
|
||||||
radar_area = radarData[acname][7];
|
radar_area = radarData[acname][7];
|
||||||
radar_range = radarData[acname][5];
|
radar_range = radarData[acname][5];
|
||||||
if ( radar_area > 0 ) { max_range = radar_range / radar_area }
|
if ( radar_area > 0 ) { max_range = radar_range / radar_area }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return( max_range );
|
return( max_range );
|
||||||
}
|
}
|
||||||
|
|
||||||
var get_ecm_type_num = func(a) {
|
var get_ecm_type_num = func(a) {
|
||||||
acname = aircraftData[a] or 0;
|
acname = aircraftData[a] or 0;
|
||||||
var num = 0;
|
var num = 0;
|
||||||
if ( acname ) {
|
if ( acname ) {
|
||||||
num = radarData[acname][8];
|
num = radarData[acname][8];
|
||||||
}
|
}
|
||||||
return( num );
|
return( num );
|
||||||
}
|
}
|
||||||
|
|
||||||
var get_aircraft_name = func( t ) {
|
var get_aircraft_name = func( t ) {
|
||||||
# Get the multiplayer aircraft name.
|
# Get the multiplayer aircraft name.
|
||||||
mpnode_string = t;
|
mpnode_string = t;
|
||||||
mpnode = props.globals.getNode(mpnode_string);
|
mpnode = props.globals.getNode(mpnode_string);
|
||||||
if ( find("tanker", mpnode_string) > 0 ) {
|
if ( find("tanker", mpnode_string) > 0 ) {
|
||||||
cutname = "KC135";
|
cutname = "KC135";
|
||||||
} else {
|
} else {
|
||||||
mpname_node_string = mpnode_string ~ "/sim/model/path";
|
mpname_node_string = mpnode_string ~ "/sim/model/path";
|
||||||
mpname_node = props.globals.getNode(mpname_node_string);
|
mpname_node = props.globals.getNode(mpname_node_string);
|
||||||
if (mpname_node == nil) { return(0) }
|
if (mpname_node == nil) { return(0) }
|
||||||
|
|
||||||
var mpname = mpname_node.getValue();
|
var mpname = mpname_node.getValue();
|
||||||
if (mpname == nil) { return(0) }
|
if (mpname == nil) { return(0) }
|
||||||
|
|
||||||
splitname = split("/", mpname);
|
splitname = split("/", mpname);
|
||||||
cutname = splitname[1];
|
#
|
||||||
|
# cutname = splitname[1];
|
||||||
}
|
#
|
||||||
return( cutname );
|
# **** by 5H1N0B1 05/01/2014
|
||||||
|
# Fixed a problem onboard radar happens automatically when you are in range of an mp gamer that uses "OpenRadar"
|
||||||
|
#
|
||||||
|
cutname = splitname[size(splitname)-1];
|
||||||
|
|
||||||
|
}
|
||||||
|
return( cutname );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var radis = func(t, my_radarcorr) {
|
var radis = func(t, my_radarcorr) {
|
||||||
cutname = get_aircraft_name(t);
|
cutname = get_aircraft_name(t);
|
||||||
# Calculate the rcs detection range,
|
# Calculate the rcs detection range,
|
||||||
# if aircraft is not found in list, 0 (generic) will be used.
|
# if aircraft is not found in list, 0 (generic) will be used.
|
||||||
acname = aircraftData[cutname];
|
acname = aircraftData[cutname];
|
||||||
if ( acname == nil ) { acname = 0 }
|
if ( acname == nil ) { acname = 0 }
|
||||||
rcs_4r = radarData[acname][3];
|
rcs_4r = radarData[acname][3];
|
||||||
|
|
||||||
# Add a correction factor for altitude, as lower alt means
|
# Add a correction factor for altitude, as lower alt means
|
||||||
# shorter radar distance (due to air turbulence).
|
# shorter radar distance (due to air turbulence).
|
||||||
alt_corr = 1;
|
alt_corr = 1;
|
||||||
alt_ac = mpnode.getNode("position/altitude-ft").getValue();
|
alt_ac = mpnode.getNode("position/altitude-ft").getValue();
|
||||||
if (alt_ac <= 1000) {
|
if (alt_ac <= 1000) {
|
||||||
alt_corr = 0.6;
|
alt_corr = 0.6;
|
||||||
} elsif ((alt_ac > 1000) and (alt_ac <= 5000)) {
|
} elsif ((alt_ac > 1000) and (alt_ac <= 5000)) {
|
||||||
alt_corr = 0.8;
|
alt_corr = 0.8;
|
||||||
}
|
}
|
||||||
# Add a correction factor for altitude AGL. Skip if AI tanker.
|
# Add a correction factor for altitude AGL. Skip if AI tanker.
|
||||||
agl_corr = 1;
|
agl_corr = 1;
|
||||||
if ( find("tanker", t) == 0 ) {
|
if ( find("tanker", t) == 0 ) {
|
||||||
mp_lon = mpnode.getNode("position/longitude-deg").getValue();
|
mp_lon = mpnode.getNode("position/longitude-deg").getValue();
|
||||||
pos_elev = geo.elevation(mp_lat, mp_lon);
|
pos_elev = geo.elevation(mp_lat, mp_lon);
|
||||||
if (pos_elev != nil) {
|
if (pos_elev != nil) {
|
||||||
mp_agl = alt_ac - ( pos_elev / FT2M );
|
mp_agl = alt_ac - ( pos_elev / FT2M );
|
||||||
if (mp_agl <= 40) {
|
if (mp_agl <= 40) {
|
||||||
agl_corr = 0.03;
|
agl_corr = 0.03;
|
||||||
} elsif ((mp_agl > 40) and (mp_agl <= 80)) {
|
} elsif ((mp_agl > 40) and (mp_agl <= 80)) {
|
||||||
agl_corr = 0.07;
|
agl_corr = 0.07;
|
||||||
} elsif ((mp_agl > 80) and (mp_agl <= 120)) {
|
} elsif ((mp_agl > 80) and (mp_agl <= 120)) {
|
||||||
agl_corr = 0.25;
|
agl_corr = 0.25;
|
||||||
} elsif ((mp_agl > 120) and (mp_agl <= 300)) {
|
} elsif ((mp_agl > 120) and (mp_agl <= 300)) {
|
||||||
agl_corr = 0.4;
|
agl_corr = 0.4;
|
||||||
} elsif ((mp_agl > 300) and (mp_agl <= 600)) {
|
} elsif ((mp_agl > 300) and (mp_agl <= 600)) {
|
||||||
agl_corr = 0.7;
|
agl_corr = 0.7;
|
||||||
} elsif ((mp_agl > 600) and (mp_agl <= 1000)) {
|
} elsif ((mp_agl > 600) and (mp_agl <= 1000)) {
|
||||||
agl_corr = 0.85;
|
agl_corr = 0.85;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# Calculate the detection distance for this multiplayer.
|
# Calculate the detection distance for this multiplayer.
|
||||||
det_range = my_radarcorr * rcs_4r * alt_corr * agl_corr / NM2KM;
|
det_range = my_radarcorr * rcs_4r * alt_corr * agl_corr / NM2KM;
|
||||||
|
|
||||||
# Compare if aircraft is in detection range and return.
|
# Compare if aircraft is in detection range and return.
|
||||||
act_range = mpnode.getNode("radar/range-nm").getValue() or 500;
|
act_range = mpnode.getNode("radar/range-nm").getValue() or 500;
|
||||||
if (det_range >= act_range) {
|
if (det_range >= act_range) {
|
||||||
return(1);
|
return(1);
|
||||||
}
|
}
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
var radar_horizon = func(our_alt_ft, target_alt_ft) {
|
var radar_horizon = func(our_alt_ft, target_alt_ft) {
|
||||||
if (our_alt_ft < 0 or our_alt_ft == nil) { our_alt_ft = 0 }
|
if (our_alt_ft < 0 or our_alt_ft == nil) { our_alt_ft = 0 }
|
||||||
if (target_alt_ft < 0 or target_alt_ft == nil) { target_alt_ft = 0 }
|
if (target_alt_ft < 0 or target_alt_ft == nil) { target_alt_ft = 0 }
|
||||||
return( 2.2 * ( math.sqrt(our_alt_ft * FT2M) + math.sqrt(target_alt_ft * FT2M) ) );
|
return( 2.2 * ( math.sqrt(our_alt_ft * FT2M) + math.sqrt(target_alt_ft * FT2M) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var load_data = func {
|
var load_data = func {
|
||||||
# a) converts aircraft model name to lookup (index) number in aircraftData{}.
|
# a) converts aircraft model name to lookup (index) number in aircraftData{}.
|
||||||
# b) appends ordered list of data into radarData[],
|
# b) appends ordered list of data into radarData[],
|
||||||
# data is:
|
# data is:
|
||||||
# - acname (the index number)
|
# - acname (the index number)
|
||||||
# - the first (if several) aircraft model name corresponding to this type,
|
# - the first (if several) aircraft model name corresponding to this type,
|
||||||
# - RCS(m2),
|
# - RCS(m2),
|
||||||
# - 4th root of RCS,
|
# - 4th root of RCS,
|
||||||
# - radar type,
|
# - radar type,
|
||||||
# - max. radar range(km),
|
# - max. radar range(km),
|
||||||
# - max. radar range target seize(RCS)m2,
|
# - max. radar range target seize(RCS)m2,
|
||||||
# - 4th root of radar RCS.
|
# - 4th root of radar RCS.
|
||||||
var data_node = props.globals.getNode("instrumentation/radar-performance/data");
|
var data_node = props.globals.getNode("instrumentation/radar-performance/data");
|
||||||
var aircraft_types = data_node.getChildren();
|
var aircraft_types = data_node.getChildren();
|
||||||
foreach( var t; aircraft_types ) {
|
foreach( var t; aircraft_types ) {
|
||||||
var index = t.getIndex();
|
var index = t.getIndex();
|
||||||
var aircraft_names = t.getChildren();
|
var aircraft_names = t.getChildren();
|
||||||
foreach( var n; aircraft_names) {
|
foreach( var n; aircraft_names) {
|
||||||
if ( n.getName() == "name") {
|
if ( n.getName() == "name") {
|
||||||
aircraftData[n.getValue()] = index;
|
aircraftData[n.getValue()] = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var t_list = [
|
var t_list = [
|
||||||
index,
|
index,
|
||||||
t.getNode("name[0]").getValue(),
|
t.getNode("name[0]").getValue(),
|
||||||
t.getNode("rcs-sq-meter").getValue(),
|
t.getNode("rcs-sq-meter").getValue(),
|
||||||
t.getNode("rcs-4th-root").getValue(),
|
t.getNode("rcs-4th-root").getValue(),
|
||||||
t.getNode("radar-type").getValue(),
|
t.getNode("radar-type").getValue(),
|
||||||
t.getNode("max-radar-rng-km").getValue(),
|
t.getNode("max-radar-rng-km").getValue(),
|
||||||
t.getNode("max-target-sq-meter").getValue(),
|
t.getNode("max-target-sq-meter").getValue(),
|
||||||
t.getNode("max-target-4th-root").getValue(),
|
t.getNode("max-target-4th-root").getValue(),
|
||||||
t.getNode("ecm-type-num").getValue()
|
t.getNode("ecm-type-num").getValue()
|
||||||
];
|
];
|
||||||
append(radarData, t_list);
|
append(radarData, t_list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var launched = 0;
|
var launched = 0;
|
||||||
|
|
||||||
var init = func {
|
var init = func {
|
||||||
if (! launched) {
|
if (! launched) {
|
||||||
print("Initializing Radar Data");
|
print("Initializing Radar Data");
|
||||||
io.read_properties(data_path, props.globals);
|
io.read_properties(data_path, props.globals);
|
||||||
load_data();
|
load_data();
|
||||||
launched = 1;
|
launched = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,28 +1,36 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!--
|
<!--
|
||||||
************************************************************************
|
*******************************************************************************
|
||||||
Genius F-31U VIBRATION USB Joystick
|
Genius F-31U VIBRATION USB Joystick Configuration for Flightgear.
|
||||||
|
Version 2.
|
||||||
|
© 2011, 2014 Martin Měřinský, mermar@centrum.cz, GPLv2 or later.
|
||||||
|
|
||||||
Axes:
|
Axes:
|
||||||
0 - Aileron
|
0 - Aileron
|
||||||
1 - Elevator
|
1 - Elevator
|
||||||
2 - Rudder
|
2 - Rudder
|
||||||
3 - Throttle
|
3 - Throttle
|
||||||
4 - View left-right Hat
|
4 - View left/right hat
|
||||||
5 - View up-down Hat
|
5 - View up/down hat
|
||||||
|
|
||||||
Buttons:
|
Buttons:
|
||||||
0 - Brakes
|
0 - Fire primary and secondary weapon (armament trigger).
|
||||||
1 - Cycle view
|
1 - Cycle view
|
||||||
2 - Elevator trim up
|
2 - Elevator trim up
|
||||||
3 - Elevator trim down
|
3 - Elevator trim down
|
||||||
4 - Flaps down
|
4 - Flaps up
|
||||||
5 - Flaps up
|
5 - Mixture richer
|
||||||
6 - Brakes
|
6 - Brakes
|
||||||
7 - Mixture richer
|
7 - Flaps down
|
||||||
8 - Mixture leaner
|
8 - Mixture leaner
|
||||||
9 - Landing Gear Toggle
|
9 - Landing gear toggle
|
||||||
************************************************************************
|
|
||||||
|
Known issues:
|
||||||
|
Flightgear cannot invert left/right "lookat" view, so this is done using Nasal
|
||||||
|
and thus it works when Flightgear is paused, unlike view elevation (up/down).
|
||||||
|
|
||||||
|
In Windows up and down view is inverted.
|
||||||
|
*******************************************************************************
|
||||||
-->
|
-->
|
||||||
<PropertyList>
|
<PropertyList>
|
||||||
<name type="string">Padix Co. Ltd. 10-Button USB Joystick</name> <!-- GNU/Linux. -->
|
<name type="string">Padix Co. Ltd. 10-Button USB Joystick</name> <!-- GNU/Linux. -->
|
||||||
|
@ -44,7 +52,7 @@ Buttons:
|
||||||
<command>property-scale</command>
|
<command>property-scale</command>
|
||||||
<property>/controls/flight/elevator</property>
|
<property>/controls/flight/elevator</property>
|
||||||
<power type="int">2</power>
|
<power type="int">2</power>
|
||||||
<factor type="double">-1.0</factor> <!-- Reverse axis. -->
|
<factor type="double">-1.0</factor> <!-- Reverse axis. -->
|
||||||
</binding>
|
</binding>
|
||||||
</axis>
|
</axis>
|
||||||
|
|
||||||
|
@ -58,7 +66,7 @@ Buttons:
|
||||||
<command>property-scale</command>
|
<command>property-scale</command>
|
||||||
<property>/controls/flight/rudder</property>
|
<property>/controls/flight/rudder</property>
|
||||||
<power type="int">2</power>
|
<power type="int">2</power>
|
||||||
<factor type="double">-1.0</factor> <!-- Reverse axis. -->
|
<factor type="double">-1.0</factor> <!-- Reverse axis. -->
|
||||||
</binding>
|
</binding>
|
||||||
</axis>
|
</axis>
|
||||||
|
|
||||||
|
@ -75,7 +83,7 @@ Buttons:
|
||||||
</axis>
|
</axis>
|
||||||
|
|
||||||
<axis>
|
<axis>
|
||||||
<desc>View Direction</desc>
|
<desc>View direction</desc>
|
||||||
<number>
|
<number>
|
||||||
<unix>4</unix>
|
<unix>4</unix>
|
||||||
<windows>6</windows>
|
<windows>6</windows>
|
||||||
|
@ -85,7 +93,7 @@ Buttons:
|
||||||
<repeatable>true</repeatable>
|
<repeatable>true</repeatable>
|
||||||
<binding>
|
<binding>
|
||||||
<!--
|
<!--
|
||||||
This also works, but LookAt views has inverted left/right.
|
This also works, but LookAt views have inverted left/right.
|
||||||
<command>property-adjust</command>
|
<command>property-adjust</command>
|
||||||
<property>/sim/current-view/goal-heading-offset-deg</property>
|
<property>/sim/current-view/goal-heading-offset-deg</property>
|
||||||
<step type="double">3.0</step>
|
<step type="double">3.0</step>
|
||||||
|
@ -106,7 +114,7 @@ Buttons:
|
||||||
<repeatable>true</repeatable>
|
<repeatable>true</repeatable>
|
||||||
<binding>
|
<binding>
|
||||||
<!--
|
<!--
|
||||||
This also works, but LookAt views has inverted left/right.
|
This also works, but LookAt views have inverted left/right.
|
||||||
<command>property-adjust</command>
|
<command>property-adjust</command>
|
||||||
<property>/sim/current-view/goal-heading-offset-deg</property>
|
<property>/sim/current-view/goal-heading-offset-deg</property>
|
||||||
<step type="double">-3.0</step>
|
<step type="double">-3.0</step>
|
||||||
|
@ -125,7 +133,7 @@ Buttons:
|
||||||
</axis>
|
</axis>
|
||||||
|
|
||||||
<axis>
|
<axis>
|
||||||
<desc>View Elevation</desc>
|
<desc>View elevation</desc>
|
||||||
<number>
|
<number>
|
||||||
<unix>5</unix>
|
<unix>5</unix>
|
||||||
<windows>7</windows>
|
<windows>7</windows>
|
||||||
|
@ -136,7 +144,7 @@ Buttons:
|
||||||
<binding>
|
<binding>
|
||||||
<command>property-adjust</command>
|
<command>property-adjust</command>
|
||||||
<property>/sim/current-view/goal-pitch-offset-deg</property>
|
<property>/sim/current-view/goal-pitch-offset-deg</property>
|
||||||
<step type="double">3.0</step> <!-- Use -3.0 for Windows. -->
|
<step type="double">3.0</step>
|
||||||
</binding>
|
</binding>
|
||||||
</low>
|
</low>
|
||||||
<high>
|
<high>
|
||||||
|
@ -145,28 +153,37 @@ Buttons:
|
||||||
<binding>
|
<binding>
|
||||||
<command>property-adjust</command>
|
<command>property-adjust</command>
|
||||||
<property>/sim/current-view/goal-pitch-offset-deg</property>
|
<property>/sim/current-view/goal-pitch-offset-deg</property>
|
||||||
<step type="double">-3.0</step> <!-- Use 3.0 for Windows. -->
|
<step type="double">-3.0</step>
|
||||||
</binding>
|
</binding>
|
||||||
</high>
|
</high>
|
||||||
</axis>
|
</axis>
|
||||||
|
|
||||||
|
|
||||||
<button n="0">
|
<button n="0">
|
||||||
<desc>Brakes</desc>
|
<desc>Fire</desc>
|
||||||
<binding>
|
<binding>
|
||||||
<command>nasal</command>
|
<command>nasal</command>
|
||||||
<script>controls.applyBrakes(1)</script>
|
<script>
|
||||||
|
setprop("/controls/armament/trigger", 1);
|
||||||
|
setprop("ai/submodels/trigger", 1);
|
||||||
|
setprop("/controls/armament/trigger1", 1);
|
||||||
|
setprop("ai/submodels/trigger1", 1);
|
||||||
|
</script>
|
||||||
</binding>
|
</binding>
|
||||||
<mod-up>
|
<mod-up>
|
||||||
<binding>
|
<binding>
|
||||||
<command>nasal</command>
|
<command>nasal</command>
|
||||||
<script>controls.applyBrakes(0)</script>
|
<script>
|
||||||
|
setprop("/controls/armament/trigger", 0);
|
||||||
|
setprop("ai/submodels/trigger", 0);
|
||||||
|
setprop("/controls/armament/trigger1", 0);
|
||||||
|
setprop("ai/submodels/trigger1", 0);
|
||||||
|
</script>
|
||||||
</binding>
|
</binding>
|
||||||
</mod-up>
|
</mod-up>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button n="1">
|
<button n="1">
|
||||||
<desc>Cycle View</desc>
|
<desc>View cycle</desc>
|
||||||
<repeatable>false</repeatable>
|
<repeatable>false</repeatable>
|
||||||
<binding>
|
<binding>
|
||||||
<command>nasal</command>
|
<command>nasal</command>
|
||||||
|
@ -196,20 +213,6 @@ Buttons:
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button n="4">
|
<button n="4">
|
||||||
<desc>Flaps down</desc>
|
|
||||||
<binding>
|
|
||||||
<command>nasal</command>
|
|
||||||
<script>controls.flapsDown(1)</script>
|
|
||||||
</binding>
|
|
||||||
<mod-up>
|
|
||||||
<binding>
|
|
||||||
<command>nasal</command>
|
|
||||||
<script>controls.flapsDown(0)</script>
|
|
||||||
</binding>
|
|
||||||
</mod-up>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button n="5">
|
|
||||||
<desc>Flaps up</desc>
|
<desc>Flaps up</desc>
|
||||||
<repeatable>false</repeatable>
|
<repeatable>false</repeatable>
|
||||||
<binding>
|
<binding>
|
||||||
|
@ -224,6 +227,15 @@ Buttons:
|
||||||
</mod-up>
|
</mod-up>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<button n="5">
|
||||||
|
<desc>Mixture richer</desc>
|
||||||
|
<repeatable>true</repeatable>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>controls.adjMixture(1)</script>
|
||||||
|
</binding>
|
||||||
|
</button>
|
||||||
|
|
||||||
<button n="6">
|
<button n="6">
|
||||||
<desc>Brakes</desc>
|
<desc>Brakes</desc>
|
||||||
<binding>
|
<binding>
|
||||||
|
@ -239,12 +251,17 @@ Buttons:
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button n="7">
|
<button n="7">
|
||||||
<desc>Mixture richer</desc>
|
<desc>Flaps down</desc>
|
||||||
<repeatable>true</repeatable>
|
|
||||||
<binding>
|
<binding>
|
||||||
<command>nasal</command>
|
<command>nasal</command>
|
||||||
<script>controls.adjMixture(1)</script>
|
<script>controls.flapsDown(1)</script>
|
||||||
</binding>
|
</binding>
|
||||||
|
<mod-up>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>controls.flapsDown(0)</script>
|
||||||
|
</binding>
|
||||||
|
</mod-up>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button n="8">
|
<button n="8">
|
||||||
|
@ -266,3 +283,4 @@ Buttons:
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
</PropertyList>
|
</PropertyList>
|
||||||
|
|
||||||
|
|
661
Input/Joysticks/Logitech/g940.xml
Normal file
661
Input/Joysticks/Logitech/g940.xml
Normal file
|
@ -0,0 +1,661 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
Logitech, Inc. Flight System G940 configuration for Flightgear.
|
||||||
|
Version 2.
|
||||||
|
© 2011, 2013, 2014 Martin Měřinský, mermar@centrum.cz, GPLv2 or later.
|
||||||
|
|
||||||
|
Axes:
|
||||||
|
0 - Stick left/right - Aileron
|
||||||
|
1 - Stick forward/backward - Elevator
|
||||||
|
2 - Pedals rudder - Rudder
|
||||||
|
3 - Pedal right break - Right differential break
|
||||||
|
4 - Pedal left break - Left differential break
|
||||||
|
5 - TRIM3 - Aileron trim
|
||||||
|
6 - Trohttle right - Throttle right engine
|
||||||
|
7 - Throttle left - Throttle left engine
|
||||||
|
8 - R1 - Mixture
|
||||||
|
9 - R2 - Propeller pitch
|
||||||
|
10 - Stick upper hat left/right -
|
||||||
|
11 - Stick upper hat up/down -
|
||||||
|
12 - Stick lower hat left/right - View direction
|
||||||
|
13 - Stick lower hat up/down - View elevation
|
||||||
|
14 - Throttle lower hat left/right - View zoom in/out
|
||||||
|
15 - Throttle lower hat up/down - Reset zoom to default/for greater overview
|
||||||
|
16 - Throttle upper hat left/right -
|
||||||
|
17 - Throttle upper hat up/down -
|
||||||
|
|
||||||
|
Buttons:
|
||||||
|
0 - S0 - Fire primary weapon
|
||||||
|
1 - FIRE - Fire secondary weapon and smoke on/off toggle
|
||||||
|
2 - S1 - Drop bombs
|
||||||
|
3 - S2 - Master arm toggle (cycle through modes)
|
||||||
|
4 - S3 - Flare release
|
||||||
|
5 - S4 - View cycle
|
||||||
|
6 - S5 - Smoke
|
||||||
|
7 - Stick upper hat push -
|
||||||
|
8 - S0 second position - Fire primary and secondary weapon and smoke on/off toggle
|
||||||
|
9 - T1 - Flaps up
|
||||||
|
10 - T2 - Flaps down
|
||||||
|
11 - T3 - Airbrake toggle
|
||||||
|
12 - T4 - Reverse thrust toggle
|
||||||
|
13 - P1 - Tailhook up/down toggle
|
||||||
|
14 - P2 - Floats up/down toggle
|
||||||
|
15 - P3 - External fuel tanks jettison
|
||||||
|
16 - P4 - Wing fold or oversweep toggle
|
||||||
|
17 - P5 - Landing gear up/down toggle
|
||||||
|
18 - P6 - Watter rudder up/down toggle
|
||||||
|
19 - P7 - Landing drag parachute reapack/deploy/jettison
|
||||||
|
20 - P8 - Refueling probe toggle
|
||||||
|
|
||||||
|
Known issues:
|
||||||
|
TRIM1, TRIM2, MODE, axis 16 and 17 do not work in GNU/Linux
|
||||||
|
(js-demo nor Flightgear).
|
||||||
|
|
||||||
|
Flightgear does not allow you to control "left" and "right" engines if you have
|
||||||
|
even number of engines and all engines if you have odd number of engines.
|
||||||
|
This config file controls all engines at once, although you have two hardware
|
||||||
|
axis. With simple editing, you can control throttle of engines 0 and 1.
|
||||||
|
|
||||||
|
Properties for plane features in Flightgear are not standardized. So the same
|
||||||
|
thing is done using different properties on different planes and you may see
|
||||||
|
errors "undefined symbol" in console. Eg.:
|
||||||
|
Nasal runtime error: undefined symbol: f14
|
||||||
|
at /input/joysticks/js/button[20]/binding, line 1
|
||||||
|
|
||||||
|
Flightgear cannot invert left/right "lookat" view, so this is done using Nasal
|
||||||
|
and thus it works when Flightgear is paused, unlike view elevation (up/down).
|
||||||
|
-->
|
||||||
|
<PropertyList>
|
||||||
|
|
||||||
|
<name type="string">G940</name> <!-- GNU/Linux. -->
|
||||||
|
|
||||||
|
<!-- Stick ************************************************************ -->
|
||||||
|
|
||||||
|
<axis n="0">
|
||||||
|
<desc>Aileron</desc>
|
||||||
|
<binding>
|
||||||
|
<command>property-scale</command>
|
||||||
|
<property>/controls/flight/aileron</property>
|
||||||
|
</binding>
|
||||||
|
</axis>
|
||||||
|
|
||||||
|
<axis n="1">
|
||||||
|
<desc>Elevator</desc>
|
||||||
|
<binding>
|
||||||
|
<command>property-scale</command>
|
||||||
|
<property>/controls/flight/elevator</property>
|
||||||
|
<factor type="double">-1.0</factor> <!-- Reverse axis. -->
|
||||||
|
</binding>
|
||||||
|
</axis>
|
||||||
|
|
||||||
|
<axis n="5">
|
||||||
|
<desc>Aileron trim</desc>
|
||||||
|
<binding>
|
||||||
|
<command>property-scale</command>
|
||||||
|
<property>/controls/flight/aileron-trim</property>
|
||||||
|
</binding>
|
||||||
|
</axis>
|
||||||
|
|
||||||
|
<button n="5">
|
||||||
|
<desc>View cycle</desc>
|
||||||
|
<repeatable>false</repeatable>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
view.stepView(1);
|
||||||
|
#gui.popupTip(sprintf("View index: %d, view type: %s", getprop("sim/current-view/view-number"), getprop("/sim/current-view/type")));
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<axis>
|
||||||
|
<desc>View direction</desc>
|
||||||
|
<number>
|
||||||
|
<unix>12</unix>
|
||||||
|
</number>
|
||||||
|
<low>
|
||||||
|
<desc>View left</desc>
|
||||||
|
<repeatable>true</repeatable>
|
||||||
|
<binding>
|
||||||
|
<!--
|
||||||
|
This also works, but LookAt views have inverted left/right.
|
||||||
|
<command>property-adjust</command>
|
||||||
|
<property>/sim/current-view/goal-heading-offset-deg</property>
|
||||||
|
<step type="double">3.0</step>
|
||||||
|
-->
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
var valueDelta = -3.0;
|
||||||
|
if (getprop("/sim/current-view/type") == "lookat")
|
||||||
|
{
|
||||||
|
valueDelta = 3.0;
|
||||||
|
}
|
||||||
|
setprop("/sim/current-view/heading-offset-deg", getprop("/sim/current-view/heading-offset-deg") - valueDelta);
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
</low>
|
||||||
|
<high>
|
||||||
|
<desc>View right</desc>
|
||||||
|
<repeatable>true</repeatable>
|
||||||
|
<binding>
|
||||||
|
<!--
|
||||||
|
This also works, but LookAt views have inverted left/right.
|
||||||
|
<command>property-adjust</command>
|
||||||
|
<property>/sim/current-view/goal-heading-offset-deg</property>
|
||||||
|
<step type="double">-3.0</step>
|
||||||
|
-->
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
var valueDelta = -3.0;
|
||||||
|
if (getprop("/sim/current-view/type") == "lookat")
|
||||||
|
{
|
||||||
|
valueDelta = 3.0;
|
||||||
|
}
|
||||||
|
setprop("/sim/current-view/heading-offset-deg", getprop("/sim/current-view/heading-offset-deg") + valueDelta);
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
</high>
|
||||||
|
</axis>
|
||||||
|
|
||||||
|
<axis>
|
||||||
|
<desc>View elevation</desc>
|
||||||
|
<number>
|
||||||
|
<unix>13</unix>
|
||||||
|
</number>
|
||||||
|
<low>
|
||||||
|
<desc>View down</desc>
|
||||||
|
<repeatable>true</repeatable>
|
||||||
|
<binding>
|
||||||
|
<command>property-adjust</command>
|
||||||
|
<property>/sim/current-view/goal-pitch-offset-deg</property>
|
||||||
|
<step type="double">3.0</step>
|
||||||
|
</binding>
|
||||||
|
</low>
|
||||||
|
<high>
|
||||||
|
<desc>View up</desc>
|
||||||
|
<repeatable>true</repeatable>
|
||||||
|
<binding>
|
||||||
|
<command>property-adjust</command>
|
||||||
|
<property>/sim/current-view/goal-pitch-offset-deg</property>
|
||||||
|
<step type="double">-3.0</step>
|
||||||
|
</binding>
|
||||||
|
</high>
|
||||||
|
</axis>
|
||||||
|
|
||||||
|
<button n="0">
|
||||||
|
<desc>Fire primary weapon</desc>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
setprop("/controls/armament/trigger", 1);
|
||||||
|
setprop("ai/submodels/trigger", 1);
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
<mod-up>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
setprop("/controls/armament/trigger", 0);
|
||||||
|
setprop("ai/submodels/trigger", 0);
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
</mod-up>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button n="1">
|
||||||
|
<desc>Fire secondary weapon</desc>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
setprop("/controls/armament/trigger1", 1);
|
||||||
|
setprop("ai/submodels/trigger1", 1);
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
<mod-up>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
setprop("/controls/armament/trigger1", 0);
|
||||||
|
setprop("ai/submodels/trigger1", 0);
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
</mod-up>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button n="2">
|
||||||
|
<desc>Drop bombs</desc>
|
||||||
|
<repeatable>false</repeatable>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
setprop("ai/submodels/red-beard-released", 1);
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button n="3">
|
||||||
|
<desc>Master arm toggle (cycle through modes)</desc>
|
||||||
|
<repeatable>false</repeatable>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
f14.master_arm_cycle();
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button n="4">
|
||||||
|
<desc>Flare release</desc>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
setprop("ai/submodels/submodel[0]/flare-release", 1);
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
<mod-up>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
setprop("ai/submodels/submodel[0]/flare-release", 0);
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
</mod-up>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button n="6">
|
||||||
|
<desc>Smoke on/off toggle</desc>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
# Smoke toggle z50lx.
|
||||||
|
if (getprop("/controls/smoke") == 1)
|
||||||
|
smokeNextState = 0;
|
||||||
|
else
|
||||||
|
smokeNextState = 1;
|
||||||
|
setprop("/controls/smoke", smokeNextState);
|
||||||
|
|
||||||
|
# Smoke toggle Su-26M2.
|
||||||
|
if (getprop("/control/smoke") == 1)
|
||||||
|
smokeNextState = 0;
|
||||||
|
else
|
||||||
|
smokeNextState = 1;
|
||||||
|
setprop("/control/smoke", smokeNextState);
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button n="8">
|
||||||
|
<desc>Fire primary and secondary weapon and smoke on/off toggle</desc>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
setprop("/controls/armament/trigger", 1);
|
||||||
|
setprop("ai/submodels/trigger", 1);
|
||||||
|
setprop("/controls/armament/trigger1", 1);
|
||||||
|
setprop("ai/submodels/trigger1", 1);
|
||||||
|
# Also smoke toggle.
|
||||||
|
if (getprop("/controls/smoke") == 1)
|
||||||
|
smokeNextState = 0;
|
||||||
|
else
|
||||||
|
smokeNextState = 1;
|
||||||
|
setprop("/controls/smoke", smokeNextState);
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
<mod-up>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
setprop("/controls/armament/trigger", 0);
|
||||||
|
setprop("ai/submodels/trigger", 0);
|
||||||
|
setprop("/controls/armament/trigger1", 0);
|
||||||
|
setprop("ai/submodels/trigger1", 0);
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
</mod-up>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Throttle ********************************************************* -->
|
||||||
|
|
||||||
|
<axis>
|
||||||
|
<desc>Throttle right engine</desc>
|
||||||
|
<number>
|
||||||
|
<unix>6</unix>
|
||||||
|
</number>
|
||||||
|
<binding>
|
||||||
|
<!-- If you want to control left and right engine, use this.
|
||||||
|
<command>property-scale</command>
|
||||||
|
<property>/controls/engines/engine[1]/throttle</property>
|
||||||
|
<offset type="double">-1.0</offset>
|
||||||
|
<factor type="double">-0.5</factor>
|
||||||
|
-->
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>controls.throttleAxis()</script>
|
||||||
|
|
||||||
|
|
||||||
|
</binding>
|
||||||
|
</axis>
|
||||||
|
|
||||||
|
<axis>
|
||||||
|
<desc>Throttle left engine</desc>
|
||||||
|
<number>
|
||||||
|
<unix>7</unix>
|
||||||
|
</number>
|
||||||
|
<binding>
|
||||||
|
<command>property-scale</command>
|
||||||
|
<property>/controls/engines/engine[0]/throttle</property>
|
||||||
|
<offset type="double">-1.0</offset>
|
||||||
|
<factor type="double">-0.5</factor>
|
||||||
|
</binding>
|
||||||
|
</axis>
|
||||||
|
|
||||||
|
<axis>
|
||||||
|
<desc>Mixture</desc>
|
||||||
|
<number>
|
||||||
|
<unix>9</unix>
|
||||||
|
</number>
|
||||||
|
<binding>
|
||||||
|
<command>property-scale</command>
|
||||||
|
<property>/controls/engines/engine/mixture</property>
|
||||||
|
<offset type="double">-1.0</offset>
|
||||||
|
<factor type="double">-0.5</factor>
|
||||||
|
</binding>
|
||||||
|
</axis>
|
||||||
|
|
||||||
|
<axis>
|
||||||
|
<desc>Propeller pitch</desc>
|
||||||
|
<number>
|
||||||
|
<unix>8</unix>
|
||||||
|
</number>
|
||||||
|
<binding>
|
||||||
|
<command>property-scale</command>
|
||||||
|
<property>/controls/engines/engine/propeller-pitch</property>
|
||||||
|
<offset type="double">-1.0</offset>
|
||||||
|
<factor type="double">-0.5</factor>
|
||||||
|
</binding>
|
||||||
|
</axis>
|
||||||
|
|
||||||
|
<axis>
|
||||||
|
<desc>View zoom</desc>
|
||||||
|
<number>
|
||||||
|
<unix>14</unix>
|
||||||
|
</number>
|
||||||
|
<low>
|
||||||
|
<desc>Zoom out</desc>
|
||||||
|
<repeatable>true</repeatable>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
view.increase();
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
</low>
|
||||||
|
<high>
|
||||||
|
<desc>Zoom in</desc>
|
||||||
|
<repeatable>true</repeatable>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>view.decrease()</script>
|
||||||
|
</binding>
|
||||||
|
</high>
|
||||||
|
</axis>
|
||||||
|
|
||||||
|
<axis>
|
||||||
|
<desc>Reset zoom</desc>
|
||||||
|
<number>
|
||||||
|
<unix>15</unix>
|
||||||
|
</number>
|
||||||
|
<low>
|
||||||
|
<desc>Reset zoom to default</desc>
|
||||||
|
<repeatable>false</repeatable>
|
||||||
|
<binding>
|
||||||
|
<command>property-assign</command>
|
||||||
|
<property>/sim/current-view/field-of-view</property>
|
||||||
|
<property>/sim/view/config/default-field-of-view-deg</property>
|
||||||
|
</binding>
|
||||||
|
</low>
|
||||||
|
<high>
|
||||||
|
<desc>Reset zoom for greater overview</desc>
|
||||||
|
<repeatable>false</repeatable>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
setprop("/sim/current-view/field-of-view", 100);
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
</high>
|
||||||
|
</axis>
|
||||||
|
|
||||||
|
<button n="9">
|
||||||
|
<desc>Flaps up</desc>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>controls.flapsDown(-1)</script>
|
||||||
|
</binding>
|
||||||
|
<mod-up>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>controls.flapsDown(0)</script>
|
||||||
|
</binding>
|
||||||
|
</mod-up>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button n="10">
|
||||||
|
<desc>Flaps down</desc>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>controls.flapsDown(1)</script>
|
||||||
|
</binding>
|
||||||
|
<mod-up>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>controls.flapsDown(0)</script>
|
||||||
|
</binding>
|
||||||
|
</mod-up>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button n="11">
|
||||||
|
<desc>Airbrake toggle</desc>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
if (getprop("/controls/flight/speedbrake") == 1)
|
||||||
|
speedbrakeNextState = 0;
|
||||||
|
else
|
||||||
|
speedbrakeNextState = 1;
|
||||||
|
setprop("/controls/flight/speedbrake", speedbrakeNextState);
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button n="12">
|
||||||
|
<desc>Reverse thrust toggle</desc>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
reverserNextState = !getprop("/controls/engines/engine[0]/reverser");
|
||||||
|
props.setAll("/controls/engines/engine", "reverser", reverserNextState);
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button n="13">
|
||||||
|
<desc>Landing tailhook toggle</desc>
|
||||||
|
<repeatable>false</repeatable>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
if (getprop("/controls/gear/tailhook") == 1)
|
||||||
|
hookNextState = 0;
|
||||||
|
else
|
||||||
|
hookNextState = 1;
|
||||||
|
setprop("/controls/gear/tailhook", hookNextState); # F-14b
|
||||||
|
setprop("fdm/jsbsim/systems/hook/tailhook-cmd-norm", hookNextState); # F-16
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button n="14">
|
||||||
|
<desc>Floats up/down toggle</desc>
|
||||||
|
<repeatable>false</repeatable>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
if (getprop("/controls/gear/float-down") == 1)
|
||||||
|
floatNextState = 0;
|
||||||
|
else
|
||||||
|
floatNextState = 1;
|
||||||
|
setprop("/controls/gear/float-down", floatNextState);
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button n="15">
|
||||||
|
<desc>External fuel tanks jettison</desc>
|
||||||
|
<repeatable>false</repeatable>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
# Lightning.
|
||||||
|
setprop("/sim/model/lightning/controls/tank_jettisoned", 1);
|
||||||
|
# F-14b
|
||||||
|
#setprop("/sim/model/f-14b/systems/external-loads/external-tanks", 0);
|
||||||
|
f14.toggle_ext_tank_selected();
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button n="16">
|
||||||
|
<desc>Wing fold or oversweep toggle</desc>
|
||||||
|
<repeatable>false</repeatable>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
f14.toggleOversweep();
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button n="17">
|
||||||
|
<desc>Landing gear toggle</desc>
|
||||||
|
<repeatable>false</repeatable>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>controls.gearToggle()</script>
|
||||||
|
</binding>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button n="18">
|
||||||
|
<desc>Watter ruder toggle</desc>
|
||||||
|
<repeatable>false</repeatable>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
if (getprop("/controls/gear/water-rudder-down") == 1)
|
||||||
|
waterRudderNextState = 0;
|
||||||
|
else
|
||||||
|
waterRudderNextState = 1;
|
||||||
|
interpolate("/controls/gear/water-rudder-down", waterRudderNextState, 2.5);
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button n="19">
|
||||||
|
<desc>Drag parachute repack - deploy - jettison</desc>
|
||||||
|
<repeatable>false</repeatable>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>
|
||||||
|
# Chute states:
|
||||||
|
# 0 ... repacked
|
||||||
|
# 1 ... deployed
|
||||||
|
# 2 ... jettisoned
|
||||||
|
if (chuteState == 0)
|
||||||
|
{
|
||||||
|
print("Command to chute (prepare for automatic or) deployment.");
|
||||||
|
# F-117, prepare for automatic deployment.
|
||||||
|
setprop("/sim/model/controls/chute", 1);
|
||||||
|
# Lightning.
|
||||||
|
setprop("sim/model/lightning/controls/flight/chute_open", 1);
|
||||||
|
setprop("sim/model/lightning/controls/flight/chute_deployed", 1);
|
||||||
|
setprop("sim/model/lightning/controls/flight/chute_jettisoned", 0);
|
||||||
|
chuteState = 1;
|
||||||
|
}
|
||||||
|
else if (chuteState == 1)
|
||||||
|
{
|
||||||
|
print("Command to chute jettison.");
|
||||||
|
# F-117, jettsion is automatic.
|
||||||
|
setprop("/sim/model/controls/chute", 0);
|
||||||
|
setprop("/sim/model/controls/chute-available", 0);
|
||||||
|
# Lightning.
|
||||||
|
setprop("sim/model/lightning/controls/flight/chute_open", 1);
|
||||||
|
setprop("sim/model/lightning/controls/flight/chute_deployed", 1);
|
||||||
|
setprop("sim/model/lightning/controls/flight/chute_jettisoned", 1);
|
||||||
|
chuteState = 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
print("Command to repack chute.");
|
||||||
|
# F-117.
|
||||||
|
setprop("/sim/model/controls/chute", 0);
|
||||||
|
setprop("/sim/model/controls/chute-available", 0);
|
||||||
|
# Lightning.
|
||||||
|
setprop("sim/model/lightning/controls/flight/chute_open", 0);
|
||||||
|
setprop("sim/model/lightning/controls/flight/chute_deployed", 0);
|
||||||
|
setprop("sim/model/lightning/controls/flight/chute_jettisoned", 0);
|
||||||
|
chuteState = 0;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</binding>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button n="20">
|
||||||
|
<desc>Refueling probe toggle</desc>
|
||||||
|
<repeatable>false</repeatable>
|
||||||
|
<binding>
|
||||||
|
<command>nasal</command>
|
||||||
|
<script>f14.refuel_probe_switch_cycle();</script>
|
||||||
|
</binding>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Pedals *********************************************************** -->
|
||||||
|
|
||||||
|
<axis>
|
||||||
|
<desc>Rudder</desc>
|
||||||
|
<number>
|
||||||
|
<unix>2</unix>
|
||||||
|
</number>
|
||||||
|
<binding>
|
||||||
|
<command>property-scale</command>
|
||||||
|
<property>/controls/flight/rudder</property>
|
||||||
|
<power type="int">2</power>
|
||||||
|
</binding>
|
||||||
|
</axis>
|
||||||
|
|
||||||
|
<axis>
|
||||||
|
<number>
|
||||||
|
<unix>4</unix>
|
||||||
|
</number>
|
||||||
|
<desc>Left differential break</desc>
|
||||||
|
<binding>
|
||||||
|
<command>property-scale</command>
|
||||||
|
<property>/controls/gear/brake-left</property>
|
||||||
|
<offset>-1.0</offset>
|
||||||
|
<factor>-0.5</factor>
|
||||||
|
</binding>
|
||||||
|
</axis>
|
||||||
|
|
||||||
|
<axis>
|
||||||
|
<number>
|
||||||
|
<unix>3</unix>
|
||||||
|
</number>
|
||||||
|
<desc>Right differential break</desc>
|
||||||
|
<binding>
|
||||||
|
<command>property-scale</command>
|
||||||
|
<property>/controls/gear/brake-right</property>
|
||||||
|
<offset>-1.0</offset>
|
||||||
|
<factor>-0.5</factor>
|
||||||
|
</binding>
|
||||||
|
</axis>
|
||||||
|
|
||||||
|
</PropertyList>
|
||||||
|
|
|
@ -1,3 +1,123 @@
|
||||||
|
var dump_obj = func(m) {
|
||||||
|
var h = {};
|
||||||
|
foreach (var k; keys(m))
|
||||||
|
if (k != "parents")
|
||||||
|
h[k] = m[k];
|
||||||
|
debug.dump(h);
|
||||||
|
};
|
||||||
|
|
||||||
|
##
|
||||||
|
# must be either of:
|
||||||
|
# 1) draw* callback, 2) SVG filename, 3) Drawable class (with styling/LOD support)
|
||||||
|
var SymbolDrawable = {
|
||||||
|
new: func() {
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
## wrapper for each element
|
||||||
|
## i.e. keeps the canvas and texture map coordinates
|
||||||
|
var CachedElement = {
|
||||||
|
new: func(canvas_path, name, source, offset) {
|
||||||
|
var m = {parents:[CachedElement] };
|
||||||
|
m.canvas_src = canvas_path;
|
||||||
|
m.name = name;
|
||||||
|
m.source = source;
|
||||||
|
m.offset = offset;
|
||||||
|
return m;
|
||||||
|
}, # new()
|
||||||
|
render: func(group) {
|
||||||
|
# create a raster image child in the render target/group
|
||||||
|
return
|
||||||
|
group.createChild("image", me.name)
|
||||||
|
.setFile( me.canvas_src )
|
||||||
|
# TODO: fix .setSourceRect() to accept a single vector for coordinates ...
|
||||||
|
.setSourceRect(left:me.source[0],top:me.source[1],right:me.source[2],bottom:me.source[3] , normalized:0)
|
||||||
|
.setTranslation(me.offset); # FIXME: make sure this stays like this and isn't overridden
|
||||||
|
}, # render()
|
||||||
|
}; # of CachedElement
|
||||||
|
|
||||||
|
var SymbolCache = {
|
||||||
|
# We can draw symbols either with left/top, centered,
|
||||||
|
# or right/bottom alignment. Specify two in a vector
|
||||||
|
# to mix and match, e.g. left/centered would be
|
||||||
|
# [SymbolCache.DRAW_LEFT_TOP,SymbolCache.DRAW_CENTERED]
|
||||||
|
DRAW_LEFT_TOP: 0.0,
|
||||||
|
DRAW_CENTERED: 0.5,
|
||||||
|
DRAW_RIGHT_BOTTOM: 1.0,
|
||||||
|
new: func(dim...) {
|
||||||
|
var m = { parents:[SymbolCache] };
|
||||||
|
# to keep track of the next free caching spot (in px)
|
||||||
|
m.next_free = [0, 0];
|
||||||
|
# to store each type of symbol
|
||||||
|
m.dict = {};
|
||||||
|
if (size(dim) == 1 and typeof(dim[0]) == 'vector')
|
||||||
|
dim = dim[0];
|
||||||
|
# Two sizes: canvas and symbol
|
||||||
|
if (size(dim) == 2) {
|
||||||
|
var canvas_x = var canvas_y = dim[0];
|
||||||
|
var image_x = var image_y = dim[1];
|
||||||
|
# Two widths (canvas and symbol) and then height/width ratio
|
||||||
|
} else if (size(dim) == 3) {
|
||||||
|
var (canvas_x,image_x,ratio) = dim;
|
||||||
|
var canvas_y = canvas_x * ratio;
|
||||||
|
var image_y = image_x * ratio;
|
||||||
|
# Explicit canvas and symbol widths/heights
|
||||||
|
} else if (size(dim) == 4) {
|
||||||
|
var (canvas_x,canvas_y,image_x,image_y) = dim;
|
||||||
|
}
|
||||||
|
m.canvas_sz = [canvas_x, canvas_y];
|
||||||
|
m.image_sz = [image_x, image_y];
|
||||||
|
|
||||||
|
# allocate a canvas
|
||||||
|
m.canvas_texture = canvas.new( {
|
||||||
|
"name": "SymbolCache"~canvas_x~'x'~canvas_y,
|
||||||
|
"size": m.canvas_sz,
|
||||||
|
"view": m.canvas_sz,
|
||||||
|
"mipmapping": 1
|
||||||
|
});
|
||||||
|
|
||||||
|
# add a placement
|
||||||
|
m.canvas_texture.addPlacement( {"type": "ref"} );
|
||||||
|
|
||||||
|
return m;
|
||||||
|
},
|
||||||
|
add: func(name, callback, draw_mode=0) {
|
||||||
|
if (typeof(draw_mode) == 'scalar')
|
||||||
|
var draw_mode0 = var draw_mode1 = draw_mode;
|
||||||
|
else var (draw_mode0,draw_mode1) = draw_mode;
|
||||||
|
# get canvas texture that we use as cache
|
||||||
|
# get next free spot in texture (column/row)
|
||||||
|
# run the draw callback and render into a group
|
||||||
|
var gr = me.canvas_texture.createGroup();
|
||||||
|
gr.setTranslation( me.next_free[0] + me.image_sz[0]*draw_mode0,
|
||||||
|
me.next_free[1] + me.image_sz[1]*draw_mode1);
|
||||||
|
#settimer(func debug.dump ( gr.getTransformedBounds() ), 0); # XXX: these are only updated when rendered
|
||||||
|
#debug.dump ( gr.getTransformedBounds() );
|
||||||
|
gr.update(); # apparently this doesn't result in sane output from .getTransformedBounds() either
|
||||||
|
#debug.dump ( gr.getTransformedBounds() );
|
||||||
|
# draw the symbol
|
||||||
|
callback(gr);
|
||||||
|
# get the bounding box, i.e. coordinates for texture map, or use the .setTranslation() params
|
||||||
|
var coords = me.next_free~me.next_free;
|
||||||
|
foreach (var i; [0,1])
|
||||||
|
coords[i+2] += me.image_sz[i];
|
||||||
|
# get the offset we used to position correctly in the bounds of the canvas
|
||||||
|
var offset = [me.image_sz[0]*draw_mode0, me.image_sz[1]*draw_mode1];
|
||||||
|
# store texture map coordinates in lookup map using the name as identifier
|
||||||
|
me.dict[name] = CachedElement.new(me.canvas_texture.getPath(), name, coords, offset );
|
||||||
|
# update next free position in cache (column/row)
|
||||||
|
me.next_free[0] += me.image_sz[0];
|
||||||
|
if (me.next_free[0] >= me.canvas_sz[0])
|
||||||
|
{ me.next_free[0] = 0; me.next_free[1] += me.image_sz[1] }
|
||||||
|
if (me.next_free[1] >= me.canvas_sz[1])
|
||||||
|
die("SymbolCache: ran out of space after adding '"~name~"'");
|
||||||
|
}, # add()
|
||||||
|
get: func(name) {
|
||||||
|
if(!contains(me.dict,name)) die("No SymbolCache entry for key:"~ name);
|
||||||
|
return me.dict[name];
|
||||||
|
}, # get()
|
||||||
|
};
|
||||||
|
|
||||||
var Symbol = {
|
var Symbol = {
|
||||||
# Static/singleton:
|
# Static/singleton:
|
||||||
registry: {},
|
registry: {},
|
||||||
|
@ -29,7 +149,7 @@ Symbol.Controller = {
|
||||||
# Static/singleton:
|
# Static/singleton:
|
||||||
registry: {},
|
registry: {},
|
||||||
add: func(type, class)
|
add: func(type, class)
|
||||||
registry[type] = class,
|
me.registry[type] = class,
|
||||||
get: func(type)
|
get: func(type)
|
||||||
if ((var class = me.registry[type]) == nil)
|
if ((var class = me.registry[type]) == nil)
|
||||||
die("unknown type '"~type~"'");
|
die("unknown type '"~type~"'");
|
||||||
|
@ -58,13 +178,17 @@ var getpos_fromghost = func(positioned_g)
|
||||||
# (geo.Coord and positioned ghost currently)
|
# (geo.Coord and positioned ghost currently)
|
||||||
Symbol.Controller.getpos = func(obj) {
|
Symbol.Controller.getpos = func(obj) {
|
||||||
if (typeof(obj) == 'ghost')
|
if (typeof(obj) == 'ghost')
|
||||||
if (ghosttype(obj) == 'positioned' or ghosttype(obj) == 'Navaid')
|
if (ghosttype(obj) == 'positioned' or ghosttype(obj) == 'Navaid' or ghosttype(obj)=='Fix' or ghosttype(obj)=='flightplan-leg')
|
||||||
return getpos_fromghost(obj);
|
return getpos_fromghost(obj);
|
||||||
else
|
else
|
||||||
die("bad ghost of type '"~ghosttype(obj)~"'");
|
die("bad ghost of type '"~ghosttype(obj)~"'");
|
||||||
if (typeof(obj) == 'hash')
|
if (typeof(obj) == 'hash')
|
||||||
if (isa(obj, geo.Coord))
|
if (isa(obj, geo.Coord))
|
||||||
return obj.latlon();
|
return obj.latlon();
|
||||||
|
if (contains(obj,'lat') and contains(obj,'lon'))
|
||||||
|
return [obj.lat, obj.lon];
|
||||||
|
|
||||||
|
debug.dump(obj);
|
||||||
die("no suitable getpos() found! Of type: "~typeof(obj));
|
die("no suitable getpos() found! Of type: "~typeof(obj));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -82,38 +206,17 @@ var DotSym = {
|
||||||
element_id: nil,
|
element_id: nil,
|
||||||
# Static/singleton:
|
# Static/singleton:
|
||||||
makeinstance: func(name, hash) {
|
makeinstance: func(name, hash) {
|
||||||
assert_ms(hash,
|
if (!isa(hash, DotSym))
|
||||||
"element_type", # type of Canvas element
|
die("OOP error");
|
||||||
#"element_id", # optional Canvas id
|
#assert_ms(hash,
|
||||||
#"init", # initialize routine
|
# "element_type", # type of Canvas element
|
||||||
"draw", # init/update routine
|
# #"element_id", # optional Canvas id
|
||||||
#getpos", # get position from model in [x_units,y_units] (optional)
|
# #"init", # initialize routine
|
||||||
);
|
# "draw", # init/update routine
|
||||||
hash.parents = [DotSym];
|
# #getpos", # get position from model in [x_units,y_units] (optional)
|
||||||
|
#);
|
||||||
return Symbol.add(name, hash);
|
return Symbol.add(name, hash);
|
||||||
},
|
},
|
||||||
readinstance: func(file, name=nil) {
|
|
||||||
#print(file);
|
|
||||||
if (name == nil)
|
|
||||||
var name = split("/", file)[-1];
|
|
||||||
if (substr(name, size(name)-4) == ".draw")
|
|
||||||
name = substr(name, 0, size(name)-5);
|
|
||||||
var code = io.readfile(file);
|
|
||||||
var code = call(compile, [code], var err=[]);
|
|
||||||
if (size(err)) {
|
|
||||||
if (substr(err[0], 0, 12) == "Parse error:") { # hack around Nasal feature
|
|
||||||
var e = split(" at line ", err[0]);
|
|
||||||
if (size(e) == 2)
|
|
||||||
err[0] = string.join("", [e[0], "\n at ", file, ", line ", e[1], "\n "]);
|
|
||||||
}
|
|
||||||
for (var i = 1; (var c = caller(i)) != nil; i += 1)
|
|
||||||
err ~= subvec(c, 2, 2);
|
|
||||||
debug.printerror(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
call(code, nil, nil, var hash = { parents:[DotSym] });
|
|
||||||
me.makeinstance(name, hash);
|
|
||||||
},
|
|
||||||
# For the instances returned from makeinstance:
|
# For the instances returned from makeinstance:
|
||||||
# @param group The Canvas group to add this to.
|
# @param group The Canvas group to add this to.
|
||||||
# @param model A correct object (e.g. positioned ghost) as
|
# @param model A correct object (e.g. positioned ghost) as
|
||||||
|
@ -132,6 +235,10 @@ var DotSym = {
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
if (m.controller != nil) {
|
if (m.controller != nil) {
|
||||||
|
#print("Creating controller");
|
||||||
|
temp = m.controller.new(m.model,m);
|
||||||
|
if (temp != nil)
|
||||||
|
m.controller = temp;
|
||||||
#print("Initializing controller");
|
#print("Initializing controller");
|
||||||
m.controller.init(model);
|
m.controller.init(model);
|
||||||
}
|
}
|
||||||
|
@ -281,93 +388,117 @@ SymbolLayer.Controller = {
|
||||||
die("searchCmd() not implemented for this SymbolLayer.Controller type!"),
|
die("searchCmd() not implemented for this SymbolLayer.Controller type!"),
|
||||||
}; # of SymbolLayer.Controller
|
}; # of SymbolLayer.Controller
|
||||||
|
|
||||||
settimer(func {
|
var AnimatedLayer = {
|
||||||
Map.Controller = {
|
|
||||||
# Static/singleton:
|
|
||||||
registry: {},
|
|
||||||
add: func(type, class)
|
|
||||||
me.registry[type] = class,
|
|
||||||
get: func(type)
|
|
||||||
if ((var class = me.registry[type]) == nil)
|
|
||||||
die("unknown type '"~type~"'");
|
|
||||||
else return class,
|
|
||||||
# Calls corresonding controller constructor
|
|
||||||
# @param map The #SymbolMap this controller is responsible for.
|
|
||||||
new: func(type, layer, arg...)
|
|
||||||
return call((var class = me.get(type)).new, [map]~arg, class),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
####### LOAD FILES #######
|
var CompassLayer = {
|
||||||
#print("loading files");
|
};
|
||||||
(func {
|
|
||||||
var FG_ROOT = getprop("/sim/fg-root");
|
var AltitudeArcLayer = {
|
||||||
var load = func(file, name) {
|
};
|
||||||
#print(file);
|
|
||||||
if (name == nil)
|
load_MapStructure = func {
|
||||||
var name = split("/", file)[-1];
|
Map.Controller = {
|
||||||
if (substr(name, size(name)-4) == ".draw")
|
# Static/singleton:
|
||||||
name = substr(name, 0, size(name)-5);
|
registry: {},
|
||||||
#print("reading file");
|
add: func(type, class)
|
||||||
var code = io.readfile(file);
|
me.registry[type] = class,
|
||||||
#print("compiling file");
|
get: func(type)
|
||||||
# This segfaults for some reason:
|
if ((var class = me.registry[type]) == nil)
|
||||||
#var code = call(compile, [code], var err=[]);
|
die("unknown type '"~type~"'");
|
||||||
var code = call(func compile(code, file), [code], var err=[]);
|
else return class,
|
||||||
if (size(err)) {
|
# Calls corresonding controller constructor
|
||||||
#print("handling error");
|
# @param map The #SymbolMap this controller is responsible for.
|
||||||
if (substr(err[0], 0, 12) == "Parse error:") { # hack around Nasal feature
|
new: func(type, layer, arg...)
|
||||||
var e = split(" at line ", err[0]);
|
return call((var class = me.get(type)).new, [map]~arg, class),
|
||||||
if (size(e) == 2)
|
};
|
||||||
err[0] = string.join("", [e[0], "\n at ", file, ", line ", e[1], "\n "]);
|
|
||||||
|
####### LOAD FILES #######
|
||||||
|
#print("loading files");
|
||||||
|
(func {
|
||||||
|
var FG_ROOT = getprop("/sim/fg-root");
|
||||||
|
var load = func(file, name) {
|
||||||
|
#print(file);
|
||||||
|
if (name == nil)
|
||||||
|
var name = split("/", file)[-1];
|
||||||
|
if (substr(name, size(name)-4) == ".draw")
|
||||||
|
name = substr(name, 0, size(name)-5);
|
||||||
|
#print("reading file");
|
||||||
|
var code = io.readfile(file);
|
||||||
|
#print("compiling file");
|
||||||
|
# This segfaults for some reason:
|
||||||
|
#var code = call(compile, [code], var err=[]);
|
||||||
|
var code = call(func compile(code, file), [code], var err=[]);
|
||||||
|
if (size(err)) {
|
||||||
|
#print("handling error");
|
||||||
|
if (substr(err[0], 0, 12) == "Parse error:") { # hack around Nasal feature
|
||||||
|
var e = split(" at line ", err[0]);
|
||||||
|
if (size(e) == 2)
|
||||||
|
err[0] = string.join("", [e[0], "\n at ", file, ", line ", e[1], "\n "]);
|
||||||
|
}
|
||||||
|
for (var i = 1; (var c = caller(i)) != nil; i += 1)
|
||||||
|
err ~= subvec(c, 2, 2);
|
||||||
|
debug.printerror(err);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
for (var i = 1; (var c = caller(i)) != nil; i += 1)
|
#print("calling code");
|
||||||
err ~= subvec(c, 2, 2);
|
call(code, nil, nil, var hash = {});
|
||||||
debug.printerror(err);
|
#debug.dump(keys(hash));
|
||||||
return;
|
return hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
var load_deps = func(name) {
|
||||||
|
load(FG_ROOT~"/Nasal/canvas/map/"~name~".lcontroller", name);
|
||||||
|
load(FG_ROOT~"/Nasal/canvas/map/"~name~".symbol", name);
|
||||||
|
load(FG_ROOT~"/Nasal/canvas/map/"~name~".scontroller", name);
|
||||||
}
|
}
|
||||||
#print("calling code");
|
|
||||||
call(code, nil, nil, var hash = {});
|
|
||||||
#debug.dump(keys(hash));
|
|
||||||
return hash;
|
|
||||||
};
|
|
||||||
load(FG_ROOT~"/Nasal/canvas/map/VOR.lcontroller", "VOR");
|
|
||||||
DotSym.readinstance(FG_ROOT~"/Nasal/canvas/map/VOR.symbol", "VOR");
|
|
||||||
load(FG_ROOT~"/Nasal/canvas/map/VOR.scontroller", "VOR");
|
|
||||||
load(FG_ROOT~"/Nasal/canvas/map/aircraftpos.controller", "VOR");
|
|
||||||
})();
|
|
||||||
#print("finished loading files");
|
|
||||||
####### TEST SYMBOL #######
|
|
||||||
|
|
||||||
if (0)
|
foreach( var name; ['VOR','FIX','NDB','DME','WPT'] )
|
||||||
settimer(func {
|
load_deps( name );
|
||||||
if (caller(0)[0] != globals.canvas)
|
load(FG_ROOT~"/Nasal/canvas/map/aircraftpos.controller", name);
|
||||||
return call(caller(0)[1], arg, nil, globals.canvas);
|
|
||||||
|
|
||||||
print("Running MapStructure test code");
|
###
|
||||||
var TestCanvas = canvas.new({
|
# set up a cache for 32x32 symbols
|
||||||
"name": "Map Test",
|
var SymbolCache32x32 = SymbolCache.new(1024,32);
|
||||||
"size": [1024, 1024],
|
|
||||||
"view": [1024, 1024],
|
|
||||||
"mipmapping": 1
|
|
||||||
});
|
|
||||||
var dlg = canvas.Window.new([400, 400], "dialog");
|
|
||||||
dlg.setCanvas(TestCanvas);
|
|
||||||
var TestMap = TestCanvas.createGroup().createChild("map"); # we should not directly use a canvas here, but instead a LayeredMap.new()
|
|
||||||
TestMap.addLayer(factory: SymbolLayer, type_arg: "VOR"); # the ID should be also exposed in the property tree for each group (layer), i.e. better debugging
|
|
||||||
# Center the map's origin:
|
|
||||||
TestMap.setTranslation(512,512); # FIXME: don't hardcode these values, but read in canvas texture dimensions, otherwise it will break once someone uses non 1024x1024 textures ...
|
|
||||||
# Initialize a range (TODO: LayeredMap.Controller):
|
|
||||||
TestMap.set("range", 100);
|
|
||||||
# Little cursor of current position:
|
|
||||||
TestMap.createChild("path").rect(-5,-5,10,10).setColorFill(1,1,1).setColor(0,1,0);
|
|
||||||
# And make it move with our aircraft:
|
|
||||||
TestMap.setController("Aircraft position"); # from aircraftpos.controller
|
|
||||||
dlg.del = func() {
|
|
||||||
TestMap.del();
|
|
||||||
# call inherited 'del'
|
|
||||||
delete(me, "del");
|
|
||||||
me.del();
|
|
||||||
};
|
|
||||||
}, 1);
|
|
||||||
}, 0); # end ugly module init timer hack
|
|
||||||
|
|
||||||
|
var drawVOR = func(color, width=3) return func(group) {
|
||||||
|
# print("drawing vor");
|
||||||
|
var bbox = group.createChild("path")
|
||||||
|
.moveTo(-15,0)
|
||||||
|
.lineTo(-7.5,12.5)
|
||||||
|
.lineTo(7.5,12.5)
|
||||||
|
.lineTo(15,0)
|
||||||
|
.lineTo(7.5,-12.5)
|
||||||
|
.lineTo(-7.5,-12.5)
|
||||||
|
.close()
|
||||||
|
.setStrokeLineWidth(width)
|
||||||
|
.setColor( color );
|
||||||
|
# debug.dump( bbox.getBoundingBox() );
|
||||||
|
};
|
||||||
|
|
||||||
|
var cachedVOR1 = SymbolCache32x32.add( "VOR-BLUE", drawVOR( color:[0, 0.6, 0.85], width:3), SymbolCache.DRAW_CENTERED );
|
||||||
|
var cachedVOR2 = SymbolCache32x32.add( "VOR-RED" , drawVOR( color:[1.0, 0, 0], width: 3), SymbolCache.DRAW_CENTERED );
|
||||||
|
var cachedVOR3 = SymbolCache32x32.add( "VOR-GREEN" , drawVOR( color:[0, 1, 0], width: 3), SymbolCache.DRAW_CENTERED );
|
||||||
|
var cachedVOR4 = SymbolCache32x32.add( "VOR-WHITE" , drawVOR( color:[1, 1, 1], width: 3), SymbolCache.DRAW_CENTERED );
|
||||||
|
|
||||||
|
# STRESS TEST
|
||||||
|
if (0) {
|
||||||
|
for(var i=0;i <= 1024/32*4 - 4; i+=1)
|
||||||
|
SymbolCache32x32.add( "VOR-YELLOW"~i , drawVOR( color:[1, 1, 0], width: 3) );
|
||||||
|
|
||||||
|
var dlg = canvas.Window.new([640,320],"dialog");
|
||||||
|
var my_canvas = dlg.createCanvas().setColorBackground(1,1,1,1);
|
||||||
|
var root = my_canvas.createGroup();
|
||||||
|
|
||||||
|
SymbolCache32x32.get(name:"VOR-BLUE").render( group: root ).setGeoPosition(getprop("/position/latitude-deg"),getprop("/position/longitude-deg"));
|
||||||
|
}
|
||||||
|
|
||||||
|
})();
|
||||||
|
#print("finished loading files");
|
||||||
|
####### TEST SYMBOL #######
|
||||||
|
|
||||||
|
canvas.load_MapStructure = func;
|
||||||
|
|
||||||
|
}; # load_MapStructure
|
||||||
|
|
||||||
|
setlistener("/nasal/canvas/loaded", load_MapStructure); # end ugly module init listener hack
|
||||||
|
|
|
@ -462,47 +462,45 @@ var Map = {
|
||||||
addLayer: func(factory, type_arg=nil, priority=nil)
|
addLayer: func(factory, type_arg=nil, priority=nil)
|
||||||
{
|
{
|
||||||
if (!contains(me, "layers"))
|
if (!contains(me, "layers"))
|
||||||
me.layers = [];
|
me.layers = {};
|
||||||
|
|
||||||
|
if(contains(me.layers, type_arg))
|
||||||
|
print("addLayer() warning: overwriting existing layer:", type_arg);
|
||||||
|
|
||||||
|
# print("addLayer():", type_arg);
|
||||||
|
|
||||||
# Argument handling
|
# Argument handling
|
||||||
if (type_arg != nil)
|
if (type_arg != nil)
|
||||||
var type = factory.get(type_arg);
|
var type = factory.get(type_arg);
|
||||||
else var type = factory;
|
else var type = factory;
|
||||||
|
|
||||||
|
me.layers[type_arg]= type.new(me);
|
||||||
if (priority == nil)
|
if (priority == nil)
|
||||||
priority = type.df_priority;
|
priority = type.df_priority;
|
||||||
append(me.layers, [type.new(me), priority]);
|
|
||||||
if (priority != nil)
|
if (priority != nil)
|
||||||
me._sort_priority();
|
me.layers[type_arg].setInt("z-index", priority);
|
||||||
return me;
|
return me;
|
||||||
},
|
},
|
||||||
setPos: func(lat,lon,hdg=nil)
|
getLayer: func(type_arg) me.layers[type_arg],
|
||||||
|
setPos: func(lat, lon, hdg=nil, range=nil)
|
||||||
{
|
{
|
||||||
me.set("ref-lat", lat);
|
me.set("ref-lat", lat);
|
||||||
me.set("ref-lon", lon);
|
me.set("ref-lon", lon);
|
||||||
if (hdg != nil)
|
if (hdg != nil)
|
||||||
me.set("hdg", hdg);
|
me.set("hdg", hdg);
|
||||||
|
if (range != nil)
|
||||||
# me.map.set("range", 100);
|
me.set("range", range);
|
||||||
},
|
},
|
||||||
# Update each layer on this Map. Called by
|
# Update each layer on this Map. Called by
|
||||||
# me.controller.
|
# me.controller.
|
||||||
update: func
|
update: func
|
||||||
{
|
{
|
||||||
foreach (var l; me.layers)
|
foreach (var l; keys(me.layers)) {
|
||||||
call(l[0].update, arg, l[0]);
|
var layer = me.layers[l];
|
||||||
|
call(layer.update, arg, layer);
|
||||||
|
}
|
||||||
return me;
|
return me;
|
||||||
},
|
},
|
||||||
# private:
|
|
||||||
_sort_priority: func()
|
|
||||||
{
|
|
||||||
me.layers = sort(me.layers, me._sort_cmp);
|
|
||||||
forindex (var i; me.layers)
|
|
||||||
me.layers[i].set("z-index", i);
|
|
||||||
},
|
|
||||||
_sort_cmp: func(a,b) {
|
|
||||||
a[1] != b[1] and a[1] != nil and b[1] != nil and (a[1] < b[1] ? -1 : 1)
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# Text
|
# Text
|
||||||
|
|
|
@ -429,10 +429,16 @@ var files_with = func(ext) {
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
foreach(var ext; var extensions = ['.draw','.model','.layer'])
|
|
||||||
load_modules(files_with(ext));
|
|
||||||
|
|
||||||
|
setlistener("/nasal/canvas/loaded", func {
|
||||||
|
foreach(var ext; var extensions = ['.draw','.model','.layer'])
|
||||||
|
load_modules(files_with(ext));
|
||||||
|
|
||||||
|
if (contains(canvas,"load_MapStructure"))
|
||||||
|
load_MapStructure();
|
||||||
|
|
||||||
|
# canvas.MFD = {EFIS:}; # where we'll be storing all MFDs
|
||||||
|
# TODO: should be inside a separate subfolder, i.e. canvas/map/mfd
|
||||||
|
load_modules( files_with('.mfd'), 'canvas' );
|
||||||
|
});
|
||||||
|
|
||||||
# canvas.MFD = {EFIS:}; # where we'll be storing all MFDs
|
|
||||||
# TODO: should be inside a separate subfolder, i.e. canvas/map/mfd
|
|
||||||
load_modules( files_with('.mfd'), 'canvas' );
|
|
||||||
|
|
32
Nasal/canvas/map/DME.lcontroller
Normal file
32
Nasal/canvas/map/DME.lcontroller
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# Class things:
|
||||||
|
var name = 'DME';
|
||||||
|
var parents = [SymbolLayer.Controller];
|
||||||
|
var __self__ = caller(0)[0];
|
||||||
|
SymbolLayer.Controller.add(name, __self__);
|
||||||
|
SymbolLayer.add(name, {
|
||||||
|
parents: [SymbolLayer],
|
||||||
|
type: name, # Symbol type
|
||||||
|
df_controller: __self__, # controller to use by default -- this one
|
||||||
|
});
|
||||||
|
var a_instance = nil;
|
||||||
|
var new = func(layer) {
|
||||||
|
var m = {
|
||||||
|
parents: [__self__],
|
||||||
|
layer: layer,
|
||||||
|
listeners: [],
|
||||||
|
query_range_nm: 25,
|
||||||
|
query_type:'dme',
|
||||||
|
};
|
||||||
|
__self__.a_instance = m;
|
||||||
|
return m;
|
||||||
|
};
|
||||||
|
var del = func() {
|
||||||
|
foreach (var l; me.listeners)
|
||||||
|
removelistener(l);
|
||||||
|
};
|
||||||
|
|
||||||
|
var searchCmd = func {
|
||||||
|
#print("Running query:", me.query_type);
|
||||||
|
return positioned.findWithinRange(me.query_range_nm, me.query_type); # the range should also be exposed, it will typically be controlled via a GUI widget or NavDisplay switch
|
||||||
|
};
|
||||||
|
|
12
Nasal/canvas/map/DME.scontroller
Normal file
12
Nasal/canvas/map/DME.scontroller
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# Class things:
|
||||||
|
var name = 'DME';
|
||||||
|
var parents = [Symbol.Controller];
|
||||||
|
var __self__ = caller(0)[0];
|
||||||
|
Symbol.Controller.add(name, __self__);
|
||||||
|
Symbol.registry[ name ].df_controller = __self__;
|
||||||
|
var new = func(model) ; # this controller doesn't need an instance
|
||||||
|
var LayerController = SymbolLayer.Controller.registry[ name ];
|
||||||
|
var isActive = func(model) LayerController.a_instance.isActive(model);
|
||||||
|
var is_tuned = func()
|
||||||
|
die( name~".scontroller.is_tuned /MUST/ be provided by implementation" );
|
||||||
|
|
35
Nasal/canvas/map/DME.symbol
Normal file
35
Nasal/canvas/map/DME.symbol
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
# Class things:
|
||||||
|
var name = 'DME';
|
||||||
|
var parents = [DotSym];
|
||||||
|
var __self__ = caller(0)[0];
|
||||||
|
DotSym.makeinstance( name, __self__ );
|
||||||
|
|
||||||
|
var element_type = "group"; # we want a group, becomes "me.element"
|
||||||
|
var icon_dme = nil;
|
||||||
|
|
||||||
|
var draw = func {
|
||||||
|
# Init
|
||||||
|
if (me.icon_dme == nil) {
|
||||||
|
me.icon_dme = me.element.createChild("path")
|
||||||
|
.moveTo(-15,0)
|
||||||
|
.line(-12.5,-7.5)
|
||||||
|
.line(7.5,-12.5)
|
||||||
|
.line(12.5,7.5)
|
||||||
|
.lineTo(7.5,-12.5)
|
||||||
|
.line(12.5,-7.5)
|
||||||
|
.line(7.5,12.5)
|
||||||
|
.line(-12.5,7.5)
|
||||||
|
.lineTo(15,0)
|
||||||
|
.lineTo(7.5,12.5)
|
||||||
|
.vert(14.5)
|
||||||
|
.horiz(-14.5)
|
||||||
|
.vert(-14.5)
|
||||||
|
.close()
|
||||||
|
.setStrokeLineWidth(3);
|
||||||
|
}
|
||||||
|
if (me.controller != nil and me.controller.is_tuned(me.model.frequency/100))
|
||||||
|
me.icon_dme.setColor(0,1,0);
|
||||||
|
else
|
||||||
|
me.icon_dme.setColor(0,0.6,0.85);
|
||||||
|
};
|
||||||
|
|
33
Nasal/canvas/map/FIX.lcontroller
Normal file
33
Nasal/canvas/map/FIX.lcontroller
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# Class things:
|
||||||
|
var name = 'FIX';
|
||||||
|
var parents = [SymbolLayer.Controller];
|
||||||
|
var __self__ = caller(0)[0];
|
||||||
|
SymbolLayer.Controller.add(name, __self__);
|
||||||
|
SymbolLayer.add(name, {
|
||||||
|
parents: [SymbolLayer],
|
||||||
|
type: name, # Symbol type
|
||||||
|
df_controller: __self__, # controller to use by default -- this one
|
||||||
|
});
|
||||||
|
var a_instance = nil;
|
||||||
|
var new = func(layer) {
|
||||||
|
var m = {
|
||||||
|
parents: [__self__],
|
||||||
|
layer: layer,
|
||||||
|
listeners: [],
|
||||||
|
query_range_nm: 25,
|
||||||
|
query_type:'fix',
|
||||||
|
};
|
||||||
|
__self__.a_instance = m;
|
||||||
|
return m;
|
||||||
|
};
|
||||||
|
var del = func() {
|
||||||
|
#print("VOR.lcontroller.del()");
|
||||||
|
foreach (var l; me.listeners)
|
||||||
|
removelistener(l);
|
||||||
|
};
|
||||||
|
|
||||||
|
var searchCmd = func {
|
||||||
|
#print("Running query:", me.query_type);
|
||||||
|
return positioned.findWithinRange(me.query_range_nm, me.query_type); # the range should also be exposed, it will typically be controlled via a GUI widget or NavDisplay switch
|
||||||
|
};
|
||||||
|
|
12
Nasal/canvas/map/FIX.scontroller
Normal file
12
Nasal/canvas/map/FIX.scontroller
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# Class things:
|
||||||
|
var name = 'FIX';
|
||||||
|
var parents = [Symbol.Controller];
|
||||||
|
var __self__ = caller(0)[0];
|
||||||
|
Symbol.Controller.add(name, __self__);
|
||||||
|
Symbol.registry[ name ].df_controller = __self__;
|
||||||
|
var new = func(model) ; # this controller doesn't need an instance
|
||||||
|
var LayerController = SymbolLayer.Controller.registry[ name ];
|
||||||
|
var isActive = func(model) LayerController.a_instance.isActive(model);
|
||||||
|
var query_range = func()
|
||||||
|
die( name~".scontroller.query_range /MUST/ be provided by implementation" );
|
||||||
|
|
30
Nasal/canvas/map/FIX.symbol
Normal file
30
Nasal/canvas/map/FIX.symbol
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# Class things:
|
||||||
|
var name = 'FIX';
|
||||||
|
var parents = [DotSym];
|
||||||
|
var __self__ = caller(0)[0];
|
||||||
|
DotSym.makeinstance( name, __self__ );
|
||||||
|
|
||||||
|
var element_type = "group"; # we want a group, becomes "me.element"
|
||||||
|
var icon_fix = nil;
|
||||||
|
var text_fix = nil;
|
||||||
|
|
||||||
|
var draw = func {
|
||||||
|
if (me.icon_fix != nil) return;
|
||||||
|
# the fix symbol
|
||||||
|
me.icon_fix = me.element.createChild("path")
|
||||||
|
.moveTo(-15,15)
|
||||||
|
.lineTo(0,-15)
|
||||||
|
.lineTo(15,15)
|
||||||
|
.close()
|
||||||
|
.setStrokeLineWidth(3)
|
||||||
|
.setColor(0,0.6,0.85)
|
||||||
|
.setScale(0.5,0.5); # FIXME: do proper LOD handling here - we need to scale according to current texture dimensions vs. original/design dimensions
|
||||||
|
# the fix label
|
||||||
|
me.text_fix = me.element.createChild("text")
|
||||||
|
.setDrawMode( canvas.Text.TEXT )
|
||||||
|
.setText(me.model.id)
|
||||||
|
.setFont("LiberationFonts/LiberationSans-Regular.ttf")
|
||||||
|
.setFontSize(28)
|
||||||
|
.setTranslation(5,25);
|
||||||
|
};
|
||||||
|
|
30
Nasal/canvas/map/NDB.lcontroller
Normal file
30
Nasal/canvas/map/NDB.lcontroller
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# Class things:
|
||||||
|
var name = 'NDB';
|
||||||
|
var parents = [SymbolLayer.Controller];
|
||||||
|
var __self__ = caller(0)[0];
|
||||||
|
SymbolLayer.Controller.add(name, __self__);
|
||||||
|
SymbolLayer.add(name, {
|
||||||
|
parents: [SymbolLayer],
|
||||||
|
type: name, # Symbol type
|
||||||
|
df_controller: __self__, # controller to use by default -- this one
|
||||||
|
});
|
||||||
|
var new = func(layer) {
|
||||||
|
var m = {
|
||||||
|
parents: [__self__],
|
||||||
|
layer: layer,
|
||||||
|
listeners: [],
|
||||||
|
query_range_nm: 25,
|
||||||
|
query_type:'ndb',
|
||||||
|
};
|
||||||
|
return m;
|
||||||
|
};
|
||||||
|
var del = func() {
|
||||||
|
foreach (var l; me.listeners)
|
||||||
|
removelistener(l);
|
||||||
|
};
|
||||||
|
|
||||||
|
var searchCmd = func {
|
||||||
|
#print("Running query:", me.query_type);
|
||||||
|
return positioned.findWithinRange(me.query_range_nm, me.query_type); # the range should also be exposed, it will typically be controlled via a GUI widget or NavDisplay switch
|
||||||
|
};
|
||||||
|
|
12
Nasal/canvas/map/NDB.scontroller
Normal file
12
Nasal/canvas/map/NDB.scontroller
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# Class things:
|
||||||
|
var name = 'NDB';
|
||||||
|
var parents = [Symbol.Controller];
|
||||||
|
var __self__ = caller(0)[0];
|
||||||
|
Symbol.Controller.add(name, __self__);
|
||||||
|
Symbol.registry[ name ].df_controller = __self__;
|
||||||
|
var new = func(model) ; # this controller doesn't need an instance
|
||||||
|
var LayerController = SymbolLayer.Controller.registry[ name ];
|
||||||
|
var isActive = func(model) LayerController.a_instance.isActive(model);
|
||||||
|
var query_range = func()
|
||||||
|
die( name~".scontroller.query_range /MUST/ be provided by implementation" );
|
||||||
|
|
18
Nasal/canvas/map/NDB.symbol
Normal file
18
Nasal/canvas/map/NDB.symbol
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Class things:
|
||||||
|
var name = 'NDB';
|
||||||
|
var parents = [DotSym];
|
||||||
|
var __self__ = caller(0)[0];
|
||||||
|
DotSym.makeinstance( name, __self__ );
|
||||||
|
|
||||||
|
var element_type = "group"; # we want a group, becomes "me.element", which we parse a SVG onto
|
||||||
|
var svg_path = "/gui/dialogs/images/ndb_symbol.svg"; # speaking of path, this is our path to use
|
||||||
|
var local_svg_path = nil; # track changes in the SVG's path
|
||||||
|
|
||||||
|
var draw = func {
|
||||||
|
if (me.svg_path == me.local_svg_path) return;
|
||||||
|
me.element.removeAllChildren();
|
||||||
|
me.local_svg_path = me.svg_path;
|
||||||
|
canvas.parsesvg(me.element, me.svg_path);
|
||||||
|
me.inited = 1;
|
||||||
|
};
|
||||||
|
|
|
@ -7,6 +7,7 @@ SymbolLayer.add("VOR", {
|
||||||
type: "VOR", # Symbol type
|
type: "VOR", # Symbol type
|
||||||
df_controller: __self__, # controller to use by default -- this one
|
df_controller: __self__, # controller to use by default -- this one
|
||||||
});
|
});
|
||||||
|
var a_instance = nil;
|
||||||
var new = func(layer) {
|
var new = func(layer) {
|
||||||
var m = {
|
var m = {
|
||||||
parents: [__self__],
|
parents: [__self__],
|
||||||
|
@ -14,6 +15,7 @@ var new = func(layer) {
|
||||||
active_vors: [],
|
active_vors: [],
|
||||||
navNs: props.globals.getNode("instrumentation").getChildren("nav"),
|
navNs: props.globals.getNode("instrumentation").getChildren("nav"),
|
||||||
listeners: [],
|
listeners: [],
|
||||||
|
query_type:'vor',
|
||||||
};
|
};
|
||||||
setsize(m.active_vors, size(m.navNs));
|
setsize(m.active_vors, size(m.navNs));
|
||||||
foreach (var navN; m.navNs) {
|
foreach (var navN; m.navNs) {
|
||||||
|
@ -24,6 +26,7 @@ var new = func(layer) {
|
||||||
}
|
}
|
||||||
#call(debug.dump, keys(layer));
|
#call(debug.dump, keys(layer));
|
||||||
m.changed_freq(update:0);
|
m.changed_freq(update:0);
|
||||||
|
__self__.a_instance = m;
|
||||||
return m;
|
return m;
|
||||||
};
|
};
|
||||||
var del = func() {
|
var del = func() {
|
||||||
|
@ -46,7 +49,7 @@ var changed_freq = func(update=1) {
|
||||||
if (update) me.layer.update();
|
if (update) me.layer.update();
|
||||||
};
|
};
|
||||||
var searchCmd = func {
|
var searchCmd = func {
|
||||||
#print("Run query");
|
#print("Running query:", me.query_type);
|
||||||
return positioned.findWithinRange(100, 'vor'); # the range should also be exposed, it will typically be controlled via a GUI widget or NavDisplay switch
|
return positioned.findWithinRange(100, me.query_type); # the range should also be exposed, it will typically be controlled via a GUI widget or NavDisplay switch
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
# Class things:
|
# Class things:
|
||||||
var parents = [Symbol.Controller];
|
var parents = [Symbol.Controller];
|
||||||
var __self__ = caller(0)[0];
|
var __self__ = caller(0)[0];
|
||||||
|
Symbol.Controller.add("VOR", __self__);
|
||||||
Symbol.registry["VOR"].df_controller = __self__;
|
Symbol.registry["VOR"].df_controller = __self__;
|
||||||
var new = func(model) ; # this controller doesn't need an instance
|
var new = func(model) ; # this controller doesn't need an instance
|
||||||
var LayerController = SymbolLayer.registry["VOR"];
|
var LayerController = SymbolLayer.Controller.registry["VOR"];
|
||||||
var isActive = func(model) LayerController.isActive(model);
|
var isActive = func(model) LayerController.a_instance.isActive(model);
|
||||||
var query_range = func()
|
var query_range = func()
|
||||||
die("VOR.scontroller.query_range /MUST/ be provided by implementation");
|
die("VOR.scontroller.query_range /MUST/ be provided by implementation");
|
||||||
|
|
||||||
|
|
|
@ -1,52 +1,57 @@
|
||||||
# Read by the DotSym.readinstance; each variable becomes a derived class's member/method
|
# Class things:
|
||||||
|
var name = 'VOR';
|
||||||
|
var parents = [DotSym];
|
||||||
|
var __self__ = caller(0)[0];
|
||||||
|
DotSym.makeinstance( name, __self__ );
|
||||||
|
|
||||||
var element_type = "group"; # we want a group, becomes "me.element"
|
var element_type = "group"; # we want a group, becomes "me.element"
|
||||||
var inited = 0; # this allows us to track whether draw() is an init() or an update()
|
var icon_vor = nil;
|
||||||
var range_vor = nil; # two elements that get drawn when needed
|
var range_vor = nil; # two elements that get drawn when needed
|
||||||
var radial_vor = nil; # if one is nil, the other has to be nil
|
var radial_vor = nil; # if one is nil, the other has to be nil
|
||||||
|
|
||||||
var draw = func {
|
var draw = func {
|
||||||
if (me.inited) {
|
# Init
|
||||||
# Update
|
if (me.icon_vor == nil) {
|
||||||
if (me.controller.isActive(me.model)) {
|
me.icon_vor = me.element.createChild("path")
|
||||||
if (me.range_vor == nil) {
|
.moveTo(-15,0)
|
||||||
var rangeNm = me.controller.query_range();
|
.lineTo(-7.5,12.5)
|
||||||
# print("VOR is tuned:", me.model.id);
|
.lineTo(7.5,12.5)
|
||||||
var radius = (me.model.range_nm/rangeNm)*345;
|
.lineTo(15,0)
|
||||||
me.range_vor = me.element.createChild("path")
|
.lineTo(7.5,-12.5)
|
||||||
.moveTo(-radius,0)
|
.lineTo(-7.5,-12.5)
|
||||||
.arcSmallCW(radius,radius,0,2*radius,0)
|
.close()
|
||||||
.arcSmallCW(radius,radius,0,-2*radius,0)
|
.setStrokeLineWidth(3)
|
||||||
.setStrokeLineWidth(3)
|
.setColor(0,0.6,0.85);
|
||||||
.setStrokeDashArray([5, 15, 5, 15, 5])
|
}
|
||||||
.setColor(0,1,0);
|
# Update
|
||||||
|
if (me.controller.isActive(me.model)) {
|
||||||
|
if (me.range_vor == nil) {
|
||||||
|
var rangeNm = me.controller.query_range();
|
||||||
|
# print("VOR is tuned:", me.model.id);
|
||||||
|
var radius = (me.model.range_nm/rangeNm)*345;
|
||||||
|
me.range_vor = me.element.createChild("path")
|
||||||
|
.moveTo(-radius,0)
|
||||||
|
.arcSmallCW(radius,radius,0,2*radius,0)
|
||||||
|
.arcSmallCW(radius,radius,0,-2*radius,0)
|
||||||
|
.setStrokeLineWidth(3)
|
||||||
|
.setStrokeDashArray([5, 15, 5, 15, 5])
|
||||||
|
.setColor(0,1,0);
|
||||||
|
|
||||||
var course = controller.get_tuned_course(me.model.frequency/100);
|
var course = me.controller.get_tuned_course(me.model.frequency/100);
|
||||||
vor_grp.createChild("path")
|
me.radial_vor = me.element.createChild("path")
|
||||||
.moveTo(0,-radius)
|
.moveTo(0,-radius)
|
||||||
.vert(2*radius)
|
.vert(2*radius)
|
||||||
.setStrokeLineWidth(3)
|
.setStrokeLineWidth(3)
|
||||||
.setStrokeDashArray([15, 5, 15, 5, 15])
|
.setStrokeDashArray([15, 5, 15, 5, 15])
|
||||||
.setColor(0,1,0)
|
.setColor(0,1,0)
|
||||||
.setRotation(course*D2R);
|
.setRotation(course*D2R);
|
||||||
icon_vor.setColor(0,1,0);
|
me.icon_vor.setColor(0,1,0);
|
||||||
}
|
|
||||||
me.range_vor.show();
|
|
||||||
me.radial_vor.show();
|
|
||||||
} else {
|
|
||||||
me.range_vor.hide();
|
|
||||||
me.radial_vor.hide();
|
|
||||||
}
|
}
|
||||||
} else # Init
|
me.range_vor.show();
|
||||||
me.element.createChild("path")
|
me.radial_vor.show();
|
||||||
.moveTo(-15,0)
|
} elsif (me.range_vor != nil) {
|
||||||
.lineTo(-7.5,12.5)
|
me.range_vor.hide();
|
||||||
.lineTo(7.5,12.5)
|
me.radial_vor.hide();
|
||||||
.lineTo(15,0)
|
}
|
||||||
.lineTo(7.5,-12.5)
|
|
||||||
.lineTo(-7.5,-12.5)
|
|
||||||
.close()
|
|
||||||
.setStrokeLineWidth(3)
|
|
||||||
.setColor(0,0.6,0.85);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
39
Nasal/canvas/map/WPT.lcontroller
Normal file
39
Nasal/canvas/map/WPT.lcontroller
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
# Class things:
|
||||||
|
var name = 'WPT'; # for waypoints
|
||||||
|
var parents = [SymbolLayer.Controller];
|
||||||
|
var __self__ = caller(0)[0];
|
||||||
|
SymbolLayer.Controller.add(name, __self__);
|
||||||
|
SymbolLayer.add(name, {
|
||||||
|
parents: [SymbolLayer],
|
||||||
|
type: name, # Symbol type
|
||||||
|
df_controller: __self__, # controller to use by default -- this one
|
||||||
|
});
|
||||||
|
var new = func(layer) {
|
||||||
|
var m = {
|
||||||
|
parents: [__self__],
|
||||||
|
layer: layer,
|
||||||
|
listeners: [],
|
||||||
|
query_range_nm: 25,
|
||||||
|
query_type:'vor',
|
||||||
|
};
|
||||||
|
return m;
|
||||||
|
};
|
||||||
|
var del = func() {
|
||||||
|
#print("VOR.lcontroller.del()");
|
||||||
|
foreach (var l; me.listeners)
|
||||||
|
removelistener(l);
|
||||||
|
};
|
||||||
|
|
||||||
|
var searchCmd = func {
|
||||||
|
#print("Running query: WPT");
|
||||||
|
|
||||||
|
var fp = flightplan();
|
||||||
|
var fpSize = fp.getPlanSize();
|
||||||
|
var result = [];
|
||||||
|
for (var i = 1; i <fpSize; i+=1)
|
||||||
|
append(result, fp.getWP(i).path()[0] );
|
||||||
|
|
||||||
|
return result;
|
||||||
|
# return positioned.findWithinRange(me.query_range_nm, me.query_type); # the range should also be exposed, it will typically be controlled via a GUI widget or NavDisplay switch
|
||||||
|
};
|
||||||
|
|
12
Nasal/canvas/map/WPT.scontroller
Normal file
12
Nasal/canvas/map/WPT.scontroller
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# Class things:
|
||||||
|
var name = 'WPT';
|
||||||
|
var parents = [Symbol.Controller];
|
||||||
|
var __self__ = caller(0)[0];
|
||||||
|
Symbol.Controller.add(name, __self__);
|
||||||
|
Symbol.registry[ name ].df_controller = __self__;
|
||||||
|
var new = func(model) ; # this controller doesn't need an instance
|
||||||
|
var LayerController = SymbolLayer.Controller.registry[ name ];
|
||||||
|
var isActive = func(model) LayerController.a_instance.isActive(model);
|
||||||
|
var query_range = func()
|
||||||
|
die( name~".scontroller.query_range /MUST/ be provided by implementation" );
|
||||||
|
|
34
Nasal/canvas/map/WPT.symbol
Normal file
34
Nasal/canvas/map/WPT.symbol
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
# Class things:
|
||||||
|
var name = 'WPT';
|
||||||
|
var parents = [DotSym];
|
||||||
|
var __self__ = caller(0)[0];
|
||||||
|
DotSym.makeinstance( name, __self__ );
|
||||||
|
|
||||||
|
var element_type = "group"; # we want a group, becomes "me.element"
|
||||||
|
var base = nil;
|
||||||
|
var text_wps = nil;
|
||||||
|
|
||||||
|
var draw = func {
|
||||||
|
if (me.base != nil) return;
|
||||||
|
me.base = me.element.createChild("path")
|
||||||
|
.setStrokeLineWidth(3)
|
||||||
|
.moveTo(0,-25)
|
||||||
|
.lineTo(-5,-5)
|
||||||
|
.lineTo(-25,0)
|
||||||
|
.lineTo(-5,5)
|
||||||
|
.lineTo(0,25)
|
||||||
|
.lineTo(5,5)
|
||||||
|
.lineTo(25,0)
|
||||||
|
.lineTo(5,-5)
|
||||||
|
.setColor(1,1,1)
|
||||||
|
.close();
|
||||||
|
|
||||||
|
me.text_wps = wpt_grp.createChild("text")
|
||||||
|
.setDrawMode( canvas.Text.TEXT )
|
||||||
|
.setText(name)
|
||||||
|
.setFont("LiberationFonts/LiberationSans-Regular.ttf")
|
||||||
|
.setFontSize(28)
|
||||||
|
.setTranslation(25,35)
|
||||||
|
.setColor(1,0,1);
|
||||||
|
};
|
||||||
|
|
|
@ -2,31 +2,27 @@ var AirportsNDModel = {};
|
||||||
AirportsNDModel.new = func make(AirportsNDModel, LayerModel);
|
AirportsNDModel.new = func make(AirportsNDModel, LayerModel);
|
||||||
|
|
||||||
AirportsNDModel.init = func {
|
AirportsNDModel.init = func {
|
||||||
#print("Updating AirportsNDModel");
|
|
||||||
|
|
||||||
me._view.reset();
|
me._view.reset();
|
||||||
|
|
||||||
var results = positioned.findWithinRange(me._controller.query_range()*2, "airport");
|
var results = positioned.findWithinRange(me._controller.query_range(), "airport");
|
||||||
var numResults = 0;
|
var numResults = 0;
|
||||||
foreach(result; results) {
|
foreach(result; results) {
|
||||||
if (numResults < 50) {
|
var apt = airportinfo(result.id);
|
||||||
var apt = airportinfo(result.id);
|
var runways = apt.runways;
|
||||||
var runways = apt.runways;
|
var runway_keys = sort(keys(runways),string.icmp);
|
||||||
var runway_keys = sort(keys(runways),string.icmp);
|
var validApt = 0;
|
||||||
var validApt = 0;
|
foreach(var rwy; runway_keys){
|
||||||
foreach(var rwy; runway_keys){
|
var r = runways[rwy];
|
||||||
var r = runways[rwy];
|
if (r.length > 1890) # Only display suitably large airports
|
||||||
if (r.length > 1890) # Only display suitably large airports
|
validApt = 1;
|
||||||
validApt = 1;
|
if (result.id == getprop("autopilot/route-manager/destination/airport") or result.id == getprop("autopilot/route-manager/departure/airport"))
|
||||||
if (result.id == getprop("autopilot/route-manager/destination/airport") or result.id == getprop("autopilot/route-manager/departure/airport"))
|
validApt = 1;
|
||||||
validApt = 1;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if(validApt) {
|
if(validApt) {
|
||||||
#canvas.draw_apt(me.apt_group, result.lat,result.lon,result.id,i);
|
#canvas.draw_apt(me.apt_group, result.lat,result.lon,result.id,i);
|
||||||
me.push(result);
|
me.push(result);
|
||||||
numResults += 1;
|
numResults += 1;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# set RefPos and hdg to apt !!
|
# set RefPos and hdg to apt !!
|
||||||
|
|
File diff suppressed because it is too large
Load diff
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 82 KiB |
|
@ -11,12 +11,10 @@ DMEModel.init = func {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
var results = positioned.findWithinRange(me._controller.query_range()*2 ,"dme");
|
var results = positioned.findWithinRange(me._controller.query_range() ,"dme");
|
||||||
foreach(result; results) {
|
foreach(result; results) {
|
||||||
me.push(result);
|
me.push(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
me.notifyView();
|
me.notifyView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,10 @@ FixModel.new = func make( LayerModel, FixModel );
|
||||||
FixModel.init = func {
|
FixModel.init = func {
|
||||||
me._view.reset(); # wraps removeAllChildren() ATM
|
me._view.reset(); # wraps removeAllChildren() ATM
|
||||||
|
|
||||||
var results = positioned.findWithinRange( me._controller['query_range']()*2 ,"fix");
|
var results = positioned.findWithinRange( me._controller['query_range']() ,"fix");
|
||||||
var numNum = 0;
|
var numNum = 0;
|
||||||
foreach(result; results) {
|
foreach(result; results) {
|
||||||
# Skip airport navaids (real thing makes distinction between high/low altitude fixes)
|
# Skip airport fixes
|
||||||
if(string.match(result.id,"*[^0-9]")) {
|
if(string.match(result.id,"*[^0-9]")) {
|
||||||
me.push(result);
|
me.push(result);
|
||||||
numNum = numNum + 1;
|
numNum = numNum + 1;
|
||||||
|
|
|
@ -2,7 +2,7 @@ var NavaidModel = {};
|
||||||
NavaidModel.new = func make(LayerModel, NavaidModel);
|
NavaidModel.new = func make(LayerModel, NavaidModel);
|
||||||
NavaidModel.init = func {
|
NavaidModel.init = func {
|
||||||
me._view.reset();
|
me._view.reset();
|
||||||
var navaids = findNavaidsWithinRange(15);
|
var navaids = findNavaidsWithinRange(me._controller.query_range());
|
||||||
foreach(var n; navaids)
|
foreach(var n; navaids)
|
||||||
me.push(n);
|
me.push(n);
|
||||||
me.notifyView();
|
me.notifyView();
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -4,10 +4,8 @@ RouteModel.new = func make(LayerModel, RouteModel);
|
||||||
|
|
||||||
RouteModel.init = func {
|
RouteModel.init = func {
|
||||||
me._view.reset();
|
me._view.reset();
|
||||||
if (!getprop("/autopilot/route-manager/active"))
|
if (!getprop("/autopilot/route-manager/active"))
|
||||||
print("Cannot draw route, route manager inactive!") and return;
|
return;
|
||||||
|
|
||||||
print("TODO: route.model is still an empty stub, see route.draw instead");
|
|
||||||
|
|
||||||
## TODO: all the model stuff is still inside the draw file for now, this just ensures that it will be called once
|
## TODO: all the model stuff is still inside the draw file for now, this just ensures that it will be called once
|
||||||
foreach(var t; [nil] )
|
foreach(var t; [nil] )
|
||||||
|
|
|
@ -130,7 +130,7 @@ void main (void)
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
//begin DIRT
|
//begin DIRT
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
if (dirt_enabled > 0.0){
|
if (dirt_enabled >= 1){
|
||||||
vec3 dirtFactorIn = vec3 (dirt_r_factor, dirt_g_factor, dirt_b_factor);
|
vec3 dirtFactorIn = vec3 (dirt_r_factor, dirt_g_factor, dirt_b_factor);
|
||||||
vec3 dirtFactor = reflmap.rgb * dirtFactorIn.rgb;
|
vec3 dirtFactor = reflmap.rgb * dirtFactorIn.rgb;
|
||||||
//dirtFactor.r = smoothstep(0.0, 1.0, dirtFactor.r);
|
//dirtFactor.r = smoothstep(0.0, 1.0, dirtFactor.r);
|
||||||
|
|
Loading…
Add table
Reference in a new issue