diff --git a/Effects/building.eff b/Effects/building.eff index 65a599a42..9edc822b2 100644 --- a/Effects/building.eff +++ b/Effects/building.eff @@ -91,7 +91,7 @@ /environment/mean-terrain-elevation-m /rendering/scene/overcast /sim/rendering/eye-altitude-m - /environment/mysnow-level-m + /environment/snow-level-m /environment/surface/dust-cover-factor /sim/rendering/shaders/skydome /environment/fog-structure diff --git a/Effects/terrain-default.eff b/Effects/terrain-default.eff index 42823e4f3..62c2a4f0a 100644 --- a/Effects/terrain-default.eff +++ b/Effects/terrain-default.eff @@ -66,7 +66,7 @@ /environment/mean-terrain-elevation-m /rendering/scene/overcast /sim/rendering/eye-altitude-m - /environment/mysnow-level-m + /environment/snow-level-m /environment/surface/dust-cover-factor /environment/surface/wetness /sim/rendering/shaders/skydome @@ -252,9 +252,9 @@ eye_alt - mysnowlevel + snowlevel float - mysnow_level + snow_level dust_cover_factor diff --git a/Effects/tree.eff b/Effects/tree.eff index a7c207983..80514ef9b 100644 --- a/Effects/tree.eff +++ b/Effects/tree.eff @@ -27,7 +27,7 @@ /environment/mean-terrain-elevation-m /rendering/scene/overcast /sim/rendering/eye-altitude-m - /environment/mysnow-level-m + /environment/snow-level-m /environment/surface/dust-cover-factor /sim/rendering/shaders/skydome /environment/fog-structure diff --git a/Effects/urban.eff b/Effects/urban.eff index f6a3130dd..168d5e702 100644 --- a/Effects/urban.eff +++ b/Effects/urban.eff @@ -303,9 +303,9 @@ eye_alt - mysnowlevel + snowlevel float - mysnow_level + snow_level dust_cover_factor @@ -500,9 +500,9 @@ eye_alt - mysnowlevel + snowlevel float - mysnow_level + snow_level dust_cover_factor diff --git a/Environment/environment.xml b/Environment/environment.xml index 6e3a8c38b..6a8692b2b 100644 --- a/Environment/environment.xml +++ b/Environment/environment.xml @@ -23,18 +23,27 @@ Fetch live weather data for your nearest airport from noaa.gov. You need a working internet connection. All the controls in this dialog are computed automatically, once a valid METAR is received. - live + + live + METAR + Manual input Enter your favorite METAR weather in the textbox above. A valid METAR syntax is required. - manual + + manual + METAR + Fair weather XXXX 012345Z 15003KT 12SM SCT041 FEW200 20/08 Q1015 NOSIG A lovely day for trip to your favorite 100$ hamburger airfield - High-pressure-core + + High-pressure-core + realistic-weather + Thunderstorm @@ -44,7 +53,10 @@ Be prepared for reduction of visibility in showers and strong gusts near thunderstorms - Thunderstorms + + Thunderstorms + realistic-weather + Stormy Monday @@ -285,6 +297,7 @@ 240 true true + true true 30000 @@ -344,7 +357,6 @@ 2000.0 1000000.0 0.0 - 3200.0 0.0 diff --git a/Environment/metarinterpolator.xml b/Environment/metarinterpolator.xml index 7499bd699..375eb7744 100644 --- a/Environment/metarinterpolator.xml +++ b/Environment/metarinterpolator.xml @@ -415,6 +415,12 @@ MetarController:snow-level gain 1.0 + + + /environment/params/metar-updates-snow-level + /environment/params/metar-updates-environment + + /environment/metar/valid diff --git a/Nasal/canvas/api.nas b/Nasal/canvas/api.nas index 2087254c6..ed4fbbb22 100644 --- a/Nasal/canvas/api.nas +++ b/Nasal/canvas/api.nas @@ -711,14 +711,41 @@ var Image = { var m = { parents: [Image, Element.new(parent, "image", id, arg)] }; - m.color = _createColorNodes(m._node, "color"); - m.sourceRect = m._node.getNode("source", 1); + m.color_fill = _createColorNodes(m._node, "color-fill"); return m; }, - + # Set image file to be used + # + # @param file Path to file or canvas (Use canvas://... for canvas, eg. + # canvas://by-index/texture[0]) setFile: func(file) { - me.set("file", file); + me.set("file", file); + }, + # Set rectangular region of source image to be used + # + # @param left Rectangle minimum x coordinate + # @param top Rectangle minimum y coordinate + # @param right Rectangle maximum x coordinate + # @param bottom Rectangle maximum y coordinate + # @param normalized Whether to use normalized ([0,1]) or image + # ([0, image_width]/[0, image_height]) coordinates + setSourceRect: func(left, top, right, bottom, normalized = 1) + { + me._node.getNode("source", 1).setValues({ + left: left, + top: top, + right: right, + bottom: bottom, + normalized: normalized + }); + return me; + }, + # Set size of image element + setSize: func(width, height) + { + me._node.setValues({size: [width, height]}); + return me; } }; @@ -764,7 +791,12 @@ var Canvas = { # Set the background color # # @param color Vector of 3 or 4 values in [0, 1] - setColorBackground: func { _setColorNodes(me.color, arg); return me; } + setColorBackground: func { _setColorNodes(me.color, arg); return me; }, + # Get path of canvas to be used eg. in Image::setFile + getPath: func() + { + return "canvas://by-index/texture[" ~ me._node.getIndex() ~ "]"; + } }; # Create a new canvas. Pass parameters as hash, eg: @@ -779,11 +811,7 @@ var new = func(vals) { var m = { parents: [Canvas] }; - m.texture = _createNodeWithIndex - ( - props.globals.getNode("canvas", 1), - "texture" - ); + m.texture = _createNodeWithIndex(Canvas.property_root, "texture"); m.color = _createColorNodes(m.texture, "color-background"); m.texture.setValues(vals); @@ -802,11 +830,7 @@ var get = func(name) node_canvas = name; else if( typeof(name) == 'scalar' ) { - var canvas_root = props.globals.getNode("canvas"); - if( canvas_root == nil ) - return nil; - - foreach(var c; canvas_root.getChildren("texture")) + foreach(var c; Canvas.property_root.getChildren("texture")) { if( c.getValue("name") == name ) node_canvas = c; @@ -847,4 +871,7 @@ else {button: {legend: "Ok", binding: {command: "dialog-close"}}} ); } -} })(); +} + +Canvas.property_root = props.globals.getNode("canvas/by-index", 1); +})(); diff --git a/Shaders/terrain-haze-detailed.frag b/Shaders/terrain-haze-detailed.frag index 2cb314665..4f7114d75 100644 --- a/Shaders/terrain-haze-detailed.frag +++ b/Shaders/terrain-haze-detailed.frag @@ -28,7 +28,7 @@ uniform float terrain_alt; uniform float hazeLayerAltitude; uniform float overcast; uniform float eye_alt; -uniform float mysnowlevel; +uniform float snowlevel; uniform float dust_cover_factor; uniform float wetness; uniform float fogstructure; @@ -262,7 +262,7 @@ void main() // mix snow snow_alpha = smoothstep(0.75, 0.85, abs(steepness)); - texel = mix(texel, snow_texel, smoothstep(mysnowlevel, mysnowlevel+200.0, snow_alpha * (relPos.z + eye_alt)+ (noise_2000m + 0.1 * noise_10m -0.55) *400.0)); + texel = mix(texel, snow_texel, smoothstep(snowlevel, snowlevel+200.0, snow_alpha * (relPos.z + eye_alt)+ (noise_2000m + 0.1 * noise_10m -0.55) *400.0)); } diff --git a/Shaders/urban-lightfield.frag b/Shaders/urban-lightfield.frag index 1bd947488..2980701b7 100644 --- a/Shaders/urban-lightfield.frag +++ b/Shaders/urban-lightfield.frag @@ -43,7 +43,7 @@ uniform float terrain_alt; uniform float hazeLayerAltitude; uniform float overcast; uniform float eye_alt; -uniform float mysnowlevel; +uniform float snowlevel; uniform float dust_cover_factor; uniform float wetness; uniform float fogstructure; diff --git a/Translations/en/menu.xml b/Translations/en/menu.xml index 8f797bb7d..61311cafe 100644 --- a/Translations/en/menu.xml +++ b/Translations/en/menu.xml @@ -43,6 +43,7 @@ Environment Weather + Environment Settings Time Settings Wildfire Settings Scenery Download diff --git a/gui/dialogs/environment-settings.xml b/gui/dialogs/environment-settings.xml new file mode 100644 index 000000000..bfbe35d7a --- /dev/null +++ b/gui/dialogs/environment-settings.xml @@ -0,0 +1,259 @@ + + + + environment-settings + false + false + vbox + 3 + + + + hbox + 1 + + + true + + + + + + + + true + + + + + + + + + table + + + 0 + 0 + + right + + + 0 + 1 + season + left + true + /sim/startup/season + summer + winter + + dialog-apply + season + + + + + + + + + + + + table + + + 0 + 0 + 4 + left + + + + + 1 + 0 + 4 + left + + metar-snow + /environment/params/metar-updates-snow-level + + dialog-apply + metar-snow + + + + + + left + 2 + 0 + + + + + right + 2 + 1 + + + + snow-level + 2 + 2 + -425.0 + 7500.0 + true + /environment/snow-level-m + + dialog-apply + snow-level + + + + + + left + 2 + 3 + + + + 2 + 4 + + %.fm + true + /environment/snow-level-m + + + + + left + 3 + 0 + + + + + right + 3 + 1 + + + + dust-level + 3 + 2 + 0.0 + 0.7 + true + /environment/surface/dust-cover-factor + + dialog-apply + dust-level + + + + + + left + 3 + 3 + + + + + left + 4 + 0 + + + + + right + 4 + 1 + + + + wetness + 4 + 2 + 0.0 + 0.7 + true + /environment/surface/wetness + + dialog-apply + wetness + + + + + + left + 4 + 3 + + + + + + + + + true + + hbox + + + + + + + + true + + + + diff --git a/gui/dialogs/local_weather_environment.xml b/gui/dialogs/local_weather_environment.xml deleted file mode 100644 index d6ca7bd28..000000000 --- a/gui/dialogs/local_weather_environment.xml +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - local_weather_environment - 400 - 210 - false - - - 5 - 180 - - - - - - 5 - 150 - - - - - 120 - 150 - - - - - 190 - 150 - 90 - 20 - 0.0 - 7500.0 - /environment/mysnow-level-m - - dialog-apply - - - - - 290 - 150 - - - - - - 340 - 150 - - %.fm - true - /environment/mysnow-level-m - - - - - 5 - 120 - - - - - 120 - 120 - - - - - 190 - 120 - 90 - 20 - 0.0 - 0.7 - /environment/surface/dust-cover-factor - - dialog-apply - - - - - 290 - 120 - - - - - - 5 - 90 - - - - - 120 - 90 - - - - - 190 - 90 - 90 - 20 - 0.0 - 12.0 - /environment/fog-structure - - dialog-apply - - - - - 290 - 90 - - - - - - 5 - 60 - - - - - 120 - 60 - - - - - 190 - 60 - 90 - 20 - 0.0 - 0.7 - /environment/surface/wetness - - dialog-apply - - - - - 290 - 60 - - - - - - 10 - 10 - - - - - - - - - - diff --git a/gui/dialogs/local_weather_tiles.xml b/gui/dialogs/local_weather_tiles.xml index 2db727b86..dffb8c7b5 100644 --- a/gui/dialogs/local_weather_tiles.xml +++ b/gui/dialogs/local_weather_tiles.xml @@ -430,19 +430,51 @@ 3 0 right - + 3 1 right - + 3 2 + 0.0 + 12.0 + /environment/fog-structure + + dialog-apply + + + + + 3 + 3 + left + + + + + 4 + 0 + right + + + + + 4 + 1 + right + + + + + 4 + 2 9.90348 12.429216196 /local-weather/config/aux-max-vis-range-m @@ -452,14 +484,14 @@ - 3 + 4 3 left - 3 + 4 4 left @@ -579,17 +611,6 @@ - - true diff --git a/gui/dialogs/rendering.xml b/gui/dialogs/rendering.xml index 904d6d200..680758b62 100644 --- a/gui/dialogs/rendering.xml +++ b/gui/dialogs/rendering.xml @@ -207,31 +207,8 @@ table - - 0 - 0 - 2 - - right - - - 0 - 2 - 2 - season - left - true - /sim/startup/season - summer - winter - - dialog-apply - season - - - - 1 + 0 0 left @@ -244,7 +221,7 @@ - 2 + 1 0 left @@ -255,9 +232,21 @@ random-buildings + + + 1 + 1 + 3 + + 1.0 + 0.6 + 0.6 + + + - 3 + 2 0 left @@ -270,7 +259,7 @@ - 4 + 3 0 left @@ -282,7 +271,7 @@ - 4 + 3 1 @@ -290,7 +279,7 @@ - 4 + 3 2 vegetation-density 0 @@ -303,7 +292,7 @@ - 4 + 3 3 %.1f diff --git a/gui/dialogs/weather-configuration.xml b/gui/dialogs/weather-configuration.xml index ca321c892..56e062391 100644 --- a/gui/dialogs/weather-configuration.xml +++ b/gui/dialogs/weather-configuration.xml @@ -372,67 +372,6 @@ - - - 2 - 0 - - - /sim/rendering/shaders/quality-level - - /sim/rendering/shaders/crop - /sim/rendering/shaders/landmass - /sim/rendering/shaders/transition - /sim/rendering/shaders/urban - - - - - - - snow-level - 2 - 1 - - - /sim/rendering/shaders/quality-level - - /sim/rendering/shaders/crop - /sim/rendering/shaders/landmass - /sim/rendering/shaders/transition - /sim/rendering/shaders/urban - - - - -425.0 - 5000.0 - true - /environment/snow-level-m - - dialog-apply - snow-level - - - - - 2 - 2 - - - /sim/rendering/shaders/quality-level - - /sim/rendering/shaders/crop - /sim/rendering/shaders/landmass - /sim/rendering/shaders/transition - /sim/rendering/shaders/urban - - - - - %.fm - true - /environment/snow-level-m - diff --git a/gui/dialogs/weather.xml b/gui/dialogs/weather.xml index 1af7bb11a..fda09fa30 100644 --- a/gui/dialogs/weather.xml +++ b/gui/dialogs/weather.xml @@ -38,9 +38,10 @@ var scenarioName = getprop( me.base ~ "/source-selection"); if (getprop( me.base ~ "/mode/manual-weather")) { - # In manual weather mode we have to diable live weather + # In manual weather mode we have to disable live weather # fetch so the weather can be changed by the user in the # weather configuration dialog. + setprop( "/environment/params/metar-updates-environment", 0 ); setprop( "/environment/realwx/enabled", 0 ); setprop( "/environment/config/enabled", 0 ); @@ -77,13 +78,14 @@ } else { # preset configured scenario var wsn = props.globals.getNode( "/environment/weather-scenarios" ); + var current = getprop("/environment/weather-scenario", ""); var found = 0; if( wsn != nil ) { var scenarios = wsn.getChildren("scenario"); forindex (var i; scenarios ) { var metarN = scenarios[i].getNode("metar"); metarN == nil and continue; - if( metarN.getValue() == getprop("/environment/metar/data","") ) { + if( scenarios[i].getNode("name").getValue() == current ) { setprop( me.base ~ "/source-selection", scenarios[i].getNode("name").getValue() ); found = 1; break; @@ -122,7 +124,6 @@ apply : func { var scenarioName = getprop( me.base ~ "/source-selection"); var metar = getprop( "environment/metar/data" ); - var tile = getprop( me.base ~ "/tile"); var global_weather_enabled = getprop( me.base ~ "/mode/global-weather"); var local_weather_enabled = getprop( me.base ~ "/mode/local-weather"); var manual_weather_enabled = getprop( me.base ~ "/mode/manual-weather"); @@ -131,7 +132,7 @@ if (manual_weather_enabled == 1) { setprop( "/environment/params/metar-updates-environment", 0 ); setprop( "/environment/realwx/enabled", 0 ); - setprop( "/environment/config/enabled", 0 ); + setprop( "/environment/config/enabled", 1 ); metar = ""; } else if( scenarioName == "Live data" ) { setprop( "/environment/params/metar-updates-environment", 1 ); @@ -149,6 +150,8 @@ metar = getprop( me.base ~ "/metar-string" ); } + setprop("/environment/weather-scenario", scenarioName); + if( metar != nil ) { setprop( "environment/metar/data", normalize_string(metar) ); } @@ -161,20 +164,6 @@ # If Local Weather is enabled, re-initialize with updated # initial tile and tile selection. setprop("/nasal/local_weather/enabled", "true"); - setprop("/local-weather/tmp/tile-type", tile); - - if ((scenarioName == "Live data" ) or - (scenarioName == "Manual input") ) { - # If using Live data, or a manually entered METAR string, the - # only sensible tile selection mode is "METAR" - setprop("/local-weather/tmp/tile-management", "METAR"); - } else if (tile != "") { - # Use Realistic Weather for defined tiles - setprop("/local-weather/tmp/tile-management", "realistic weather"); - } else { - # Otherwise repeat the tile - setprop("/local-weather/tmp/tile-management", "repeat-tile"); - } # Re-initialize local weather. local_weather.set_tile(); @@ -194,14 +183,15 @@ }, scenarioListener : func( n ) { - description = ""; - metar = "nil"; - tile = ""; + var description = ""; + var metar = "nil"; + var local_weather_props = nil; + var scenario = me.findScenarioByName( n.getValue() ); if( scenario != nil ) { description = normalize_string(scenario.getNode("description", 1 ).getValue()); metar = normalize_string(scenario.getNode("metar", 1 ).getValue()); - tile = normalize_string(scenario.getNode("tile", 1 ).getValue()); + local_weather_props = scenario.getNode("local-weather"); } if (n.getValue() == "Live data") { @@ -212,12 +202,63 @@ if (n.getValue() == "Manual input") { # Special case - retain current values var metar = getprop( me.base ~ "/metar-string" ); - } - + } setprop(me.base ~ "/description", description ); setprop(me.base ~ "/metar-string", metar ); - setprop(me.base ~ "/tile", tile); + + # Set the wind from the METAR string. + var result = []; + var msplit = split(" ", string.uc(metar)); + foreach (var word; msplit) { + + if ((size(word) > 6) and string.match(word, "*[0-9][0-9]KT")) { + # We've got the wind definition word. Now to split it up. + # Format is nnnmmKT or nnnmmGppKT + # Direction is easy - the first 3 characters. + var dir = chr(word[0]) ~ chr(word[1]) ~ chr(word[2]); + + if (dir == "VRB") { + setprop("/local-weather/tmp/tile-orientation-deg", 360.0 * rand()); + setprop("/local-weather/tmp/gust-angular-variation-deg", 180.0); + setprop("/local-weather/tmp/gust-frequency-hz", 0.001); + } else { + setprop("/local-weather/tmp/tile-orientation-deg", dir); + setprop("/local-weather/tmp/gust-angular-variation-deg", 0.0); + setprop("/local-weather/tmp/gust-frequency-hz", 0.0); + } + + # Next two are the base wind + var spd = chr(word[3]) ~ chr(word[4]); + setprop("/local-weather/tmp/windspeed-kt", spd); + + var gst = 0; + if ((size(word) > 7) and (chr(word[5]) == 'G')) { + # Gusty case + gst = chr(word[6]) ~ chr(word[7]); + } + + if ((gst > spd) and (spd > 0)) { + setprop("/local-weather/tmp/gust-relative-strength", (gst - spd) / spd); + setprop("/local-weather/tmp/gust-frequency-hz", 0.7); + } else { + setprop("/local-weather/tmp/gust-relative-strength", 0.0); + } + } + } + + + if (local_weather_props != nil) { + # The local weather properties need to be set now, so they can + # be configured by the user if they select Advanced Settings + props.copy(local_weather_props, props.globals.getNode("/local-weather/tmp", 1)); + } else { + # If no local weather properties have been set, we'll read from the scenario + # METAR + setprop("/local-weather/tmp/tile-type", "manual"); + setprop("/local-weather/tmp/tile-management", "METAR"); + } + me.refresh(); }, diff --git a/gui/menubar.xml b/gui/menubar.xml index f58ade722..912669d71 100644 --- a/gui/menubar.xml +++ b/gui/menubar.xml @@ -281,6 +281,14 @@ + + environment-settings + + dialog-show + environment-settings + + + time-settings