1
0
Fork 0

Merge branch 'master' of gitorious.org:fg/fgdata

This commit is contained in:
Hal V. Engel 2014-01-12 00:13:21 +00:00
commit 7f574f500d
30 changed files with 2551 additions and 3012 deletions

View file

@ -84,7 +84,13 @@ var get_aircraft_name = func( t ) {
if (mpname == nil) { return(0) }
splitname = split("/", mpname);
cutname = splitname[1];
#
# cutname = splitname[1];
#
# **** 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 );
@ -195,9 +201,3 @@ var init = func {
launched = 1;
}
}

View file

@ -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:
0 - Aileron
1 - Elevator
2 - Rudder
3 - Throttle
4 - View left-right Hat
5 - View up-down Hat
4 - View left/right hat
5 - View up/down hat
Buttons:
0 - Brakes
0 - Fire primary and secondary weapon (armament trigger).
1 - Cycle view
2 - Elevator trim up
3 - Elevator trim down
4 - Flaps down
5 - Flaps up
4 - Flaps up
5 - Mixture richer
6 - Brakes
7 - Mixture richer
7 - Flaps down
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>
<name type="string">Padix Co. Ltd. 10-Button USB Joystick</name> <!-- GNU/Linux. -->
@ -75,7 +83,7 @@ Buttons:
</axis>
<axis>
<desc>View Direction</desc>
<desc>View direction</desc>
<number>
<unix>4</unix>
<windows>6</windows>
@ -85,7 +93,7 @@ Buttons:
<repeatable>true</repeatable>
<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>
<property>/sim/current-view/goal-heading-offset-deg</property>
<step type="double">3.0</step>
@ -106,7 +114,7 @@ Buttons:
<repeatable>true</repeatable>
<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>
<property>/sim/current-view/goal-heading-offset-deg</property>
<step type="double">-3.0</step>
@ -125,7 +133,7 @@ Buttons:
</axis>
<axis>
<desc>View Elevation</desc>
<desc>View elevation</desc>
<number>
<unix>5</unix>
<windows>7</windows>
@ -136,7 +144,7 @@ Buttons:
<binding>
<command>property-adjust</command>
<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>
</low>
<high>
@ -145,28 +153,37 @@ Buttons:
<binding>
<command>property-adjust</command>
<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>
</high>
</axis>
<button n="0">
<desc>Brakes</desc>
<desc>Fire</desc>
<binding>
<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>
<mod-up>
<binding>
<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>
</mod-up>
</button>
<button n="1">
<desc>Cycle View</desc>
<desc>View cycle</desc>
<repeatable>false</repeatable>
<binding>
<command>nasal</command>
@ -196,20 +213,6 @@ Buttons:
</button>
<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>
<repeatable>false</repeatable>
<binding>
@ -224,6 +227,15 @@ Buttons:
</mod-up>
</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">
<desc>Brakes</desc>
<binding>
@ -239,12 +251,17 @@ Buttons:
</button>
<button n="7">
<desc>Mixture richer</desc>
<repeatable>true</repeatable>
<desc>Flaps down</desc>
<binding>
<command>nasal</command>
<script>controls.adjMixture(1)</script>
<script>controls.flapsDown(1)</script>
</binding>
<mod-up>
<binding>
<command>nasal</command>
<script>controls.flapsDown(0)</script>
</binding>
</mod-up>
</button>
<button n="8">
@ -266,3 +283,4 @@ Buttons:
</button>
</PropertyList>

View 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>

View file

@ -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 = {
# Static/singleton:
registry: {},
@ -29,7 +149,7 @@ Symbol.Controller = {
# Static/singleton:
registry: {},
add: func(type, class)
registry[type] = class,
me.registry[type] = class,
get: func(type)
if ((var class = me.registry[type]) == nil)
die("unknown type '"~type~"'");
@ -58,13 +178,17 @@ var getpos_fromghost = func(positioned_g)
# (geo.Coord and positioned ghost currently)
Symbol.Controller.getpos = func(obj) {
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);
else
die("bad ghost of type '"~ghosttype(obj)~"'");
if (typeof(obj) == 'hash')
if (isa(obj, geo.Coord))
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));
};
@ -82,38 +206,17 @@ var DotSym = {
element_id: nil,
# Static/singleton:
makeinstance: func(name, hash) {
assert_ms(hash,
"element_type", # type of Canvas element
#"element_id", # optional Canvas id
#"init", # initialize routine
"draw", # init/update routine
#getpos", # get position from model in [x_units,y_units] (optional)
);
hash.parents = [DotSym];
if (!isa(hash, DotSym))
die("OOP error");
#assert_ms(hash,
# "element_type", # type of Canvas element
# #"element_id", # optional Canvas id
# #"init", # initialize routine
# "draw", # init/update routine
# #getpos", # get position from model in [x_units,y_units] (optional)
#);
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:
# @param group The Canvas group to add this to.
# @param model A correct object (e.g. positioned ghost) as
@ -132,6 +235,10 @@ var DotSym = {
),
};
if (m.controller != nil) {
#print("Creating controller");
temp = m.controller.new(m.model,m);
if (temp != nil)
m.controller = temp;
#print("Initializing controller");
m.controller.init(model);
}
@ -281,9 +388,18 @@ SymbolLayer.Controller = {
die("searchCmd() not implemented for this SymbolLayer.Controller type!"),
}; # of SymbolLayer.Controller
settimer(func {
Map.Controller = {
# Static/singleton:
var AnimatedLayer = {
};
var CompassLayer = {
};
var AltitudeArcLayer = {
};
load_MapStructure = func {
Map.Controller = {
# Static/singleton:
registry: {},
add: func(type, class)
me.registry[type] = class,
@ -295,11 +411,11 @@ Map.Controller = {
# @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 #######
#print("loading files");
(func {
####### LOAD FILES #######
#print("loading files");
(func {
var FG_ROOT = getprop("/sim/fg-root");
var load = func(file, name) {
#print(file);
@ -330,44 +446,59 @@ Map.Controller = {
#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)
settimer(func {
if (caller(0)[0] != globals.canvas)
return call(caller(0)[1], arg, nil, globals.canvas);
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("Running MapStructure test code");
var TestCanvas = canvas.new({
"name": "Map Test",
"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();
foreach( var name; ['VOR','FIX','NDB','DME','WPT'] )
load_deps( name );
load(FG_ROOT~"/Nasal/canvas/map/aircraftpos.controller", name);
###
# set up a cache for 32x32 symbols
var SymbolCache32x32 = SymbolCache.new(1024,32);
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() );
};
}, 1);
}, 0); # end ugly module init timer hack
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

View file

@ -462,47 +462,45 @@ var Map = {
addLayer: func(factory, type_arg=nil, priority=nil)
{
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
if (type_arg != nil)
var type = factory.get(type_arg);
else var type = factory;
me.layers[type_arg]= type.new(me);
if (priority == nil)
priority = type.df_priority;
append(me.layers, [type.new(me), priority]);
if (priority != nil)
me._sort_priority();
me.layers[type_arg].setInt("z-index", priority);
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-lon", lon);
if (hdg != nil)
me.set("hdg", hdg);
# me.map.set("range", 100);
if (range != nil)
me.set("range", range);
},
# Update each layer on this Map. Called by
# me.controller.
update: func
{
foreach (var l; me.layers)
call(l[0].update, arg, l[0]);
foreach (var l; keys(me.layers)) {
var layer = me.layers[l];
call(layer.update, arg, layer);
}
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

View file

@ -429,10 +429,16 @@ var files_with = func(ext) {
}
return results;
}
foreach(var ext; var extensions = ['.draw','.model','.layer'])
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' );

View 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
};

View 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" );

View 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);
};

View 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
};

View 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" );

View 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);
};

View 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
};

View 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" );

View 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;
};

View file

@ -7,6 +7,7 @@ SymbolLayer.add("VOR", {
type: "VOR", # Symbol type
df_controller: __self__, # controller to use by default -- this one
});
var a_instance = nil;
var new = func(layer) {
var m = {
parents: [__self__],
@ -14,6 +15,7 @@ var new = func(layer) {
active_vors: [],
navNs: props.globals.getNode("instrumentation").getChildren("nav"),
listeners: [],
query_type:'vor',
};
setsize(m.active_vors, size(m.navNs));
foreach (var navN; m.navNs) {
@ -24,6 +26,7 @@ var new = func(layer) {
}
#call(debug.dump, keys(layer));
m.changed_freq(update:0);
__self__.a_instance = m;
return m;
};
var del = func() {
@ -46,7 +49,7 @@ var changed_freq = func(update=1) {
if (update) me.layer.update();
};
var searchCmd = func {
#print("Run query");
return positioned.findWithinRange(100, 'vor'); # the range should also be exposed, it will typically be controlled via a GUI widget or NavDisplay switch
#print("Running query:", me.query_type);
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
};

View file

@ -1,10 +1,11 @@
# Class things:
var parents = [Symbol.Controller];
var __self__ = caller(0)[0];
Symbol.Controller.add("VOR", __self__);
Symbol.registry["VOR"].df_controller = __self__;
var new = func(model) ; # this controller doesn't need an instance
var LayerController = SymbolLayer.registry["VOR"];
var isActive = func(model) LayerController.isActive(model);
var LayerController = SymbolLayer.Controller.registry["VOR"];
var isActive = func(model) LayerController.a_instance.isActive(model);
var query_range = func()
die("VOR.scontroller.query_range /MUST/ be provided by implementation");

View file

@ -1,12 +1,28 @@
# 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 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 radial_vor = nil; # if one is nil, the other has to be nil
var draw = func {
if (me.inited) {
# Init
if (me.icon_vor == nil) {
me.icon_vor = me.element.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(3)
.setColor(0,0.6,0.85);
}
# Update
if (me.controller.isActive(me.model)) {
if (me.range_vor == nil) {
@ -21,32 +37,21 @@ var draw = func {
.setStrokeDashArray([5, 15, 5, 15, 5])
.setColor(0,1,0);
var course = controller.get_tuned_course(me.model.frequency/100);
vor_grp.createChild("path")
var course = me.controller.get_tuned_course(me.model.frequency/100);
me.radial_vor = me.element.createChild("path")
.moveTo(0,-radius)
.vert(2*radius)
.setStrokeLineWidth(3)
.setStrokeDashArray([15, 5, 15, 5, 15])
.setColor(0,1,0)
.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 {
} elsif (me.range_vor != nil) {
me.range_vor.hide();
me.radial_vor.hide();
}
} else # Init
me.element.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(3)
.setColor(0,0.6,0.85);
};

View 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
};

View 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" );

View 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);
};

View file

@ -2,14 +2,11 @@ var AirportsNDModel = {};
AirportsNDModel.new = func make(AirportsNDModel, LayerModel);
AirportsNDModel.init = func {
#print("Updating AirportsNDModel");
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;
foreach(result; results) {
if (numResults < 50) {
var apt = airportinfo(result.id);
var runways = apt.runways;
var runway_keys = sort(keys(runways),string.icmp);
@ -28,7 +25,6 @@ AirportsNDModel.init = func {
numResults += 1;
}
}
}
# set RefPos and hdg to apt !!
# me._map_handle.setRefPos(apt.lat, apt.lon);

File diff suppressed because it is too large Load diff

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 82 KiB

View file

@ -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) {
me.push(result);
}
me.notifyView();
}

View file

@ -4,10 +4,10 @@ FixModel.new = func make( LayerModel, FixModel );
FixModel.init = func {
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;
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]")) {
me.push(result);
numNum = numNum + 1;

View file

@ -2,7 +2,7 @@ var NavaidModel = {};
NavaidModel.new = func make(LayerModel, NavaidModel);
NavaidModel.init = func {
me._view.reset();
var navaids = findNavaidsWithinRange(15);
var navaids = findNavaidsWithinRange(me._controller.query_range());
foreach(var n; navaids)
me.push(n);
me.notifyView();

View file

@ -2,14 +2,10 @@
# Boeing Navigation Display by Gijs de Rooy
# ==============================================================================
##
# do we really need to keep track of each drawable here ??
var i = 0;
##
# pseudo DSL-ish: use these as placeholders in the config hash below
var ALWAYS = func 1;
@ -27,15 +23,12 @@ var trigger_update = func(layer) layer._model.init();
# any aircraft-specific ND behavior should be wrapped here,
# to isolate/decouple things in the generic NavDisplay class
#
# Note to Gijs: this may look weird and confusing, but it' actually requires
# less coding now, and it is now even possible to configure things via a little
# XML wrapper
# TODO: move this to an XML config file
#
var NDStyles = {
##
# this configures the 744 ND to help generalize the NavDisplay class itself
'B747-400': {
'Boeing': {
font_mapper: func(family, weight) {
if( family == "Liberation Sans" and weight == "normal" )
return "LiberationFonts/LiberationSans-Regular.ttf";
@ -46,97 +39,138 @@ var NDStyles = {
# aircraft developers should all be editing the same ND.svg image
# the code can deal with the differences now
svg_filename: "Nasal/canvas/map/boeingND.svg",
##
## this loads and configures existing layers (currently, *.layer files in Nasal/canvas/map)
##
##
## this loads and configures existing layers (currently, *.layer files in Nasal/canvas/map)
##
layers: [
{ name:'fixes', update_on:['toggle_range','toggle_waypoints','toggle_display_mode'], predicate: func(nd, layer) {
{ name:'fixes', disabled:1, update_on:['toggle_range','toggle_waypoints'],
predicate: func(nd, layer) {
# print("Running fixes predicate");
var visible=nd.get_switch('toggle_waypoints') and nd.in_mode('toggle_display_mode', ['MAP']);
if(nd.rangeNm() <= 40 and visible) {
var visible=nd.get_switch('toggle_waypoints') and nd.in_mode('toggle_display_mode', ['MAP']) and (nd.rangeNm() <= 40);
if (visible) {
# print("fixes update requested!");
trigger_update( layer );
} layer._view.setVisible(visible);
}
layer._view.setVisible(visible);
}, # end of layer update predicate
}, # end of fixes layer
{ name:'FIX', isMapStructure:1, update_on:['toggle_range','toggle_waypoints'],
# FIXME: this is a really ugly place for controller code
predicate: func(nd, layer) {
# print("Running vor layer predicate");
# toggle visibility here
var visible=nd.get_switch('toggle_waypoints') and nd.in_mode('toggle_display_mode', ['MAP']) and (nd.rangeNm() <= 40);
layer.group.setVisible( nd.get_switch('toggle_waypoints') );
if (visible) {
#print("Updating MapStructure ND layer: FIX");
# (Hopefully) smart update
layer.update();
}
}, # end of layer update predicate
}, # end of FIX layer
# Should redraw every 10 seconds
{ name:'storms', update_on:['toggle_range','toggle_weather','toggle_display_mode'], predicate: func(nd, layer) {
{ name:'storms', update_on:['toggle_range','toggle_weather','toggle_display_mode'],
predicate: func(nd, layer) {
# print("Running fixes predicate");
var visible=nd.get_switch('toggle_weather') and nd.get_switch('toggle_display_mode') != "PLAN";
if (visible) {
#print("storms update requested!");
trigger_update( layer );
} layer._view.setVisible(visible);
}
layer._view.setVisible(visible);
}, # end of layer update predicate
}, # end of storms layer
{ name:'airplaneSymbol', update_on:['toggle_range','toggle_display_mode'], predicate: func(nd, layer) {
# print("Running fixes predicate");
var visible=nd.get_switch('toggle_display_mode') == "PLAN";
if (visible) {
trigger_update( layer );
} layer._view.setVisible(visible);
}, # end of layer update predicate
}, # end of storms layer
{ name:'airports-nd', update_on:['toggle_range','toggle_airports','toggle_display_mode'], predicate: func(nd, layer) {
{ name:'airports-nd', update_on:['toggle_range','toggle_airports','toggle_display_mode'],
predicate: func(nd, layer) {
# print("Running airports-nd predicate");
var visible = nd.get_switch('toggle_airports') and nd.in_mode('toggle_display_mode', ['MAP']);
if (nd.rangeNm() <= 80 and visible) {
if (visible) {
trigger_update( layer ); # clear & redraw
}
layer._view.setVisible( visible);
layer._view.setVisible( visible );
}, # end of layer update predicate
}, # end of airports layer
{ name:'vor', update_on:['toggle_range','toggle_stations','toggle_display_mode'], predicate: func(nd, layer) {
var visible = nd.get_switch('toggle_stations') and nd.in_mode('toggle_display_mode', ['MAP']);
if(nd.rangeNm() <= 40 and visible) {
# Should distinct between low and high altitude navaids. Hiding above 40 NM for now, to prevent clutter/lag.
{ name:'vor', disabled:1, update_on:['toggle_range','toggle_stations','toggle_display_mode'],
predicate: func(nd, layer) {
# print("Running vor layer predicate");
var visible = nd.get_switch('toggle_stations') and nd.in_mode('toggle_display_mode', ['MAP']) and (nd.rangeNm() <= 40);
if(visible) {
trigger_update( layer ); # clear & redraw
}
layer._view.setVisible( visible );
layer._view.setVisible( nd.get_switch('toggle_stations') );
}, # end of layer update predicate
}, # end of VOR layer
{ name:'VOR', isMapStructure:1, update_on:['toggle_range','toggle_stations','toggle_display_mode'],
# FIXME: this is a really ugly place for controller code
predicate: func(nd, layer) {
# print("Running vor layer predicate");
# toggle visibility here
var visible = nd.get_switch('toggle_stations') and nd.in_mode('toggle_display_mode', ['MAP']) and (nd.rangeNm() <= 40);
layer.group.setVisible( visible );
if (visible) {
#print("Updating MapStructure ND layer: VOR");
# (Hopefully) smart update
layer.update();
}
}, # end of layer update predicate
}, # end of VOR layer
{ name:'dme', update_on:['toggle_range','toggle_stations','toggle_display_mode'], predicate: func(nd, layer) {
var visible = nd.get_switch('toggle_stations') and nd.in_mode('toggle_display_mode', ['MAP']);
if(nd.rangeNm() <= 40 and visible){
# Should distinct between low and high altitude navaids. Hiding above 40 NM for now, to prevent clutter/lag.
{ name:'dme', disabled:1, update_on:['toggle_range','toggle_stations'],
predicate: func(nd, layer) {
var visible = nd.get_switch('toggle_stations') and nd.in_mode('toggle_display_mode', ['MAP']) and (nd.rangeNm() <= 40);
if(visible) {
trigger_update( layer ); # clear & redraw
}
layer._view.setVisible( visible );
layer._view.setVisible( nd.get_switch('toggle_stations') );
}, # end of layer update predicate
}, # end of DME layers
{ name:'DME', isMapStructure:1, update_on:['toggle_range','toggle_stations'],
# FIXME: this is a really ugly place for controller code
predicate: func(nd, layer) {
# print("Running vor layer predicate");
# toggle visibility here
layer.group.setVisible( nd.get_switch('toggle_stations') );
if (nd.rangeNm() <= 40 and
nd.get_switch('toggle_stations') and
nd.get_switch('toggle_display_mode') == "MAP") {
#print("Updating MapStructure ND layer: DME");
# (Hopefully) smart update
layer.update();
}
}, # end of layer update predicate
}, # end of DME layer
{ name:'mp-traffic', update_on:['toggle_range','toggle_traffic'], predicate: func(nd, layer) {
{ name:'mp-traffic', update_on:['toggle_range','toggle_traffic'],
predicate: func(nd, layer) {
trigger_update( layer ); # clear & redraw
layer._view.setVisible( nd.get_switch('toggle_traffic') );
layer._view.setVisible( 1 ); #nd.get_switch('toggle_traffic')
}, # end of layer update predicate
}, # end of traffic layer
{ name:'runway-nd', update_on:['toggle_range','toggle_display_mode'], predicate: func(nd, layer) {
var visible = (nd.rangeNm() <= 40 and getprop("autopilot/route-manager/active") and nd.in_mode('toggle_display_mode', ['MAP','PLAN'])) ;
{ name:'runway-nd', update_on:['toggle_range','toggle_display_mode'],
predicate: func(nd, layer) {
var visible = (nd.rangeNm() <= 40 and getprop("autopilot/route-manager/active") ) ;
if (visible)
trigger_update( layer ); # clear & redraw
layer._view.setVisible( visible );
}, # end of layer update predicate
}, # end of airports-nd layer
{ name:'route', update_on:['toggle_display_mode',], predicate: func(nd, layer) {
var visible= (nd.in_mode('toggle_display_mode', ['MAP','PLAN']));
if (visible) {
{ name:'route', update_on:['toggle_range','toggle_display_mode'],
predicate: func(nd, layer) {
trigger_update( layer ); # clear & redraw
}
layer._view.setVisible( visible );
layer._view.setVisible( 1 ); #nd.get_switch('toggle_traffic')
}, # end of layer update predicate
}, # end of route layer
## add other layers here, layer names must match the registered names as used in *.layer files for now
## this will all change once we're using Philosopher's MapStructure framework
## add other layers here, layer names must match the registered names as used in *.layer files for now
## this will all change once we're using Philosopher's MapStructure framework
], # end of vector with configured layers
@ -146,7 +180,8 @@ var NDStyles = {
# SVG identifier, callback etc
# TODO: update_on([]), update_mode (update() vs. timers/listeners)
# TODO: support putting symbols on specific layers
features: [ {
features: [
{
# TODO: taOnly doesn't need to use getprop polling in update(), use a listener instead!
id: 'taOnly', # the SVG ID
impl: { # implementation hash
@ -211,7 +246,8 @@ var NDStyles = {
is_false: func(nd) nd.symbols.eta.hide(),
}, # of eta.impl
}, # of eta
{ id:'hdg',
{
id:'hdg',
impl: {
init: func(nd,symbol),
predicate: ALWAYS, # always true
@ -219,8 +255,8 @@ var NDStyles = {
is_false: NOTHING,
}, # of hdg.impl
}, # of hdg
{ id:'gs',
{
id:'gs',
impl: {
init: func(nd,symbol),
common: func(nd) nd.symbols.gs.setText(sprintf("%3.0f",nd.aircraft_source.get_spd() )),
@ -231,29 +267,29 @@ var NDStyles = {
is_false: func(nd) nd.symbols.gs.setFontSize(52),
}, # of gs.impl
}, # of gs
{ id:'rangeArcs',
{
id:'rangeArcs',
impl: {
init: func(nd,symbol),
predicate: func(nd) ((nd.in_mode('toggle_display_mode', ['APP','VOR']) and nd.get_switch('toggle_weather')) or (nd.get_switch('toggle_display_mode') == "MAP" and !nd.get_switch('toggle_centered'))),
predicate: func(nd) (((nd.get_switch('toggle_display_mode') == "APP" or nd.get_switch('toggle_display_mode') == "VOR") and nd.get_switch('toggle_weather')) or nd.get_switch('toggle_display_mode') == "MAP"),
is_true: func(nd) nd.symbols.rangeArcs.show(),
is_false: func(nd) nd.symbols.rangeArcs.hide(),
}, # of rangeArcs.impl
}, # of rangeArcs
], # end of vector with features
}, # end of 744 ND style
}, # end of Boeing style
#####
##
## add support for other aircraft/ND types and styles here (737, 757, 777 etc)
## add support for other aircraft/ND types and styles here (Airbus etc)
##
##
}; # end of NDStyles
##
# encapsulate hdg/lat/lon source, so that the ND may also display AI/MP aircraft in a pilot-view at some point (aka stress-testing)
#
@ -263,16 +299,36 @@ NDSourceDriver.new = func {
var m = {parents:[NDSourceDriver]};
m.get_hdg_mag= func getprop("/orientation/heading-magnetic-deg");
m.get_hdg_tru= func getprop("/orientation/heading-deg");
m.get_trk_mag= func getprop("/orientation/track-magnetic-deg");
m.get_trk_tru= func getprop("/orientation/track-deg");
m.get_hgg = func getprop("instrumentation/afds/settings/heading");
m.get_trk_mag= func
{
if(getprop("/velocities/groundspeed-kt") > 80)
{
getprop("/orientation/track-magnetic-deg");
}
else
{
getprop("/orientation/heading-magnetic-deg");
}
};
m.get_trk_tru = func
{
if(getprop("/velocities/groundspeed-kt") > 80)
{
getprop("/orientation/track-deg");
}
else
{
getprop("/orientation/heading-deg");
}
};
m.get_lat= func getprop("/position/latitude-deg");
m.get_lon= func getprop("/position/longitude-deg");
m.get_spd= func getprop("/velocities/groundspeed-kt");
m.get_vspd= func getprop("/velocities/vertical-speed-fps");
return m;
return m;
}
##
# configure aircraft specific cockpit switches here
# these are some defaults, can be overridden when calling NavDisplay.new() -
@ -284,7 +340,7 @@ return m;
# TODO: switches are ND specific, so move to the NDStyle hash!
var default_switches = {
'toggle_range': {path: '/inputs/range-nm', value:10, type:'INT'},
'toggle_range': {path: '/inputs/range-nm', value:40, type:'INT'},
'toggle_weather': {path: '/inputs/wxr', value:0, type:'BOOL'},
'toggle_airports': {path: '/inputs/arpt', value:0, type:'BOOL'},
'toggle_stations': {path: '/inputs/sta', value:0, type:'BOOL'},
@ -292,9 +348,12 @@ var default_switches = {
'toggle_position': {path: '/inputs/pos', value:0, type:'BOOL'},
'toggle_data': {path: '/inputs/data',value:0, type:'BOOL'},
'toggle_terrain': {path: '/inputs/terr',value:0, type:'BOOL'},
'toggle_traffic': {path: '/inputs/tfc',value:0, type:'BOOL'},
'toggle_traffic': {path: '/inputs/tcas',value:0, type:'BOOL'},
'toggle_centered': {path: '/inputs/nd-centered',value:0, type:'BOOL'},
'toggle_display_mode': {path: '/mfd/display-mode', value:'MAP', type:'STRING'},
'toggle_lh_vor_adf': {path: '/inputs/lh-vor-adf',value:0, type:'INT'},
'toggle_rh_vor_adf': {path: '/inputs/rh-vor-adf',value:0, type:'INT'},
'toggle_display_mode': {path: '/mfd/display-mode', value:'MAP', type:'STRING'}, # valid values are: APP, MAP, PLAN or VOR
'toggle_display_type': {path: '/mfd/display-type', value:'CRT', type:'STRING'}, # valid values are: CRT or LCD
'toggle_true_north': {path: '/mfd/true-north', value:0, type:'BOOL'},
};
@ -341,7 +400,6 @@ var NavDisplay = {
# print("listen_switch triggered:", s, " callback id:", id(c) );
c();
});
},
# get the full property path for a given switch
@ -363,19 +421,16 @@ var NavDisplay = {
connectAI: func(source=nil) {
me.aircraft_source = {
get_hdg_mag: func source.getNode('orientation/heading-magnetic-deg').getValue(),
get_hdg_tru: func source.getNode('orientation/heading-deg').getValue(),
get_trk_mag: func source.getNode('orientation/track-magnetic-deg').getValue(),
get_trk_tru: func source.getNode('orientation/track-deg').getValue(),
get_lat: func source.getNode('position/latitude-deg').getValue(),
get_lon: func source.getNode('position/longitude-deg').getValue(),
get_spd: func source.getNode('velocities/true-airspeed-kt').getValue(),
get_vspd: func source.getNode('velocities/vertical-speed-fps').getValue(),
};
}, # of connectAI
# TODO: the ctor should allow customization, for different aircraft
# especially properties and SVG files/handles (747, 757, 777 etc)
new : func(prop1, switches=default_switches, style='B747-400') {
new : func(prop1, switches=default_switches, style='Boeing') {
var m = { parents : [NavDisplay]};
m.listeners=[]; # for cleanup handling
@ -384,11 +439,11 @@ var NavDisplay = {
m.nd_style = NDStyles[style]; # look up ND specific stuff (file names etc)
m.radio_list=["instrumentation/comm/frequencies","instrumentation/comm[1]/frequencies",
"instrumentation/nav/frequencies","instrumentation/nav[1]/frequencies"];
"instrumentation/nav/frequencies", "instrumentation/nav[1]/frequencies"];
m.mfd_mode_list=["APP","VOR","MAP","PLAN"];
m.efis_path = prop1;
m.efis_switches = switches ;
m.efis_switches = switches;
# just an alias, to avoid having to rewrite the old code for now
m.rangeNm = func m.get_switch('toggle_range');
@ -397,17 +452,15 @@ var NavDisplay = {
m.mfd = m.efis.initNode("mfd");
# TODO: unify this with switch handling
m.mfd_mode_num = m.mfd.initNode("mode-num",2,"INT");
m.mfd_display_mode = m.mfd.initNode("display-mode",m.mfd_mode_list[2],"STRING");
m.mfd_mode_num = m.mfd .initNode("mode-num",2,"INT");
m.std_mode = m.efis.initNode("inputs/setting-std",0,"BOOL");
m.previous_set = m.efis.initNode("inhg-previos",29.92); # watch out typo here, check other files before fixing !
m.previous_set = m.efis.initNode("inhg-previous",29.92);
m.kpa_mode = m.efis.initNode("inputs/kpa-mode",0,"BOOL");
m.kpa_output = m.efis.initNode("inhg-kpa",29.92);
m.kpa_prevoutput = m.efis.initNode("inhg-kpa-previous",29.92);
m.temp = m.efis.initNode("fixed-temp",0);
m.alt_meters = m.efis.initNode("inputs/alt-meters",0,"BOOL");
m.fpv = m.efis.initNode("inputs/fpv",0,"BOOL");
m.nd_centered = m.efis.initNode("inputs/nd-centered",0,"BOOL");
m.mins_mode = m.efis.initNode("inputs/minimums-mode",0,"BOOL");
m.mins_mode_txt = m.efis.initNode("minimums-mode-text","RADIO","STRING");
@ -415,10 +468,7 @@ var NavDisplay = {
m.mk_minimums = props.globals.getNode("instrumentation/mk-viii/inputs/arinc429/decision-height");
# TODO: these are switches, can be unified with switch handling hash above (eventually):
m.rh_vor_adf = m.efis.initNode("inputs/rh-vor-adf",0,"INT"); # not yet in switches hash
m.lh_vor_adf = m.efis.initNode("inputs/lh-vor-adf",0,"INT"); # not yet in switches hash
m.nd_plan_wpt = m.efis.initNode("inputs/plan-wpt-index", 0, "INT"); # ditto
m.nd_plan_wpt = m.efis.initNode("inputs/plan-wpt-index", 0, "INT"); # not yet in switches hash
###
# initialize all switches based on the defaults specified in the switch hash
@ -435,17 +485,13 @@ var NavDisplay = {
},
newMFD: func(canvas_group)
{
me.listen("/sim/signals/reinit", func me.handle_reinit() );
me.update_timer = maketimer(0.05, func me.update() ); # TODO: make interval configurable via ctor
me.nd = canvas_group;
# load the specified SVG file into the me.nd group and populate all sub groups
canvas.parsesvg(me.nd, me.nd_style.svg_filename, {'font-mapper': me.nd_style.font_mapper});
me.symbols = {}; # storage for SVG elements, to avoid namespace pollution (all SVG elements end up here)
foreach(var feature; me.nd_style.features ) {
@ -457,27 +503,28 @@ var NavDisplay = {
### this is the "old" method that's less flexible, we want to use the style hash instead (see above)
# because things are much better configurable that way
# now look up all required SVG elements and initialize member fields using the same name to have a convenient handle
foreach(var element; ["wind",
"dmeLDist","dmeRDist","vorLId","vorRId",
"range","status.wxr","status.wpt",
"status.sta","status.arpt"])
foreach(var element; ["wind","dmeLDist","dmeRDist","dmeL","dmeR","vorL","vorR","vorLId","vorRId",
"range","status.wxr","status.wpt","hdgGroup","status.sta","status.arpt"])
me.symbols[element] = me.nd.getElementById(element);
# load elements from vector image, and create instance variables using identical names, and call updateCenter() on each
# anything that needs updatecenter called, should be added to the vector here
#
foreach(var element; ["rotateComp","rotateComp2","windArrow","selHdg","selHdg2","hdgGroup","northUp",
"aplSymMap","aplSymMapCtr","aplSymVor","curHdgPtr","curHdgPtr2",
"staFromL","staToL","staFromR","staToR","staFromL2","staToL2","staFromR2","staToR2",
"trkInd","vorCrsPtr2","locPtr","compass","compassApp","hdgTrk","truMag","altArc","planArcs"] )
foreach(var element; ["windArrow","compassApp","northUp","aplSymMap","aplSymMapCtr","aplSymVor",
"staFromL2","staToL2","staFromR2","staToR2",
"locPtr","hdgTrk","truMag","altArc","planArcs",
"trkInd","compass","HdgBugCRT","TrkBugLCD","HdgBugLCD","selHdgLine","curHdgPtr",
"staFromL","staToL","staFromR","staToR"] )
me.symbols[element] = me.nd.getElementById(element).updateCenter();
foreach(var element; ["HdgBugCRT2","TrkBugLCD2","HdgBugLCD2","selHdgLine2","curHdgPtr2","vorCrsPtr2"] )
me.symbols[element] = me.nd.getElementById(element).setCenter(512,565);
# this should probably be using Philosopher's new SymbolLayer ?
me.map = me.nd.createChild("map","map")
.set("clip", "rect(124, 1024, 1024, 0)");
# this callback will be passed onto the model via the controller hash, and used for the positioned queries, to specify max query range:
var get_range = func me.get_switch('toggle_range');
# predicate for the draw controller
@ -507,12 +554,18 @@ var NavDisplay = {
# so we need some simple way to communicate between frontend<->backend until we have real controllers
# for now, a single controller hash is shared by most layers - unsupported callbacks are simply ignored by the draw files
#
var controller = { query_range: func get_range(),
var controller = {
query_range: func get_range(),
is_tuned:is_tuned,
get_tuned_course:get_course_by_freq,
get_position: get_current_position,
};
# FIXME: MapStructure: big hack
canvas.Symbol.Controller.get("VOR").query_range = controller.query_range;
canvas.Symbol.Controller.get("VOR").get_tuned_course = controller.get_tuned_course;
canvas.Symbol.Controller.get("DME").is_tuned = controller.is_tuned;
###
# set up various layers, controlled via callbacks in the controller hash
# revisit this code once Philosopher's "Smart MVC Symbols/Layers" work is committed and integrated
@ -522,27 +575,34 @@ var NavDisplay = {
me.layers={}; # storage container for all ND specific layers
# look up all required layers as specified per the NDStyle hash and do the initial setup for event handling
foreach(var layer; me.nd_style.layers) {
print("newMFD(): Setting up ND layer:", layer.name);
if(layer['disabled']) continue; # skip this layer
#print("newMFD(): Setting up ND layer:", layer.name);
# huge hack for the alt-arc, which is not rendered as a map group, but directly as part of the toplevel ND group
var render_target = (!contains(layer,'not_a_map') or !layer.not_a_map) ? me.map : me.nd;
var the_layer = me.layers[layer.name] = canvas.MAP_LAYERS[layer.name].new( render_target, layer.name, controller );
var the_layer = nil;
if(!layer['isMapStructure'])
the_layer = me.layers[layer.name] = canvas.MAP_LAYERS[layer.name].new( render_target, layer.name, controller );
else {
#print("Setting up MapStructure-based layer for ND, name:", layer.name);
render_target.addLayer(factory: canvas.SymbolLayer, type_arg: layer.name);
the_layer = me.layers[layer.name] = render_target.getLayer(layer.name);
}
# now register all layer specific notification listeners and their corresponding update predicate/callback
# pass the ND instance and the layer handle to the predicate when it is called
# so that it can directly access the ND instance and its own layer (without having to know the layer's name)
var event_handler = make_event_handler(layer.predicate, the_layer);
foreach(var event; layer.update_on) {
# print("Setting up subscription:", event, " for ", layer.name, " handler id:", id(event_handler) );
me.listen_switch(event, event_handler ) ;
me.listen_switch(event, event_handler);
} # foreach event subscription
# and now update/init each layer once by calling its update predicate for initialization
event_handler();
} # foreach layer
print("navdisplay.mfd:ND layer setup completed");
#print("navdisplay.mfd:ND layer setup completed");
# start the update timer, which makes sure that the update() will be called
me.update_timer.start();
@ -550,19 +610,21 @@ var NavDisplay = {
# next, radio & autopilot & listeners
# TODO: move this to .init field in layers hash or to model files
foreach(var n; var radios = [ "instrumentation/nav/frequencies/selected-mhz",
foreach(var n; var radios = [
"instrumentation/nav/frequencies/selected-mhz",
"instrumentation/nav[1]/frequencies/selected-mhz"])
me.listen(n, func() {
me.drawvor();
me.drawdme();
# me.drawvor();
# me.drawdme();
});
# TODO: move this to the route.model
# Hack to draw the route on rm activation
me.listen("/autopilot/route-manager/active", func(active) {
if(active.getValue()) {
setprop(me.get_full_switch_path('toggle_display_mode'),getprop(me.get_full_switch_path('toggle_display_mode')));
me.drawroute();
me.drawrunways();
} else {
print("TODO: navdisplay.mfd: implement route-manager/layer clearing!");
#print("TODO: navdisplay.mfd: implement route-manager/layer clearing!");
#me.route_group.removeAllChildren(); # HACK!
}
});
@ -574,18 +636,16 @@ var NavDisplay = {
drawroute: func print("drawroute no longer used!"),
drawrunways: func print("drawrunways no longer used!"),
in_mode:func(switch, modes) {
foreach(var m; modes)
if (me.get_switch(switch)==m) return 1;
in_mode:func(switch, modes)
{
foreach(var m; modes) if(me.get_switch(switch)==m) return 1;
return 0;
},
# each model should keep track of when it last got updated, using current lat/lon
# in update(), we can then check if the aircraft has traveled more than 0.5-1 nm (depending on selected range)
# and update each model accordingly
update: func() # FIXME: This stuff is still too aircraft specific, cannot easily be reused by other aircraft
{
##
# important constants
var m1 = 111132.92;
@ -599,13 +659,12 @@ var NavDisplay = {
var lonNm = 60;
# fgcommand('profiler-start');
# Heading update
var userHdgMag = me.aircraft_source.get_hdg_mag();
var userHdgTru = me.aircraft_source.get_hdg_tru();
var userTrkMag = me.aircraft_source.get_trk_mag();
var userTrkTru = me.aircraft_source.get_trk_tru();
if (me.get_switch('toggle_true_north')) {
if(me.get_switch('toggle_true_north')) {
me.symbols.truMag.setText("TRU");
var userHdg=userHdgTru;
var userTrk=userTrkTru;
@ -616,11 +675,11 @@ var NavDisplay = {
}
if (me.aircraft_source.get_spd() < 80)
userTrk = userHdg;
var userLat = me.aircraft_source.get_lat();
var userLon = me.aircraft_source.get_lon();
var userSpd = me.aircraft_source.get_spd();
var userVSpd = me.aircraft_source.get_vspd();
var dispLCD = me.get_switch('toggle_display_type') == "LCD";
# this should only ever happen when testing the experimental AI/MP ND driver hash (not critical)
if (!userHdg or !userTrk or !userLat or !userLon) {
@ -628,11 +687,12 @@ var NavDisplay = {
return;
}
if (me.get_switch('toggle_centered') or me.in_mode('toggle_display_mode', ['PLAN']))
if(me.in_mode('toggle_display_mode', ['PLAN']))
me.map.setTranslation(512,512);
elsif(me.get_switch('toggle_centered'))
me.map.setTranslation(512,565);
else
me.map.setTranslation(512,824);
# Calculate length in NM of one degree at current location TODO: expose as methods, for external callbacks
var userLatR = userLat*D2R;
var userLonR = userLon*D2R;
@ -641,23 +701,78 @@ var NavDisplay = {
latNm = latlen*M2NM; #60 at equator
lonNm = lonlen*M2NM; #60 at equator
me.symbols.windArrow.setRotation((getprop("/environment/wind-from-heading-deg")-userHdgMag)*D2R);
me.symbols.windArrow.setRotation((getprop("/environment/wind-from-heading-deg")-userHdg)*D2R);
me.symbols.wind.setText(sprintf("%3.0f / %2.0f",getprop("/environment/wind-from-heading-deg"),getprop("/environment/wind-speed-kt")));
if ((var navid0=getprop("instrumentation/nav/nav-id"))!=nil )
me.symbols.vorLId.setText(navid0);
if ((var navid1=getprop("instrumentation/nav[1]/nav-id"))!=nil )
me.symbols.vorRId.setText(navid1);
if((var nav0dist=getprop("instrumentation/nav/nav-distance"))!=nil )
me.symbols.dmeLDist.setText(sprintf("%3.1f",nav0dist*0.000539));
if((var nav1dist=getprop("instrumentation/nav[1]/nav-distance"))!=nil )
me.symbols.dmeRDist.setText(sprintf("%3.1f",nav1dist*0.000539));
if(me.get_switch('toggle_lh_vor_adf') == 1)
{
me.symbols.vorL.setText("VOR L");
me.symbols.vorL.setColor(0.195,0.96,0.097);
me.symbols.dmeL.setText("DME");
me.symbols.dmeL.setColor(0.195,0.96,0.097);
if(getprop("instrumentation/nav/in-range"))
me.symbols.vorLId.setText(getprop("instrumentation/nav/nav-id"));
else
me.symbols.vorLId.setText(getprop("instrumentation/nav/frequencies/selected-mhz-fmt"));
me.symbols.vorLId.setColor(0.195,0.96,0.097);
if(getprop("instrumentation/nav/dme-in-range"))
me.symbols.dmeLDist.setText(sprintf("%3.1f",getprop("instrumentation/nav/nav-distance")*0.000539));
else me.symbols.dmeLDist.setText(" ---");
me.symbols.dmeLDist.setColor(0.195,0.96,0.097);
} elsif(me.get_switch('toggle_lh_vor_adf') == -1) {
me.symbols.vorL.setText("ADF L");
me.symbols.vorL.setColor(0,0.6,0.85);
me.symbols.dmeL.setText("");
me.symbols.dmeL.setColor(0,0.6,0.85);
if((var navident=getprop("instrumentation/adf/ident")) != "")
me.symbols.vorLId.setText(navident);
else me.symbols.vorLId.setText(sprintf("%3d",getprop("instrumentation/adf/frequencies/selected-khz")));
me.symbols.vorLId.setColor(0,0.6,0.85);
me.symbols.dmeLDist.setText("");
me.symbols.dmeLDist.setColor(0,0.6,0.85);
} else {
me.symbols.vorL.setText("");
me.symbols.dmeL.setText("");
me.symbols.vorLId.setText("");
me.symbols.dmeLDist.setText("");
}
if(me.get_switch('toggle_rh_vor_adf') == 1) {
me.symbols.vorR.setText("VOR R");
me.symbols.vorR.setColor(0.195,0.96,0.097);
me.symbols.dmeR.setText("DME");
me.symbols.dmeR.setColor(0.195,0.96,0.097);
if(getprop("instrumentation/nav[1]/in-range"))
me.symbols.vorRId.setText(getprop("instrumentation/nav[1]/nav-id"));
else
me.symbols.vorRId.setText(getprop("instrumentation/nav[1]/frequencies/selected-mhz-fmt"));
me.symbols.vorRId.setColor(0.195,0.96,0.097);
if(getprop("instrumentation/nav[1]/dme-in-range"))
me.symbols.dmeRDist.setText(sprintf("%3.1f",getprop("instrumentation/nav[1]/nav-distance")*0.000539));
else me.symbols.dmeRDist.setText(" ---");
me.symbols.dmeRDist.setColor(0.195,0.96,0.097);
} elsif(me.get_switch('toggle_rh_vor_adf') == -1) {
me.symbols.vorR.setText("ADF R");
me.symbols.vorR.setColor(0,0.6,0.85);
me.symbols.dmeR.setText("");
me.symbols.dmeR.setColor(0,0.6,0.85);
if((var navident=getprop("instrumentation/adf[1]/ident")) != "")
me.symbols.vorRId.setText(navident);
else me.symbols.vorRId.setText(sprintf("%3d",getprop("instrumentation/adf[1]/frequencies/selected-khz")));
me.symbols.vorRId.setColor(0,0.6,0.85);
me.symbols.dmeRDist.setText("");
me.symbols.dmeRDist.setColor(0,0.6,0.85);
} else {
me.symbols.vorR.setText("");
me.symbols.dmeR.setText("");
me.symbols.vorRId.setText("");
me.symbols.dmeRDist.setText("");
}
me.symbols.range.setText(sprintf("%3.0f",me.rangeNm() ));
me.symbols.range.setText(sprintf("%3.0f",me.rangeNm()/2));
# reposition the map, change heading & range:
if(me.in_mode('toggle_display_mode', ['PLAN'])) {
me.symbols.windArrow.hide();
me.symbols.windArrow.setVisible(!dispLCD);
me.map._node.getNode("hdg",1).setDoubleValue(0);
if (getprop(me.efis_path ~ "/inputs/plan-wpt-index") >= 0) {
me.map._node.getNode("ref-lat",1).setDoubleValue(getprop("/autopilot/route-manager/route/wp["~getprop(me.efis_path ~ "/inputs/plan-wpt-index")~"]/latitude-deg"));
@ -668,26 +783,37 @@ var NavDisplay = {
me.map._node.getNode("ref-lat",1).setDoubleValue(userLat);
me.map._node.getNode("ref-lon",1).setDoubleValue(userLon);
}
me.map._node.getNode("range",1).setDoubleValue(me.rangeNm()/2); # avoid this here, use a listener instead
# The set range of the map does not correspond to what we see in-sim!!
me.map._node.getNode("range",1).setDoubleValue(me.rangeNm()/3.2); # avoid this here, use a listener instead
var vhdg_bug = getprop("autopilot/settings/heading-bug-deg");
if(me.in_mode('toggle_display_mode', ['MAP'])) {
me.symbols.rotateComp.setRotation(-userTrk*D2R);
me.symbols.rotateComp2.setRotation(-userTrk*D2R);
me.symbols.HdgBugCRT.setRotation((vhdg_bug-userTrk)*D2R);
me.symbols.HdgBugLCD.setRotation((vhdg_bug-userTrk)*D2R);
me.symbols.TrkBugLCD.setRotation((vhdg_bug-userTrk)*D2R);
me.symbols.selHdgLine.setRotation((vhdg_bug-userTrk)*D2R);
me.symbols.HdgBugCRT2.setRotation((vhdg_bug-userTrk)*D2R);
me.symbols.TrkBugLCD2.setRotation((vhdg_bug-userTrk)*D2R);
me.symbols.selHdgLine2.setRotation((vhdg_bug-userTrk)*D2R);
me.symbols.trkInd.setRotation(0);
me.symbols.curHdgPtr.setRotation(userHdg*D2R);
me.symbols.curHdgPtr2.setRotation(userHdg*D2R);
me.map._node.getNode("hdg",1).setDoubleValue(userTrk);
me.symbols.curHdgPtr.setRotation((userHdg-userTrk)*D2R);
me.symbols.curHdgPtr2.setRotation((userHdg-userTrk)*D2R);
me.map._node.getNode("hdg",1).setDoubleValue(userTrkTru);
me.symbols.compass.setRotation(-userTrk*D2R);
me.symbols.compassApp.setRotation(-userTrk*D2R);
me.symbols.hdgTrk.setText("TRK");
}
if(me.in_mode('toggle_display_mode', ['APP','VOR'])) {
me.symbols.rotateComp.setRotation(-userHdg*D2R);
me.symbols.rotateComp2.setRotation(-userHdg*D2R);
me.symbols.HdgBugCRT.setRotation((vhdg_bug-userHdg)*D2R);
me.symbols.HdgBugLCD.setRotation((vhdg_bug-userHdg)*D2R);
me.symbols.selHdgLine.setRotation((vhdg_bug-userHdg)*D2R);
me.symbols.HdgBugCRT2.setRotation((vhdg_bug-userHdg)*D2R);
me.symbols.HdgBugLCD2.setRotation((vhdg_bug-userHdg)*D2R);
me.symbols.selHdgLine2.setRotation((vhdg_bug-userHdg)*D2R);
me.symbols.trkInd.setRotation((userTrk-userHdg)*D2R);
me.symbols.curHdgPtr.setRotation(userHdg*D2R);
me.symbols.curHdgPtr2.setRotation(userHdg*D2R);
me.map._node.getNode("hdg",1).setDoubleValue(userHdg);
me.symbols.curHdgPtr.setRotation(0);
me.symbols.curHdgPtr2.setRotation(0);
me.map._node.getNode("hdg",1).setDoubleValue(userHdgTru);
me.symbols.compass.setRotation(-userHdg*D2R);
me.symbols.compassApp.setRotation(-userHdg*D2R);
me.symbols.hdgTrk.setText("HDG");
@ -727,31 +853,127 @@ var NavDisplay = {
}
var staPtrVis = !me.in_mode('toggle_display_mode', ['APP','PLAN']);
if (!me.get_switch('toggle_centered') and me.in_mode('toggle_display_mode', ['APP','MAP','VOR'])) {
var magVar = getprop("environment/magnetic-variation-deg");
if(me.in_mode('toggle_display_mode', ['APP','MAP','VOR','PLAN']))
{
if(getprop("instrumentation/nav/heading-deg") != nil)
var nav0hdg=getprop("instrumentation/nav/heading-deg") - userHdg - magVar;
if(getprop("instrumentation/nav[1]/heading-deg") != nil)
var nav1hdg=getprop("instrumentation/nav[1]/heading-deg") - userHdg - magVar;
var adf0hdg=getprop("instrumentation/adf/indicated-bearing-deg");
var adf1hdg=getprop("instrumentation/adf[1]/indicated-bearing-deg");
if(!me.get_switch('toggle_centered'))
{
if(me.in_mode('toggle_display_mode', ['PLAN']))
me.symbols.trkInd.hide();
else
me.symbols.trkInd.show();
if((getprop("instrumentation/nav/in-range") and me.get_switch('toggle_lh_vor_adf') == 1)) {
me.symbols.staFromL.setVisible(staPtrVis);
me.symbols.staFromL2.hide();
me.symbols.staFromR.setVisible(staPtrVis);
me.symbols.staFromR2.hide();
me.symbols.staToL.setVisible(staPtrVis);
me.symbols.staToL2.hide();
me.symbols.staFromL.setColor(0.195,0.96,0.097);
me.symbols.staToL.setColor(0.195,0.96,0.097);
me.symbols.staFromL.setRotation((nav0hdg+180)*D2R);
me.symbols.staToL.setRotation(nav0hdg*D2R);
}
elsif(getprop("instrumentation/adf/in-range") and (me.get_switch('toggle_lh_vor_adf') == -1)) {
me.symbols.staFromL.setVisible(staPtrVis);
me.symbols.staToL.setVisible(staPtrVis);
me.symbols.staFromL.setColor(0,0.6,0.85);
me.symbols.staToL.setColor(0,0.6,0.85);
me.symbols.staFromL.setRotation((adf0hdg+180)*D2R);
me.symbols.staToL.setRotation(adf0hdg*D2R);
} else {
me.symbols.staFromL.hide();
me.symbols.staToL.hide();
}
if((getprop("instrumentation/nav[1]/in-range") and me.get_switch('toggle_rh_vor_adf') == 1)) {
me.symbols.staFromR.setVisible(staPtrVis);
me.symbols.staToR.setVisible(staPtrVis);
me.symbols.staFromR.setColor(0.195,0.96,0.097);
me.symbols.staToR.setColor(0.195,0.96,0.097);
me.symbols.staFromR.setRotation((nav1hdg+180)*D2R);
me.symbols.staToR.setRotation(nav1hdg*D2R);
} elsif(getprop("instrumentation/adf[1]/in-range") and (me.get_switch('toggle_rh_vor_adf') == -1)) {
me.symbols.staFromR.setVisible(staPtrVis);
me.symbols.staToR.setVisible(staPtrVis);
me.symbols.staFromR.setColor(0,0.6,0.85);
me.symbols.staToR.setColor(0,0.6,0.85);
me.symbols.staFromR.setRotation((adf1hdg+180)*D2R);
me.symbols.staToR.setRotation(adf1hdg*D2R);
} else {
me.symbols.staFromR.hide();
me.symbols.staToR.hide();
}
me.symbols.staFromL2.hide();
me.symbols.staToL2.hide();
me.symbols.staFromR2.hide();
me.symbols.staToR2.hide();
me.symbols.rotateComp.setVisible(staPtrVis);
me.symbols.rotateComp2.hide();
me.symbols.curHdgPtr2.hide();
me.symbols.HdgBugCRT2.hide();
me.symbols.TrkBugLCD2.hide();
me.symbols.HdgBugLCD2.hide();
me.symbols.selHdgLine2.hide();
me.symbols.curHdgPtr.setVisible(staPtrVis);
me.symbols.TrkBugLCD.hide();
me.symbols.HdgBugCRT.setVisible(staPtrVis and !dispLCD);
me.symbols.HdgBugLCD.setVisible(staPtrVis and dispLCD);
me.symbols.selHdgLine.setVisible(staPtrVis);
} else {
me.symbols.trkInd.hide();
me.symbols.staFromL.hide();
if((getprop("instrumentation/nav/in-range") and me.get_switch('toggle_lh_vor_adf') == 1)) {
me.symbols.staFromL2.setVisible(staPtrVis);
me.symbols.staFromR.hide();
me.symbols.staFromR2.setVisible(staPtrVis);
me.symbols.staToL.hide();
me.symbols.staToL2.setVisible(staPtrVis);
me.symbols.staToR.hide();
me.symbols.staToR2.setVisible(staPtrVis);
me.symbols.rotateComp.hide();
me.symbols.rotateComp2.setVisible(staPtrVis);
me.symbols.staFromL2.setColor(0.195,0.96,0.097);
me.symbols.staToL2.setColor(0.195,0.96,0.097);
me.symbols.staFromL2.setRotation((nav0hdg+180)*D2R);
me.symbols.staToL2.setRotation(nav0hdg*D2R);
} elsif(getprop("instrumentation/adf/in-range") and (me.get_switch('toggle_lh_vor_adf') == -1)) {
me.symbols.staFromL2.setVisible(staPtrVis);
me.symbols.staToL2.setVisible(staPtrVis);
me.symbols.staFromL2.setColor(0,0.6,0.85);
me.symbols.staToL2.setColor(0,0.6,0.85);
me.symbols.staFromL2.setRotation((adf0hdg+180)*D2R);
me.symbols.staToL2.setRotation(adf0hdg*D2R);
} else {
me.symbols.staFromL2.hide();
me.symbols.staToL2.hide();
}
if((getprop("instrumentation/nav[1]/in-range") and me.get_switch('toggle_rh_vor_adf') == 1)) {
me.symbols.staFromR2.setVisible(staPtrVis);
me.symbols.staToR2.setVisible(staPtrVis);
me.symbols.staFromR2.setColor(0.195,0.96,0.097);
me.symbols.staToR2.setColor(0.195,0.96,0.097);
me.symbols.staFromR2.setRotation((nav1hdg+180)*D2R);
me.symbols.staToR2.setRotation(nav1hdg*D2R);
} elsif(getprop("instrumentation/adf[1]/in-range") and (me.get_switch('toggle_rh_vor_adf') == -1)) {
me.symbols.staFromR2.setVisible(staPtrVis);
me.symbols.staToR2.setVisible(staPtrVis);
me.symbols.staFromR2.setColor(0,0.6,0.85);
me.symbols.staToR2.setColor(0,0.6,0.85);
me.symbols.staFromR2.setRotation((adf1hdg+180)*D2R);
me.symbols.staToR2.setRotation(adf1hdg*D2R);
} else {
me.symbols.staFromR2.hide();
me.symbols.staToR2.hide();
}
me.symbols.staFromL.hide();
me.symbols.staToL.hide();
me.symbols.staFromR.hide();
me.symbols.staToR.hide();
me.symbols.curHdgPtr.hide();
me.symbols.HdgBugCRT.hide();
me.symbols.TrkBugLCD.hide();
me.symbols.HdgBugLCD.hide();
me.symbols.selHdgLine.hide();
me.symbols.curHdgPtr2.setVisible(staPtrVis);
me.symbols.TrkBugLCD2.hide();
me.symbols.HdgBugCRT2.setVisible(staPtrVis and !dispLCD);
me.symbols.HdgBugLCD2.setVisible(staPtrVis and dispLCD);
me.symbols.selHdgLine2.setVisible(staPtrVis);
}
}
me.symbols.hdgGroup.setVisible(!me.in_mode('toggle_display_mode', ['PLAN']));
me.symbols.northUp.setVisible(me.in_mode('toggle_display_mode', ['PLAN']));
me.symbols.aplSymMap.setVisible(me.in_mode('toggle_display_mode', ['APP','MAP','VOR']) and !me.get_switch('toggle_centered'));
@ -776,27 +998,6 @@ var NavDisplay = {
me.symbols.altArc.hide();
}
## these would require additional arguments to be moved to an external config hash currently
me.symbols.selHdg.setRotation(getprop("autopilot/settings/true-heading-deg")*D2R);
me.symbols.selHdg2.setRotation(getprop("autopilot/settings/true-heading-deg")*D2R);
if (var nav0hdg=getprop("instrumentation/nav/heading-deg") != nil) {
me.symbols.staFromL.setRotation((nav0hdg-userHdgMag+180)*D2R);
me.symbols.staFromL2.setRotation((nav0hdg-userHdgMag+180)*D2R);
}
if (var nav0hdg=getprop("instrumentation/nav/heading-deg") != nil) {
me.symbols.staToL.setRotation((nav0hdg-userHdgMag)*D2R);
me.symbols.staToL2.setRotation((nav0hdg-userHdgMag)*D2R);
}
if (var nav1hdg=getprop("instrumentation/nav[1]/heading-deg") != nil) {
me.symbols.staFromR.setRotation((nav1hdg-userHdgMag+180)*D2R);
me.symbols.staFromR2.setRotation((nav1hdg-userHdgMag+180)*D2R);
}
if (var nav1hdg=getprop("instrumentation/nav[1]/heading-deg") != nil) {
me.symbols.staToR.setRotation((nav1hdg-userHdgMag)*D2R);
me.symbols.staToR2.setRotation((nav1hdg-userHdgMag)*D2R);
}
## run all predicates in the NDStyle hash and evaluate their true/false behavior callbacks
## this is in line with the original design, but normally we don't need to getprop/poll here,
## using listeners or timers would be more canvas-friendly whenever possible
@ -804,28 +1005,21 @@ var NavDisplay = {
## will be updated at frame rate too - wasteful ... (check the performance monitor!)
foreach(var feature; me.nd_style.features ) {
# for stuff that always needs to be updated
if (contains(feature.impl, 'common')) feature.impl.common(me);
# conditional stuff
if(!contains(feature.impl, 'predicate')) continue; # no conditional stuff
if ( var result=feature.impl.predicate(me) ) {
# print("Update predicate true for ", feature.id);
if ( var result=feature.impl.predicate(me) )
feature.impl.is_true(me, result); # pass the result to the predicate
}
else {
# print("Update predicate false for ", feature.id);
else
feature.impl.is_false( me, result ); # pass the result to the predicate
}
}
## update the status flags shown on the ND (wxr, wpt, arpt, sta)
# this could/should be using listeners instead ...
me.symbols['status.wxr'].setVisible( me.get_switch('toggle_weather') and me.in_mode('toggle_display_mode', ['MAP']));
me.symbols['status.wpt'].setVisible( me.get_switch('toggle_waypoints') and me.in_mode('toggle_display_mode', ['MAP']));
me.symbols['status.arpt'].setVisible( me.get_switch('toggle_airports') and me.in_mode('toggle_display_mode', ['MAP']));
me.symbols['status.sta'].setVisible( me.get_switch('toggle_stations') and me.in_mode('toggle_display_mode', ['MAP']));
}
};

View file

@ -5,9 +5,7 @@ RouteModel.new = func make(LayerModel, RouteModel);
RouteModel.init = func {
me._view.reset();
if (!getprop("/autopilot/route-manager/active"))
print("Cannot draw route, route manager inactive!") and return;
print("TODO: route.model is still an empty stub, see route.draw instead");
return;
## 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] )

View file

@ -130,7 +130,7 @@ void main (void)
//////////////////////////////////////////////////////////////////////
//begin DIRT
//////////////////////////////////////////////////////////////////////
if (dirt_enabled > 0.0){
if (dirt_enabled >= 1){
vec3 dirtFactorIn = vec3 (dirt_r_factor, dirt_g_factor, dirt_b_factor);
vec3 dirtFactor = reflmap.rgb * dirtFactorIn.rgb;
//dirtFactor.r = smoothstep(0.0, 1.0, dirtFactor.r);