mirror of
https://github.com/MaSzyna-EU07/StarterNG.git
synced 2026-10-28 18:47:28 +01:00
Compare commits
4 Commits
refactor/s
...
feat/openg
| Author | SHA1 | Date | |
|---|---|---|---|
| d222f49179 | |||
| 8d6b4805c8 | |||
| 2befefb547 | |||
| 5929a4ef4f |
405
StarterNG.Tests/GraphicsSettingsTests.cs
Normal file
405
StarterNG.Tests/GraphicsSettingsTests.cs
Normal file
@@ -0,0 +1,405 @@
|
|||||||
|
using StarterNG.Classes;
|
||||||
|
using StarterNG.Domain.Settings;
|
||||||
|
using StarterNG.Infrastructure.Settings;
|
||||||
|
using StarterNG.Tests.Fakes;
|
||||||
|
|
||||||
|
namespace StarterNG.Tests;
|
||||||
|
|
||||||
|
public class GraphicsSettingsTests
|
||||||
|
{
|
||||||
|
private static readonly string UserIni = Path.Combine("/home/kolejarz", ".config", "MaSzyna", "eu07.ini");
|
||||||
|
|
||||||
|
private static TestInstallation WithIni(string text)
|
||||||
|
{
|
||||||
|
var installation = new TestInstallation(new InMemoryFileSystem().WithFile(UserIni, text));
|
||||||
|
installation.Environment.With("HOME", "/home/kolejarz");
|
||||||
|
installation.SettingsStore.Load();
|
||||||
|
return installation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SimulatorSettings Read(string text, bool dlssPlatform = true)
|
||||||
|
{
|
||||||
|
var s = new SimulatorSettings();
|
||||||
|
new SettingsSerializer(dlssPlatform).Read(s, ConfigFile.Parse(text));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string Write(SimulatorSettings s, string text = "", bool dlssPlatform = true)
|
||||||
|
{
|
||||||
|
var c = ConfigFile.Parse(text);
|
||||||
|
new SettingsSerializer(dlssPlatform).Write(s, c);
|
||||||
|
return c.ToText();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string[] Lines(string text) =>
|
||||||
|
text.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None);
|
||||||
|
|
||||||
|
private static string? Line(string text, string key) =>
|
||||||
|
Lines(text).FirstOrDefault(l => l == key || l.StartsWith(key + " ", StringComparison.Ordinal));
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData("full", GraphicsBackend.OpenGL)]
|
||||||
|
[InlineData("default", GraphicsBackend.OpenGL)]
|
||||||
|
[InlineData("gl46", GraphicsBackend.OpenGL)]
|
||||||
|
[InlineData("legacy", GraphicsBackend.OpenGL)]
|
||||||
|
[InlineData("experimental", GraphicsBackend.OpenGL)]
|
||||||
|
[InlineData("vulkan", GraphicsBackend.Vulkan)]
|
||||||
|
[InlineData("vulkan14", GraphicsBackend.Vulkan)]
|
||||||
|
public void The_renderer_is_read_with_the_aliases_the_simulator_takes(string value, GraphicsBackend expected)
|
||||||
|
{
|
||||||
|
Assert.Equal(expected, Read($"gfxrenderer {value}\n").Backend);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void The_renderer_is_written_as_a_name_every_simulator_reads()
|
||||||
|
{
|
||||||
|
Assert.Equal("gfxrenderer full", Line(Write(Read("gfxrenderer legacy\n")), "gfxrenderer"));
|
||||||
|
Assert.Equal("gfxrenderer vulkan", Line(Write(Read("gfxrenderer vulkan14\n")), "gfxrenderer"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void The_new_graphics_keys_are_read()
|
||||||
|
{
|
||||||
|
var s = Read("gfxrenderer vulkan\n" +
|
||||||
|
"gfx.antialiasing dlss\ngfx.dlss.preset K\ngfx.framegeneration x3\ngfx.reflex boost\n" +
|
||||||
|
"gfx.raytracing yes\ngfx.raytracing.range 800\ngfx.ssr high\ngfx.postfx.ao ssao\ngfx.postfx.ao.quality 4 6\n" +
|
||||||
|
"gfx.lights.shadows low\ngfx.contactshadows 3\ngfx.fog analytic\ngfx.fog.quality ultra\n" +
|
||||||
|
"gfx.clouds ultra\ngfx.clouds.shadows no\ngfx.grass no\ngfx.grass.distance 120\ngfx.grass.density 1.5\n" +
|
||||||
|
"gfx.buffer.percent 0.67\ngfx.vulkan.device RTX\n");
|
||||||
|
|
||||||
|
Assert.Equal(GraphicsBackend.Vulkan, s.Backend);
|
||||||
|
Assert.Equal(AntiAliasingMode.Dlss, s.AntiAliasing);
|
||||||
|
Assert.Equal("k", s.DlssPreset);
|
||||||
|
Assert.Equal(3, s.FrameGeneration);
|
||||||
|
Assert.Equal(2, s.Reflex);
|
||||||
|
Assert.True(s.RayTracing);
|
||||||
|
Assert.Equal(800, s.RayTracingRange);
|
||||||
|
Assert.Equal(3, s.Ssr);
|
||||||
|
Assert.Equal(1, s.AmbientOcclusion);
|
||||||
|
Assert.Equal((4, 6), (s.AoSlices, s.AoSteps));
|
||||||
|
Assert.Equal(1, s.LightShadows);
|
||||||
|
Assert.Equal(3, s.ContactShadows);
|
||||||
|
Assert.False(s.VolumetricFog);
|
||||||
|
Assert.Equal(4, s.FogQuality);
|
||||||
|
Assert.Equal(4, s.Clouds);
|
||||||
|
Assert.False(s.CloudShadows);
|
||||||
|
Assert.False(s.Grass);
|
||||||
|
Assert.Equal(120, s.GrassDistance);
|
||||||
|
Assert.Equal(1.5, s.GrassDensity);
|
||||||
|
Assert.Equal(67, s.BufferScalePercent);
|
||||||
|
Assert.Equal("RTX", s.VulkanDevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Missing_keys_take_the_simulators_defaults()
|
||||||
|
{
|
||||||
|
var s = Read("");
|
||||||
|
|
||||||
|
Assert.Equal(GraphicsBackend.OpenGL, s.Backend);
|
||||||
|
Assert.Equal(AntiAliasingMode.Msaa4, s.AntiAliasing);
|
||||||
|
Assert.Equal(2, s.Ssr);
|
||||||
|
Assert.Equal(2, s.AmbientOcclusion);
|
||||||
|
Assert.Equal(2, s.LightShadows);
|
||||||
|
Assert.Equal(0, s.ContactShadows);
|
||||||
|
Assert.True(s.VolumetricFog);
|
||||||
|
Assert.Equal(2, s.FogQuality);
|
||||||
|
Assert.Equal(2, s.Clouds);
|
||||||
|
Assert.False(s.RayTracing);
|
||||||
|
Assert.Equal(1, s.FrameGeneration);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void The_tokens_written_are_the_ones_the_simulator_parses()
|
||||||
|
{
|
||||||
|
var s = Read("gfxrenderer vulkan\n");
|
||||||
|
s.AntiAliasing = AntiAliasingMode.Dlaa;
|
||||||
|
s.FrameGeneration = 4;
|
||||||
|
s.Reflex = 1;
|
||||||
|
s.LightShadows = 3;
|
||||||
|
s.ContactShadows = 0;
|
||||||
|
s.Clouds = 4;
|
||||||
|
s.VolumetricFog = false;
|
||||||
|
s.FogQuality = 1;
|
||||||
|
s.AmbientOcclusion = 1;
|
||||||
|
s.Ssr = 2;
|
||||||
|
s.RayTracing = true;
|
||||||
|
|
||||||
|
string text = Write(s);
|
||||||
|
|
||||||
|
Assert.Equal("gfx.antialiasing dlaa", Line(text, "gfx.antialiasing"));
|
||||||
|
Assert.Equal("multisampling 0", Line(text, "multisampling"));
|
||||||
|
Assert.Equal("gfx.framegeneration x4", Line(text, "gfx.framegeneration"));
|
||||||
|
Assert.Equal("gfx.reflex on", Line(text, "gfx.reflex"));
|
||||||
|
Assert.Equal("gfx.lights.shadows high", Line(text, "gfx.lights.shadows"));
|
||||||
|
Assert.Equal("gfx.contactshadows no", Line(text, "gfx.contactshadows"));
|
||||||
|
Assert.Equal("gfx.clouds ultra", Line(text, "gfx.clouds"));
|
||||||
|
Assert.Equal("gfx.fog analytic", Line(text, "gfx.fog"));
|
||||||
|
Assert.Equal("gfx.fog.quality low", Line(text, "gfx.fog.quality"));
|
||||||
|
Assert.Equal("gfx.postfx.ao ssao", Line(text, "gfx.postfx.ao"));
|
||||||
|
Assert.Equal("gfx.ssr medium", Line(text, "gfx.ssr"));
|
||||||
|
Assert.Equal("gfx.raytracing yes", Line(text, "gfx.raytracing"));
|
||||||
|
Assert.Equal("gfx.buffer.percent 100", Line(text, "gfx.buffer.percent"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Msaa_is_written_to_both_keys_for_older_simulators()
|
||||||
|
{
|
||||||
|
var s = Read("multisampling 1\n");
|
||||||
|
Assert.Equal(AntiAliasingMode.Msaa2, s.AntiAliasing);
|
||||||
|
|
||||||
|
string text = Write(s);
|
||||||
|
|
||||||
|
Assert.Equal("multisampling 1", Line(text, "multisampling"));
|
||||||
|
Assert.Equal("gfx.antialiasing msaax2", Line(text, "gfx.antialiasing"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Of_the_two_anti_aliasing_keys_the_later_one_wins_as_in_the_simulator()
|
||||||
|
{
|
||||||
|
Assert.Equal(AntiAliasingMode.Taa, Read("multisampling 2\ngfx.antialiasing taa\n").AntiAliasing);
|
||||||
|
Assert.Equal(AntiAliasingMode.Msaa4, Read("gfx.antialiasing taa\nmultisampling 2\n").AntiAliasing);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Gfx_antialiasing_is_moved_below_multisampling_so_it_takes_effect()
|
||||||
|
{
|
||||||
|
var s = Read("gfx.antialiasing msaax4\nmultisampling 2\n");
|
||||||
|
s.AntiAliasing = AntiAliasingMode.Taa;
|
||||||
|
|
||||||
|
string text = Write(s, "gfx.antialiasing msaax4\nmultisampling 2\n");
|
||||||
|
var lines = Lines(text).ToList();
|
||||||
|
|
||||||
|
Assert.True(lines.IndexOf("gfx.antialiasing taa") > lines.IndexOf("multisampling 0"));
|
||||||
|
Assert.Equal(AntiAliasingMode.Taa, Read(text).AntiAliasing);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void On_opengl_the_vulkan_only_features_are_written_off()
|
||||||
|
{
|
||||||
|
var s = Read("gfxrenderer full\ngfx.antialiasing dlss\ngfx.framegeneration x2\ngfx.reflex on\ngfx.raytracing yes\n");
|
||||||
|
|
||||||
|
Assert.Equal(AntiAliasingMode.Taa, s.AntiAliasing);
|
||||||
|
Assert.Equal(1, s.FrameGeneration);
|
||||||
|
Assert.Equal(0, s.Reflex);
|
||||||
|
Assert.False(s.RayTracing);
|
||||||
|
|
||||||
|
string text = Write(s);
|
||||||
|
Assert.Equal("gfx.antialiasing taa", Line(text, "gfx.antialiasing"));
|
||||||
|
Assert.Equal("gfx.framegeneration off", Line(text, "gfx.framegeneration"));
|
||||||
|
Assert.Equal("gfx.reflex off", Line(text, "gfx.reflex"));
|
||||||
|
Assert.Equal("gfx.raytracing no", Line(text, "gfx.raytracing"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Frame_generation_needs_dlss_even_on_vulkan()
|
||||||
|
{
|
||||||
|
var s = Read("gfxrenderer vulkan\ngfx.antialiasing taa\ngfx.framegeneration x2\ngfx.reflex on\n");
|
||||||
|
|
||||||
|
Assert.Equal(1, s.FrameGeneration);
|
||||||
|
Assert.Equal(1, s.Reflex);
|
||||||
|
Assert.False(GraphicsRules.ReflexForced(s, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Frame_generation_turns_reflex_on()
|
||||||
|
{
|
||||||
|
var s = Read("gfxrenderer vulkan\ngfx.antialiasing dlss\ngfx.framegeneration x2\n");
|
||||||
|
|
||||||
|
Assert.True(GraphicsRules.ReflexForced(s, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Without_a_dlss_platform_dlss_falls_back_to_taa()
|
||||||
|
{
|
||||||
|
var s = Read("gfxrenderer vulkan\ngfx.antialiasing dlss\n", dlssPlatform: false);
|
||||||
|
|
||||||
|
Assert.Equal(AntiAliasingMode.Taa, s.AntiAliasing);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Dlaa_ignores_the_render_scale()
|
||||||
|
{
|
||||||
|
var s = Read("gfxrenderer vulkan\ngfx.antialiasing dlaa\n");
|
||||||
|
Assert.False(GraphicsRules.BufferScaleUsed(s, true));
|
||||||
|
|
||||||
|
s.AntiAliasing = AntiAliasingMode.Dlss;
|
||||||
|
Assert.True(GraphicsRules.BufferScaleUsed(s, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Sizes_are_rounded_down_to_what_the_simulator_uses()
|
||||||
|
{
|
||||||
|
var s = Read("maxtexturesize 16384\nmaxcabtexturesize 3000\nshadowtune 3000 0 250 0\n");
|
||||||
|
|
||||||
|
Assert.Equal(8192, s.MaxTextureSize);
|
||||||
|
Assert.Equal(2048, s.MaxCabTextureSize);
|
||||||
|
Assert.Equal(2048, s.ShadowMapResolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Keys_the_simulator_dropped_are_commented_out()
|
||||||
|
{
|
||||||
|
const string old = "usevbo yes\ngfx.angleplatform vulkan\ngfx.usegles no\ngfx.framebuffer.width 1920\ngfx.framebuffer.height 1080\n";
|
||||||
|
|
||||||
|
string text = Write(Read(old), old);
|
||||||
|
|
||||||
|
foreach (string key in new[] { "usevbo", "gfx.angleplatform", "gfx.usegles", "gfx.framebuffer.width", "gfx.framebuffer.height" })
|
||||||
|
{
|
||||||
|
Assert.Null(Line(text, key));
|
||||||
|
Assert.Contains(Lines(text), l => l.StartsWith("// " + key, StringComparison.Ordinal));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void The_render_scale_reads_the_old_starter_key_when_the_new_one_is_missing()
|
||||||
|
{
|
||||||
|
Assert.Equal(75, Read("starter.bufferscale 75\n").BufferScalePercent);
|
||||||
|
Assert.Equal(50, Read("starter.bufferscale 75\ngfx.buffer.percent 50\n").BufferScalePercent);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[InlineData(GraphicsPreset.Lowest)]
|
||||||
|
[InlineData(GraphicsPreset.Low)]
|
||||||
|
[InlineData(GraphicsPreset.Medium)]
|
||||||
|
[InlineData(GraphicsPreset.High)]
|
||||||
|
[InlineData(GraphicsPreset.Ultra)]
|
||||||
|
public void A_preset_is_recognised_after_it_is_applied_and_survives_a_round_trip(GraphicsPreset preset)
|
||||||
|
{
|
||||||
|
foreach (var backend in new[] { GraphicsBackend.OpenGL, GraphicsBackend.Vulkan })
|
||||||
|
{
|
||||||
|
var s = new SimulatorSettings { Backend = backend };
|
||||||
|
GraphicsPresets.Apply(s, preset, true);
|
||||||
|
|
||||||
|
Assert.Equal(preset, GraphicsPresets.Detect(s, true));
|
||||||
|
Assert.Equal(preset, GraphicsPresets.Detect(Read(Write(s)), true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void A_change_after_a_preset_makes_the_settings_custom()
|
||||||
|
{
|
||||||
|
var s = new SimulatorSettings();
|
||||||
|
GraphicsPresets.Apply(s, GraphicsPreset.High, true);
|
||||||
|
s.Clouds = 4;
|
||||||
|
|
||||||
|
Assert.Equal(GraphicsPreset.Custom, GraphicsPresets.Detect(s, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Presets_leave_alone_what_is_not_a_matter_of_quality()
|
||||||
|
{
|
||||||
|
var s = new SimulatorSettings { Width = 2560, Height = 1440, BufferScalePercent = 67, VSync = true, FieldOfView = 60, MotionBlur = false };
|
||||||
|
|
||||||
|
GraphicsPresets.Apply(s, GraphicsPreset.Lowest, true);
|
||||||
|
|
||||||
|
Assert.Equal((2560, 1440, 67, true, 60, false), (s.Width, s.Height, s.BufferScalePercent, s.VSync, s.FieldOfView, s.MotionBlur));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Ray_tracing_comes_with_ultra_on_vulkan_only()
|
||||||
|
{
|
||||||
|
var vulkan = new SimulatorSettings { Backend = GraphicsBackend.Vulkan };
|
||||||
|
var opengl = new SimulatorSettings { Backend = GraphicsBackend.OpenGL };
|
||||||
|
|
||||||
|
GraphicsPresets.Apply(vulkan, GraphicsPreset.Ultra, true);
|
||||||
|
GraphicsPresets.Apply(opengl, GraphicsPreset.Ultra, true);
|
||||||
|
|
||||||
|
Assert.True(vulkan.RayTracing);
|
||||||
|
Assert.False(opengl.RayTracing);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void A_preset_keeps_dlss_on_vulkan()
|
||||||
|
{
|
||||||
|
var s = new SimulatorSettings { Backend = GraphicsBackend.Vulkan, AntiAliasing = AntiAliasingMode.Dlss };
|
||||||
|
|
||||||
|
GraphicsPresets.Apply(s, GraphicsPreset.Ultra, true);
|
||||||
|
|
||||||
|
Assert.Equal(AntiAliasingMode.Dlss, s.AntiAliasing);
|
||||||
|
Assert.Equal(GraphicsPreset.Ultra, GraphicsPresets.Detect(s, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void An_import_takes_the_settings_but_keeps_this_installations_simulator_and_the_unmanaged_lines()
|
||||||
|
{
|
||||||
|
var installation = WithIni("starter.exe.auto no\nstarter.exe.path eu07_local.exe\ncalibratein 0 0 0 0\ngfx.clouds low\n");
|
||||||
|
installation.Files.WithFile("/backup/eu07.ini", "starter.exe.auto no\nstarter.exe.path eu07_other.exe\ngfx.clouds ultra\ngfxrenderer vulkan\n");
|
||||||
|
|
||||||
|
Assert.True(installation.SettingsStore.ImportFrom("/backup/eu07.ini"));
|
||||||
|
var s = installation.SettingsStore.Settings;
|
||||||
|
Assert.Equal(4, s.Clouds);
|
||||||
|
Assert.Equal(GraphicsBackend.Vulkan, s.Backend);
|
||||||
|
Assert.Equal("eu07_local.exe", s.ExecutablePath);
|
||||||
|
|
||||||
|
// Nothing is written until saved, and the save keeps the user's own lines.
|
||||||
|
Assert.Contains("gfx.clouds low", installation.Files.ReadAllText(UserIni));
|
||||||
|
installation.SettingsStore.Save();
|
||||||
|
string saved = installation.Files.ReadAllText(UserIni);
|
||||||
|
Assert.Contains("calibratein 0 0 0 0", saved);
|
||||||
|
Assert.Contains("gfx.clouds ultra", saved);
|
||||||
|
Assert.Contains("starter.exe.path eu07_local.exe", saved);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void An_import_of_a_missing_file_changes_nothing()
|
||||||
|
{
|
||||||
|
var installation = WithIni("gfx.clouds low\n");
|
||||||
|
|
||||||
|
Assert.False(installation.SettingsStore.ImportFrom("/nowhere/eu07.ini"));
|
||||||
|
Assert.Equal(1, installation.SettingsStore.Settings.Clouds);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void An_export_writes_a_complete_file_elsewhere_and_leaves_the_users_one_alone()
|
||||||
|
{
|
||||||
|
var installation = WithIni("calibratein 0 0 0 0\ngfx.clouds low\n");
|
||||||
|
installation.SettingsStore.Settings.Clouds = 3;
|
||||||
|
|
||||||
|
Assert.True(installation.SettingsStore.ExportTo("/export/eu07.ini"));
|
||||||
|
|
||||||
|
string exported = installation.Files.ReadAllText("/export/eu07.ini");
|
||||||
|
Assert.Contains("calibratein 0 0 0 0", exported);
|
||||||
|
Assert.Contains("gfx.clouds high", exported);
|
||||||
|
Assert.Contains("gfx.clouds low", installation.Files.ReadAllText(UserIni));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void The_dlss_libraries_are_looked_for_next_to_a_windows_build()
|
||||||
|
{
|
||||||
|
var files = new InMemoryFileSystem()
|
||||||
|
.WithDirectory(TestInstallation.Root)
|
||||||
|
.WithExecutable(TestInstallation.At("eu07.exe"), "MZ binary")
|
||||||
|
.WithFile(TestInstallation.At("nvngx_dlss.dll"), "dll");
|
||||||
|
var installation = new TestInstallation(files);
|
||||||
|
|
||||||
|
Assert.Equal((true, false), installation.Executables.DlssLibraries(TestInstallation.At("eu07.exe")));
|
||||||
|
|
||||||
|
files.WithFile(TestInstallation.At("nvngx_dlssg.dll"), "dll");
|
||||||
|
Assert.Equal((true, true), installation.Executables.DlssLibraries(TestInstallation.At("eu07.exe")));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void The_dlss_libraries_of_a_linux_build_are_the_shared_objects()
|
||||||
|
{
|
||||||
|
var files = new InMemoryFileSystem()
|
||||||
|
.WithDirectory(TestInstallation.Root)
|
||||||
|
.WithExecutable(TestInstallation.At("eu07"), "\u007fELF binary")
|
||||||
|
.WithFile(TestInstallation.At("libnvidia-ngx-dlssg.so.310.4.0"), "so");
|
||||||
|
var installation = new TestInstallation(files);
|
||||||
|
|
||||||
|
Assert.Equal((false, true), installation.Executables.DlssLibraries(TestInstallation.At("eu07")));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void A_later_line_moved_up_keeps_the_index_of_every_key()
|
||||||
|
{
|
||||||
|
var c = ConfigFile.Parse("a 1\nb 2\nc 3\n");
|
||||||
|
|
||||||
|
c.MoveAfter("a", "c");
|
||||||
|
|
||||||
|
Assert.Equal("b 2\nc 3\na 1\n", c.ToText().Replace("\r\n", "\n"));
|
||||||
|
Assert.True(c.LineOf("a") > c.LineOf("c"));
|
||||||
|
c.Set("b", "9");
|
||||||
|
Assert.Equal("b 9\nc 3\na 1\n", c.ToText().Replace("\r\n", "\n"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -50,7 +50,7 @@ public sealed class AppServices
|
|||||||
State = new AppState();
|
State = new AppState();
|
||||||
|
|
||||||
Executables = new ExecutableLocator(files, paths, environment, log);
|
Executables = new ExecutableLocator(files, paths, environment, log);
|
||||||
SettingsStore = new SettingsStore(files, clock, log, settingsPaths, new SettingsSerializer(), Executables);
|
SettingsStore = new SettingsStore(files, clock, log, settingsPaths, new SettingsSerializer(dlssPlatform: !environment.IsMacOS), Executables);
|
||||||
MissingVehicleLog = new MissingVehicleLog(SettingsStore.Settings, MissingAssets, Library, log);
|
MissingVehicleLog = new MissingVehicleLog(SettingsStore.Settings, MissingAssets, Library, log);
|
||||||
Favorites = new FavoriteSceneries(files, log, settingsPaths.FavoritesPath());
|
Favorites = new FavoriteSceneries(files, log, settingsPaths.FavoritesPath());
|
||||||
StartSimulation = new StartSimulation(State, SettingsStore, Library.Vehicles, Executables, files, paths,
|
StartSimulation = new StartSimulation(State, SettingsStore, Library.Vehicles, Executables, files, paths,
|
||||||
|
|||||||
@@ -75,6 +75,68 @@ public sealed class SettingsStore
|
|||||||
TouchConfigAge();
|
TouchConfigAge();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Whether the simulator can have DLSS on this platform at all.</summary>
|
||||||
|
public bool DlssPlatform => _serializer.DlssPlatform;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Takes the settings of another eu07.ini (a backup, a file from another machine)
|
||||||
|
/// into the current ones, keeping what belongs to this installation: the chosen
|
||||||
|
/// simulator, the last scenery and the window state. The lines of this user's
|
||||||
|
/// file the starter does not manage stay as they are. Nothing is written until Save.
|
||||||
|
/// </summary>
|
||||||
|
public bool ImportFrom(string path)
|
||||||
|
{
|
||||||
|
ConfigFile imported;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
imported = ConfigFile.Parse(_files.ReadAllText(path, _encoding));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Log($"importing {path}", ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var s = Settings;
|
||||||
|
bool selectAutomatically = s.SelectExeAutomatically;
|
||||||
|
string executable = s.ExecutablePath;
|
||||||
|
string lastScenery = s.LastScenery;
|
||||||
|
bool maximized = s.WindowMaximized;
|
||||||
|
|
||||||
|
_serializer.Read(s, imported);
|
||||||
|
|
||||||
|
s.SelectExeAutomatically = selectAutomatically;
|
||||||
|
s.ExecutablePath = executable;
|
||||||
|
s.LastScenery = lastScenery;
|
||||||
|
s.WindowMaximized = maximized;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the settings as a complete eu07.ini somewhere else - this user's file
|
||||||
|
/// with the settings applied - leaving the file itself and its state alone.
|
||||||
|
/// </summary>
|
||||||
|
public bool ExportTo(string path)
|
||||||
|
{
|
||||||
|
var copy = ConfigFile.Parse(_config.ToText());
|
||||||
|
_serializer.Write(Settings, copy);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string? directory = Path.GetDirectoryName(path);
|
||||||
|
if (!string.IsNullOrEmpty(directory))
|
||||||
|
_files.CreateDirectory(directory);
|
||||||
|
|
||||||
|
_files.WriteAllText(path, copy.ToText(), _encoding);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Log($"exporting {path}", ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void CaptureAndSave()
|
public void CaptureAndSave()
|
||||||
{
|
{
|
||||||
_capture?.CaptureInto(Settings);
|
_capture?.CaptureInto(Settings);
|
||||||
|
|||||||
@@ -32,6 +32,28 @@ public sealed class ConfigFile
|
|||||||
|
|
||||||
public bool Has(string key) => _index.ContainsKey(key);
|
public bool Has(string key) => _index.ContainsKey(key);
|
||||||
|
|
||||||
|
/// <summary>The line the key is on, or -1. The simulator reads the file top down, so a later line wins.</summary>
|
||||||
|
public int LineOf(string key) => _index.TryGetValue(key, out int i) ? i : -1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Moves the line of <paramref name="key"/> right below that of <paramref name="anchor"/>
|
||||||
|
/// when it is above it, for keys the simulator lets override one another.
|
||||||
|
/// </summary>
|
||||||
|
public void MoveAfter(string key, string anchor)
|
||||||
|
{
|
||||||
|
if (!_index.TryGetValue(key, out int from) || !_index.TryGetValue(anchor, out int to) || from > to)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string line = _lines[from];
|
||||||
|
_lines.RemoveAt(from);
|
||||||
|
_lines.Insert(to, line);
|
||||||
|
|
||||||
|
_index.Clear();
|
||||||
|
for (int i = 0; i < _lines.Count; i++)
|
||||||
|
if (TryParseKey(_lines[i], out string k))
|
||||||
|
_index[k] = i;
|
||||||
|
}
|
||||||
|
|
||||||
public string? GetRaw(string key)
|
public string? GetRaw(string key)
|
||||||
{
|
{
|
||||||
if (!_index.TryGetValue(key, out int i))
|
if (!_index.TryGetValue(key, out int i))
|
||||||
|
|||||||
151
StarterNG/Domain/Settings/GraphicsPresets.cs
Normal file
151
StarterNG/Domain/Settings/GraphicsPresets.cs
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace StarterNG.Domain.Settings;
|
||||||
|
|
||||||
|
public enum GraphicsPreset { Lowest, Low, Medium, High, Ultra, Custom }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Quality presets of the starter: one set of graphics settings each. A preset
|
||||||
|
/// leaves alone what is a matter of taste or of the machine rather than of quality
|
||||||
|
/// (resolution, render scale, vsync, field of view, motion blur, chromatic
|
||||||
|
/// aberration) and keeps DLSS when it is on, since that is a choice of the
|
||||||
|
/// anti-aliasing the presets cannot make better. Ray tracing is only for Vulkan.
|
||||||
|
/// </summary>
|
||||||
|
public static class GraphicsPresets
|
||||||
|
{
|
||||||
|
public static readonly GraphicsPreset[] All =
|
||||||
|
{
|
||||||
|
GraphicsPreset.Lowest, GraphicsPreset.Low, GraphicsPreset.Medium, GraphicsPreset.High, GraphicsPreset.Ultra
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>The settings a preset governs. Doubles are kept in hundredths so equality is exact.</summary>
|
||||||
|
private sealed record Quality(
|
||||||
|
int Texture, int CabTexture, int Anisotropy, AntiAliasingMode AntiAliasing,
|
||||||
|
int DrawRange, int Spline, int DynamicLights,
|
||||||
|
bool Shadows, int ShadowMap, int ShadowRange, int ShadowRank, int LightShadows, int ContactShadows,
|
||||||
|
int Ao, int AoSlices, int AoSteps,
|
||||||
|
int ReflectionsFidelity, int ReflectionsFramerate, int Ssr, bool RayTracing,
|
||||||
|
bool VolumetricFog, int FogQuality, int Clouds, bool CloudShadows,
|
||||||
|
bool Grass, int GrassDistance, int GrassDensityPercent,
|
||||||
|
int SmokeFidelity, int Precipitation, bool Bloom, bool ExtraEffects);
|
||||||
|
|
||||||
|
private static Quality Table(GraphicsPreset preset) => preset switch
|
||||||
|
{
|
||||||
|
GraphicsPreset.Lowest => new Quality(
|
||||||
|
1024, 1024, 1, AntiAliasingMode.Off,
|
||||||
|
1, 1, 3,
|
||||||
|
false, 1024, 75, 1, 0, 0,
|
||||||
|
0, 3, 4,
|
||||||
|
0, 5, 0, false,
|
||||||
|
false, 1, 0, false,
|
||||||
|
false, 60, 100,
|
||||||
|
1, 16384, false, false),
|
||||||
|
GraphicsPreset.Low => new Quality(
|
||||||
|
2048, 2048, 4, AntiAliasingMode.Msaa2,
|
||||||
|
2, 2, 5,
|
||||||
|
true, 1024, 150, 2, 1, 0,
|
||||||
|
1, 3, 4,
|
||||||
|
0, 10, 1, false,
|
||||||
|
true, 1, 1, false,
|
||||||
|
true, 40, 50,
|
||||||
|
1, 32768, true, true),
|
||||||
|
GraphicsPreset.Medium => new Quality(
|
||||||
|
4096, 4096, 8, AntiAliasingMode.Msaa2,
|
||||||
|
3, 3, 7,
|
||||||
|
true, 2048, 250, 3, 2, 0,
|
||||||
|
2, 3, 4,
|
||||||
|
1, 30, 2, false,
|
||||||
|
true, 2, 2, true,
|
||||||
|
true, 60, 100,
|
||||||
|
2, 65536, true, true),
|
||||||
|
GraphicsPreset.High => new Quality(
|
||||||
|
4096, 4096, 16, AntiAliasingMode.Msaa4,
|
||||||
|
3, 4, 7,
|
||||||
|
true, 4096, 300, 3, 3, 1,
|
||||||
|
2, 4, 6,
|
||||||
|
2, 30, 2, false,
|
||||||
|
true, 3, 3, true,
|
||||||
|
true, 90, 100,
|
||||||
|
3, 65536, true, true),
|
||||||
|
GraphicsPreset.Ultra => new Quality(
|
||||||
|
8192, 8192, 16, AntiAliasingMode.Msaa8,
|
||||||
|
3, 4, 7,
|
||||||
|
true, 8192, 400, 3, 3, 3,
|
||||||
|
2, 6, 8,
|
||||||
|
2, 60, 3, true,
|
||||||
|
true, 4, 4, true,
|
||||||
|
true, 120, 150,
|
||||||
|
4, 131072, true, true),
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(preset), preset, null)
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>A preset as it lands on these settings: DLSS kept where it runs, ray tracing on Vulkan only.</summary>
|
||||||
|
private static Quality Resolved(GraphicsPreset preset, SimulatorSettings s, bool dlssPlatform)
|
||||||
|
{
|
||||||
|
var q = Table(preset);
|
||||||
|
if (GraphicsRules.DlssActive(s, dlssPlatform))
|
||||||
|
q = q with { AntiAliasing = s.AntiAliasing };
|
||||||
|
if (!GraphicsRules.RayTracingAllowed(s))
|
||||||
|
q = q with { RayTracing = false };
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Quality Of(SimulatorSettings s) => new(
|
||||||
|
s.MaxTextureSize, s.MaxCabTextureSize, s.TextureFiltering, s.AntiAliasing,
|
||||||
|
(int)Math.Round(s.DrawRangeFactor), s.SplineFidelity, s.DynamicLights,
|
||||||
|
s.RenderShadows, s.ShadowMapResolution, s.ShadowProjectionRange, s.ShadowRankCutoff, s.LightShadows, s.ContactShadows,
|
||||||
|
s.AmbientOcclusion, s.AoSlices, s.AoSteps,
|
||||||
|
s.ReflectionsFidelity, s.ReflectionsFramerate, s.Ssr, s.RayTracing,
|
||||||
|
s.VolumetricFog, s.FogQuality, s.Clouds, s.CloudShadows,
|
||||||
|
s.Grass, s.GrassDistance, (int)Math.Round(s.GrassDensity * 100),
|
||||||
|
s.SmokeFidelity, s.PrecipitationParticles, s.Bloom, s.ExtraEffects);
|
||||||
|
|
||||||
|
public static void Apply(SimulatorSettings s, GraphicsPreset preset, bool dlssPlatform)
|
||||||
|
{
|
||||||
|
if (preset == GraphicsPreset.Custom)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var q = Resolved(preset, s, dlssPlatform);
|
||||||
|
s.MaxTextureSize = q.Texture;
|
||||||
|
s.MaxCabTextureSize = q.CabTexture;
|
||||||
|
s.TextureFiltering = q.Anisotropy;
|
||||||
|
s.AntiAliasing = q.AntiAliasing;
|
||||||
|
s.DrawRangeFactor = q.DrawRange;
|
||||||
|
s.SplineFidelity = q.Spline;
|
||||||
|
s.DynamicLights = q.DynamicLights;
|
||||||
|
s.RenderShadows = q.Shadows;
|
||||||
|
s.ShadowMapResolution = q.ShadowMap;
|
||||||
|
s.ShadowProjectionRange = q.ShadowRange;
|
||||||
|
s.ShadowRankCutoff = q.ShadowRank;
|
||||||
|
s.LightShadows = q.LightShadows;
|
||||||
|
s.ContactShadows = q.ContactShadows;
|
||||||
|
s.AmbientOcclusion = q.Ao;
|
||||||
|
s.AoSlices = q.AoSlices;
|
||||||
|
s.AoSteps = q.AoSteps;
|
||||||
|
s.ReflectionsFidelity = q.ReflectionsFidelity;
|
||||||
|
s.ReflectionsFramerate = q.ReflectionsFramerate;
|
||||||
|
s.Ssr = q.Ssr;
|
||||||
|
s.RayTracing = q.RayTracing;
|
||||||
|
s.VolumetricFog = q.VolumetricFog;
|
||||||
|
s.FogQuality = q.FogQuality;
|
||||||
|
s.Clouds = q.Clouds;
|
||||||
|
s.CloudShadows = q.CloudShadows;
|
||||||
|
s.Grass = q.Grass;
|
||||||
|
s.GrassDistance = q.GrassDistance;
|
||||||
|
s.GrassDensity = q.GrassDensityPercent / 100.0;
|
||||||
|
s.SmokeFidelity = q.SmokeFidelity;
|
||||||
|
s.PrecipitationParticles = q.Precipitation;
|
||||||
|
s.Bloom = q.Bloom;
|
||||||
|
s.ExtraEffects = q.ExtraEffects;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>The preset these settings are exactly, or Custom.</summary>
|
||||||
|
public static GraphicsPreset Detect(SimulatorSettings s, bool dlssPlatform)
|
||||||
|
{
|
||||||
|
var current = Of(s);
|
||||||
|
foreach (var preset in All)
|
||||||
|
if (Resolved(preset, s, dlssPlatform) == current)
|
||||||
|
return preset;
|
||||||
|
return GraphicsPreset.Custom;
|
||||||
|
}
|
||||||
|
}
|
||||||
105
StarterNG/Domain/Settings/GraphicsRules.cs
Normal file
105
StarterNG/Domain/Settings/GraphicsRules.cs
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
namespace StarterNG.Domain.Settings;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// What the simulator does with combinations of graphics settings, mirrored here so
|
||||||
|
/// the starter only offers what takes effect and writes eu07.ini the way the
|
||||||
|
/// simulator will run it (utilities/Globals.cpp, rendering/vulkan14, rendering/opengl46).
|
||||||
|
/// </summary>
|
||||||
|
public static class GraphicsRules
|
||||||
|
{
|
||||||
|
public static bool IsDlss(AntiAliasingMode mode) => mode is AntiAliasingMode.Dlss or AntiAliasingMode.Dlaa;
|
||||||
|
|
||||||
|
public static bool IsTemporal(AntiAliasingMode mode) => mode == AntiAliasingMode.Taa || IsDlss(mode);
|
||||||
|
|
||||||
|
public static bool IsVulkan(SimulatorSettings s) => s.Backend == GraphicsBackend.Vulkan;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DLSS is the Vulkan renderer's only (the OpenGL one takes TAA instead), and the
|
||||||
|
/// DLSS SDK has no macOS libraries.
|
||||||
|
/// </summary>
|
||||||
|
public static bool DlssAllowed(SimulatorSettings s, bool dlssPlatform) => dlssPlatform && IsVulkan(s);
|
||||||
|
|
||||||
|
public static bool DlssActive(SimulatorSettings s, bool dlssPlatform) =>
|
||||||
|
DlssAllowed(s, dlssPlatform) && IsDlss(s.AntiAliasing);
|
||||||
|
|
||||||
|
/// <summary>The frame generation goes with gfx.antialiasing dlss or dlaa, nothing else.</summary>
|
||||||
|
public static bool FrameGenerationAllowed(SimulatorSettings s, bool dlssPlatform) => DlssActive(s, dlssPlatform);
|
||||||
|
|
||||||
|
/// <summary>Reflex (VK_NV_low_latency2) is the Vulkan renderer's only.</summary>
|
||||||
|
public static bool ReflexAllowed(SimulatorSettings s) => IsVulkan(s);
|
||||||
|
|
||||||
|
/// <summary>The frame generation turns Reflex on whatever gfx.reflex says.</summary>
|
||||||
|
public static bool ReflexForced(SimulatorSettings s, bool dlssPlatform) =>
|
||||||
|
FrameGenerationAllowed(s, dlssPlatform) && s.FrameGeneration > 1;
|
||||||
|
|
||||||
|
/// <summary>Ray traced reflections: the Vulkan renderer on a GPU with ray queries.</summary>
|
||||||
|
public static bool RayTracingAllowed(SimulatorSettings s) => IsVulkan(s);
|
||||||
|
|
||||||
|
/// <summary>The render scale is ignored by DLAA, which always draws at the size of the window.</summary>
|
||||||
|
public static bool BufferScaleUsed(SimulatorSettings s, bool dlssPlatform) =>
|
||||||
|
!(DlssActive(s, dlssPlatform) && s.AntiAliasing == AntiAliasingMode.Dlaa);
|
||||||
|
|
||||||
|
/// <summary>TAA and DLSS run in the post-processing which gfx.skippipeline leaves out.</summary>
|
||||||
|
public static bool TemporalWithoutPipeline(SimulatorSettings s) => s.SkipPipeline && IsTemporal(s.AntiAliasing);
|
||||||
|
|
||||||
|
/// <summary>With the clustered lights the headlights come from the clusters; dynamiclights only caps the old path.</summary>
|
||||||
|
public static bool DynamicLightsUsed(SimulatorSettings s) => !s.LightsClustered;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Brings the settings to what the simulator would run with: the Vulkan-only
|
||||||
|
/// features off on OpenGL, DLSS falling back to TAA, values within the ranges
|
||||||
|
/// the simulator clamps them to.
|
||||||
|
/// </summary>
|
||||||
|
public static void Normalize(SimulatorSettings s, bool dlssPlatform)
|
||||||
|
{
|
||||||
|
if (IsDlss(s.AntiAliasing) && !DlssAllowed(s, dlssPlatform))
|
||||||
|
s.AntiAliasing = AntiAliasingMode.Taa;
|
||||||
|
|
||||||
|
s.FrameGeneration = FrameGenerationAllowed(s, dlssPlatform) ? Clamp(s.FrameGeneration, 1, 4) : 1;
|
||||||
|
s.Reflex = ReflexAllowed(s) ? Clamp(s.Reflex, 0, 2) : 0;
|
||||||
|
if (!RayTracingAllowed(s))
|
||||||
|
s.RayTracing = false;
|
||||||
|
|
||||||
|
if (!IsKnownDlssPreset(s.DlssPreset))
|
||||||
|
s.DlssPreset = "default";
|
||||||
|
|
||||||
|
s.MaxTextureSize = PowerOfTwo(s.MaxTextureSize, 64, 8192);
|
||||||
|
s.MaxCabTextureSize = PowerOfTwo(s.MaxCabTextureSize, 512, 8192);
|
||||||
|
s.ShadowMapResolution = PowerOfTwo(s.ShadowMapResolution, 512, 8192);
|
||||||
|
s.BufferScalePercent = Clamp(s.BufferScalePercent, 25, 200);
|
||||||
|
s.LightShadows = Clamp(s.LightShadows, 0, 3);
|
||||||
|
s.ContactShadows = Clamp(s.ContactShadows, 0, 3);
|
||||||
|
s.AmbientOcclusion = Clamp(s.AmbientOcclusion, 0, 2);
|
||||||
|
s.AoSlices = Clamp(s.AoSlices, 1, 8);
|
||||||
|
s.AoSteps = Clamp(s.AoSteps, 1, 16);
|
||||||
|
s.Ssr = Clamp(s.Ssr, 0, 3);
|
||||||
|
s.RayTracingRange = Clamp(s.RayTracingRange, 10, 5000);
|
||||||
|
s.FogQuality = Clamp(s.FogQuality, 1, 4);
|
||||||
|
s.Clouds = Clamp(s.Clouds, 0, 4);
|
||||||
|
s.GrassDistance = Clamp(s.GrassDistance, 5, 500);
|
||||||
|
s.GrassDensity = s.GrassDensity < 0 ? 0 : (s.GrassDensity > 4 ? 4 : s.GrassDensity);
|
||||||
|
s.PrecipitationParticles = Clamp(s.PrecipitationParticles, 0, 1 << 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly string[] DlssPresets = { "default", "j", "k", "l", "m" };
|
||||||
|
|
||||||
|
public static bool IsKnownDlssPreset(string? preset)
|
||||||
|
{
|
||||||
|
foreach (string known in DlssPresets)
|
||||||
|
if (string.Equals(known, preset, System.StringComparison.OrdinalIgnoreCase))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int Clamp(int v, int lo, int hi) => v < lo ? lo : (v > hi ? hi : v);
|
||||||
|
|
||||||
|
/// <summary>The power of two nearest below, as the simulator rounds texture and shadow map sizes.</summary>
|
||||||
|
private static int PowerOfTwo(int v, int lo, int hi)
|
||||||
|
{
|
||||||
|
v = Clamp(v, lo, hi);
|
||||||
|
int p = lo;
|
||||||
|
while (p * 2 <= v)
|
||||||
|
p *= 2;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,12 @@ public enum ConsistReadyOverride { Scenery = 0, AlwaysCold = 1, AlwaysReady = 2
|
|||||||
|
|
||||||
public enum ExeProblem { None, NotFound, NotExecutable, WrongPlatform }
|
public enum ExeProblem { None, NotFound, NotExecutable, WrongPlatform }
|
||||||
|
|
||||||
|
// gfxrenderer: the opengl 4.6 renderer ("full", which the simulator reads as "default") or the vulkan 1.4 one.
|
||||||
|
public enum GraphicsBackend { OpenGL = 0, Vulkan = 1 }
|
||||||
|
|
||||||
|
// gfx.antialiasing. Dlss and Dlaa are the vulkan renderer's only; the simulator falls back to taa elsewhere.
|
||||||
|
public enum AntiAliasingMode { Off, Msaa2, Msaa4, Msaa8, Taa, Dlss, Dlaa }
|
||||||
|
|
||||||
public sealed class SimulatorSettings
|
public sealed class SimulatorSettings
|
||||||
{
|
{
|
||||||
public bool LanguageWasSet { get; internal set; }
|
public bool LanguageWasSet { get; internal set; }
|
||||||
@@ -37,14 +43,18 @@ public sealed class SimulatorSettings
|
|||||||
public bool LogMissingVehicleFiles;
|
public bool LogMissingVehicleFiles;
|
||||||
public bool DeveloperTools;
|
public bool DeveloperTools;
|
||||||
|
|
||||||
public int RenderEngine;
|
public GraphicsBackend Backend = GraphicsBackend.OpenGL;
|
||||||
|
public string VulkanDevice = "";
|
||||||
public int Width = 1280;
|
public int Width = 1280;
|
||||||
public int Height = 720;
|
public int Height = 720;
|
||||||
public int BufferScalePercent = 100;
|
public int BufferScalePercent = 100;
|
||||||
public int MaxTextureSize = 4096;
|
public int MaxTextureSize = 4096;
|
||||||
public int MaxCabTextureSize = 4096;
|
public int MaxCabTextureSize = 4096;
|
||||||
public int TextureFiltering = 8;
|
public int TextureFiltering = 8;
|
||||||
public int Multisampling = 2;
|
public AntiAliasingMode AntiAliasing = AntiAliasingMode.Msaa4;
|
||||||
|
public string DlssPreset = "default";
|
||||||
|
public int FrameGeneration = 1;
|
||||||
|
public int Reflex;
|
||||||
public int DynamicLights = 7;
|
public int DynamicLights = 7;
|
||||||
public double DrawRangeFactor = 3.0;
|
public double DrawRangeFactor = 3.0;
|
||||||
public bool VSync;
|
public bool VSync;
|
||||||
@@ -54,8 +64,27 @@ public sealed class SimulatorSettings
|
|||||||
public bool MotionBlur = true;
|
public bool MotionBlur = true;
|
||||||
public bool ExtraEffects = true;
|
public bool ExtraEffects = true;
|
||||||
public bool EnvMap = true;
|
public bool EnvMap = true;
|
||||||
public bool UseVbo = true;
|
|
||||||
public bool RenderShadows = true;
|
public bool RenderShadows = true;
|
||||||
|
public bool ShadowSdsm;
|
||||||
|
public int LightShadows = 2;
|
||||||
|
public int ContactShadows;
|
||||||
|
public bool LightsClustered = true;
|
||||||
|
public int AmbientOcclusion = 2;
|
||||||
|
public int AoSlices = 3;
|
||||||
|
public int AoSteps = 4;
|
||||||
|
public int Ssr = 2;
|
||||||
|
public bool RayTracing;
|
||||||
|
public int RayTracingRange = 500;
|
||||||
|
public bool VolumetricFog = true;
|
||||||
|
public int FogQuality = 2;
|
||||||
|
public int Clouds = 2;
|
||||||
|
public bool CloudShadows = true;
|
||||||
|
public bool Grass = true;
|
||||||
|
public int GrassDistance = 60;
|
||||||
|
public double GrassDensity = 1.0;
|
||||||
|
public int PrecipitationParticles = 65536;
|
||||||
|
public bool Bloom = true;
|
||||||
|
public bool AutoExposure = true;
|
||||||
public int ReflectionsFramerate = 60;
|
public int ReflectionsFramerate = 60;
|
||||||
public int ShadowMapResolution = 2048;
|
public int ShadowMapResolution = 2048;
|
||||||
public int ShadowProjectionRange = 250;
|
public int ShadowProjectionRange = 250;
|
||||||
@@ -69,7 +98,6 @@ public sealed class SimulatorSettings
|
|||||||
public int FpsLimit = 30;
|
public int FpsLimit = 30;
|
||||||
public double ShadowAngleLimit = 0.2;
|
public double ShadowAngleLimit = 0.2;
|
||||||
public bool FullscreenWindowed;
|
public bool FullscreenWindowed;
|
||||||
public bool RenderAngleVulkan;
|
|
||||||
|
|
||||||
public int SplineFidelity = 1;
|
public int SplineFidelity = 1;
|
||||||
public bool FullPhysics = true;
|
public bool FullPhysics = true;
|
||||||
@@ -97,7 +125,6 @@ public sealed class SimulatorSettings
|
|||||||
|
|
||||||
public bool CompressTextures = true;
|
public bool CompressTextures = true;
|
||||||
public bool ScaleSpeculars = true;
|
public bool ScaleSpeculars = true;
|
||||||
public bool UseGLES;
|
|
||||||
public bool ShaderGamma;
|
public bool ShaderGamma;
|
||||||
public bool ScreenMipmaps = true;
|
public bool ScreenMipmaps = true;
|
||||||
public bool ExtendedModelConversion;
|
public bool ExtendedModelConversion;
|
||||||
@@ -120,8 +147,8 @@ public sealed class SimulatorSettings
|
|||||||
|
|
||||||
public bool WindowMaximized;
|
public bool WindowMaximized;
|
||||||
|
|
||||||
public static readonly string[] RenderEngines =
|
// "full" rather than "default": every simulator build reads it, the new ones as the opengl 4.6 renderer.
|
||||||
{ "full", "legacy", "simpleshader", "simple", "off", "experimental" };
|
public static readonly string[] RenderEngines = { "full", "vulkan" };
|
||||||
|
|
||||||
public static readonly int[] AnisotropySteps = { 1, 2, 4, 8, 16 };
|
public static readonly int[] AnisotropySteps = { 1, 2, 4, 8, 16 };
|
||||||
|
|
||||||
|
|||||||
@@ -246,6 +246,37 @@ public sealed class ExecutableLocator
|
|||||||
return extension.Length == 0 || extension is ".exe" or ".x86_64" or ".run" or ".appimage";
|
return extension.Length == 0 || extension is ".exe" or ".x86_64" or ".run" or ".appimage";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the NVIDIA libraries of DLSS and of its frame generation sit next to
|
||||||
|
/// the simulator, where it loads them from; without them it runs with TAA.
|
||||||
|
/// The names follow the build: a Windows one wants the DLLs, a Linux one the .so files.
|
||||||
|
/// </summary>
|
||||||
|
public (bool Dlss, bool FrameGeneration) DlssLibraries(string executable)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Resolve hands back either a path of its own search or the bare name of the pick.
|
||||||
|
string full = _files.FileExists(executable) ? executable : FullPath(executable);
|
||||||
|
string? directory = Path.GetDirectoryName(full);
|
||||||
|
if (string.IsNullOrEmpty(directory) || !_files.DirectoryExists(directory))
|
||||||
|
return (false, false);
|
||||||
|
|
||||||
|
bool windowsBuild = _files.FileExists(full)
|
||||||
|
? Format(full) == BinaryFormat.PortableExecutable
|
||||||
|
: _environment.IsWindows;
|
||||||
|
|
||||||
|
return windowsBuild
|
||||||
|
? (Has(directory, "nvngx_dlss.dll"), Has(directory, "nvngx_dlssg.dll"))
|
||||||
|
: (Has(directory, "libnvidia-ngx-dlss.so*"), Has(directory, "libnvidia-ngx-dlssg.so*"));
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return (false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Has(string directory, string pattern) => _files.GetFiles(directory, pattern).Count > 0;
|
||||||
|
|
||||||
private string FullPath(string path) =>
|
private string FullPath(string path) =>
|
||||||
Path.IsPathRooted(path) ? path : Path.Combine(_paths.Root, path);
|
Path.IsPathRooted(path) ? path : Path.Combine(_paths.Root, path);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,16 @@ namespace StarterNG.Infrastructure.Settings;
|
|||||||
|
|
||||||
public sealed class SettingsSerializer
|
public sealed class SettingsSerializer
|
||||||
{
|
{
|
||||||
|
private readonly bool _dlssPlatform;
|
||||||
|
|
||||||
|
/// <param name="dlssPlatform">Whether the simulator can have DLSS here at all (not on macOS).</param>
|
||||||
|
public SettingsSerializer(bool dlssPlatform = true)
|
||||||
|
{
|
||||||
|
_dlssPlatform = dlssPlatform;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DlssPlatform => _dlssPlatform;
|
||||||
|
|
||||||
public void Read(SimulatorSettings s, ConfigFile c)
|
public void Read(SimulatorSettings s, ConfigFile c)
|
||||||
{
|
{
|
||||||
s.LanguageWasSet = c.Has("lang");
|
s.LanguageWasSet = c.Has("lang");
|
||||||
@@ -58,14 +68,18 @@ public sealed class SettingsSerializer
|
|||||||
s.LogMissingVehicleFiles = c.GetBool("starter.logmissingvehicles", false);
|
s.LogMissingVehicleFiles = c.GetBool("starter.logmissingvehicles", false);
|
||||||
s.DeveloperTools = c.GetBool("starter.developertools", false);
|
s.DeveloperTools = c.GetBool("starter.developertools", false);
|
||||||
|
|
||||||
s.RenderEngine = IndexOf(SimulatorSettings.RenderEngines, c.GetString("gfxrenderer", "full"), 0);
|
s.Backend = ParseBackend(c.GetString("gfxrenderer", "full"));
|
||||||
|
s.VulkanDevice = c.GetString("gfx.vulkan.device", "");
|
||||||
s.Width = c.GetInt("width", 1280);
|
s.Width = c.GetInt("width", 1280);
|
||||||
s.Height = c.GetInt("height", 720);
|
s.Height = c.GetInt("height", 720);
|
||||||
s.BufferScalePercent = Clamp(c.GetInt("starter.bufferscale", 100), 50, 200);
|
s.BufferScalePercent = ReadBufferScale(c);
|
||||||
s.MaxTextureSize = c.GetInt("maxtexturesize", 4096);
|
s.MaxTextureSize = c.GetInt("maxtexturesize", 4096);
|
||||||
s.MaxCabTextureSize = c.GetInt("maxcabtexturesize", 4096);
|
s.MaxCabTextureSize = c.GetInt("maxcabtexturesize", 4096);
|
||||||
s.TextureFiltering = c.GetInt("anisotropicfiltering", 8);
|
s.TextureFiltering = c.GetInt("anisotropicfiltering", 8);
|
||||||
s.Multisampling = Clamp(c.GetInt("multisampling", 2), 0, 3);
|
s.AntiAliasing = ReadAntiAliasing(c);
|
||||||
|
s.DlssPreset = c.GetString("gfx.dlss.preset", "default").ToLowerInvariant();
|
||||||
|
s.FrameGeneration = ParseFrameGeneration(FirstToken(c, "gfx.framegeneration"));
|
||||||
|
s.Reflex = ParseReflex(FirstToken(c, "gfx.reflex"));
|
||||||
s.DynamicLights = Clamp(c.GetInt("dynamiclights", 7), 0, 7);
|
s.DynamicLights = Clamp(c.GetInt("dynamiclights", 7), 0, 7);
|
||||||
s.DrawRangeFactor = c.GetDouble("gfx.drawrange.factor.max", 3.0);
|
s.DrawRangeFactor = c.GetDouble("gfx.drawrange.factor.max", 3.0);
|
||||||
s.VSync = c.GetBool("vsync", false);
|
s.VSync = c.GetBool("vsync", false);
|
||||||
@@ -75,8 +89,28 @@ public sealed class SettingsSerializer
|
|||||||
s.MotionBlur = c.GetBool("gfx.postfx.motionblur.enabled", true);
|
s.MotionBlur = c.GetBool("gfx.postfx.motionblur.enabled", true);
|
||||||
s.ExtraEffects = c.GetBool("gfx.extraeffects", true);
|
s.ExtraEffects = c.GetBool("gfx.extraeffects", true);
|
||||||
s.EnvMap = c.GetBool("gfx.envmap.enabled", true);
|
s.EnvMap = c.GetBool("gfx.envmap.enabled", true);
|
||||||
s.UseVbo = c.GetBool("usevbo", true);
|
|
||||||
s.RenderShadows = c.GetBool("shadows", true);
|
s.RenderShadows = c.GetBool("shadows", true);
|
||||||
|
s.ShadowSdsm = c.GetBool("gfx.shadow.sdsm", false);
|
||||||
|
s.LightShadows = ParseLevel(FirstToken(c, "gfx.lights.shadows"), 2, 3);
|
||||||
|
s.ContactShadows = ParseLevel(FirstToken(c, "gfx.contactshadows"), 0, 3);
|
||||||
|
s.LightsClustered = c.GetBool("gfx.lights.clustered", true);
|
||||||
|
s.AmbientOcclusion = ParseAmbientOcclusion(FirstToken(c, "gfx.postfx.ao"));
|
||||||
|
var aoQuality = c.GetTokens("gfx.postfx.ao.quality");
|
||||||
|
s.AoSlices = aoQuality.Length >= 1 ? ParseInt(aoQuality[0], 3) : 3;
|
||||||
|
s.AoSteps = aoQuality.Length >= 2 ? ParseInt(aoQuality[1], 4) : 4;
|
||||||
|
s.Ssr = ParseLevel(FirstToken(c, "gfx.ssr"), 2, 3);
|
||||||
|
s.RayTracing = c.GetBool("gfx.raytracing", false);
|
||||||
|
s.RayTracingRange = (int)Math.Round(c.GetDouble("gfx.raytracing.range", 500));
|
||||||
|
s.VolumetricFog = ParseVolumetricFog(FirstToken(c, "gfx.fog"));
|
||||||
|
s.FogQuality = ParseFogQuality(FirstToken(c, "gfx.fog.quality"));
|
||||||
|
s.Clouds = ParseLevel(FirstToken(c, "gfx.clouds"), 2, 4);
|
||||||
|
s.CloudShadows = c.GetBool("gfx.clouds.shadows", true);
|
||||||
|
s.Grass = c.GetBool("gfx.grass", true);
|
||||||
|
s.GrassDistance = (int)Math.Round(c.GetDouble("gfx.grass.distance", 60));
|
||||||
|
s.GrassDensity = c.GetDouble("gfx.grass.density", 1.0);
|
||||||
|
s.PrecipitationParticles = c.GetInt("gfx.precipitation.particles", 65536);
|
||||||
|
s.Bloom = c.GetBool("gfx.postfx.bloom", true);
|
||||||
|
s.AutoExposure = c.GetBool("gfx.postfx.autoexposure", true);
|
||||||
s.ReflectionsFramerate = c.GetInt("gfx.reflections.framerate", 60);
|
s.ReflectionsFramerate = c.GetInt("gfx.reflections.framerate", 60);
|
||||||
|
|
||||||
var shadowTune = c.GetTokens("shadowtune");
|
var shadowTune = c.GetTokens("shadowtune");
|
||||||
@@ -94,7 +128,6 @@ public sealed class SettingsSerializer
|
|||||||
s.FpsLimit = Clamp(c.GetInt("fpslimit", 30), 1, 100);
|
s.FpsLimit = Clamp(c.GetInt("fpslimit", 30), 1, 100);
|
||||||
s.ShadowAngleLimit = c.GetDouble("gfx.shadow.angle.min", 0.2);
|
s.ShadowAngleLimit = c.GetDouble("gfx.shadow.angle.min", 0.2);
|
||||||
s.FullscreenWindowed = c.GetBool("fullscreenwindowed", false);
|
s.FullscreenWindowed = c.GetBool("fullscreenwindowed", false);
|
||||||
s.RenderAngleVulkan = string.Equals(c.GetString("gfx.angleplatform", ""), "vulkan", StringComparison.OrdinalIgnoreCase);
|
|
||||||
|
|
||||||
s.SplineFidelity = Clamp(c.GetInt("splinefidelity", 1), 1, 4);
|
s.SplineFidelity = Clamp(c.GetInt("splinefidelity", 1), 1, 4);
|
||||||
s.FullPhysics = c.GetBool("fullphysics", true);
|
s.FullPhysics = c.GetBool("fullphysics", true);
|
||||||
@@ -125,7 +158,6 @@ public sealed class SettingsSerializer
|
|||||||
|
|
||||||
s.CompressTextures = c.GetBool("compresstex", true);
|
s.CompressTextures = c.GetBool("compresstex", true);
|
||||||
s.ScaleSpeculars = c.GetBool("scalespeculars", true);
|
s.ScaleSpeculars = c.GetBool("scalespeculars", true);
|
||||||
s.UseGLES = c.GetBool("gfx.usegles", false);
|
|
||||||
s.ShaderGamma = c.GetBool("gfx.shadergamma", false);
|
s.ShaderGamma = c.GetBool("gfx.shadergamma", false);
|
||||||
s.ScreenMipmaps = c.GetBool("python.mipmaps", true);
|
s.ScreenMipmaps = c.GetBool("python.mipmaps", true);
|
||||||
s.ExtendedModelConversion = c.GetInt("convertmodels", 0) != 0;
|
s.ExtendedModelConversion = c.GetInt("convertmodels", 0) != 0;
|
||||||
@@ -151,15 +183,25 @@ public sealed class SettingsSerializer
|
|||||||
s.HideArchivalVehicles = c.GetBool("starter.hide.archivalvehicles", true);
|
s.HideArchivalVehicles = c.GetBool("starter.hide.archivalvehicles", true);
|
||||||
s.LastScenery = c.GetString("starter.last.scenery", "");
|
s.LastScenery = c.GetString("starter.last.scenery", "");
|
||||||
s.WindowMaximized = c.GetBool("starter.window.maximized", false);
|
s.WindowMaximized = c.GetBool("starter.window.maximized", false);
|
||||||
|
|
||||||
|
GraphicsRules.Normalize(s, _dlssPlatform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keys the simulator no longer reads (it logs each of them on every start); commented out on save.
|
||||||
private static readonly string[] ObsoleteKeys =
|
private static readonly string[] ObsoleteKeys =
|
||||||
{
|
{
|
||||||
"gfx.postfx.tonemapping",
|
"gfx.postfx.tonemapping",
|
||||||
|
"usevbo",
|
||||||
|
"gfx.angleplatform",
|
||||||
|
"gfx.usegles",
|
||||||
|
"gfx.framebuffer.width",
|
||||||
|
"gfx.framebuffer.height",
|
||||||
};
|
};
|
||||||
|
|
||||||
public void Write(SimulatorSettings s, ConfigFile c)
|
public void Write(SimulatorSettings s, ConfigFile c)
|
||||||
{
|
{
|
||||||
|
GraphicsRules.Normalize(s, _dlssPlatform);
|
||||||
|
|
||||||
foreach (string key in ObsoleteKeys)
|
foreach (string key in ObsoleteKeys)
|
||||||
c.Remove(key);
|
c.Remove(key);
|
||||||
|
|
||||||
@@ -198,18 +240,24 @@ public sealed class SettingsSerializer
|
|||||||
c.SetBool("starter.logmissingvehicles", s.LogMissingVehicleFiles);
|
c.SetBool("starter.logmissingvehicles", s.LogMissingVehicleFiles);
|
||||||
c.SetBool("starter.developertools", s.DeveloperTools);
|
c.SetBool("starter.developertools", s.DeveloperTools);
|
||||||
|
|
||||||
c.Set("gfxrenderer", SimulatorSettings.RenderEngines[Clamp(s.RenderEngine, 0, SimulatorSettings.RenderEngines.Length - 1)]);
|
c.Set("gfxrenderer", SimulatorSettings.RenderEngines[(int)s.Backend]);
|
||||||
|
if (!string.IsNullOrWhiteSpace(s.VulkanDevice)) c.Set("gfx.vulkan.device", s.VulkanDevice.Trim()); else c.Remove("gfx.vulkan.device");
|
||||||
c.SetInt("width", s.Width);
|
c.SetInt("width", s.Width);
|
||||||
c.SetInt("height", s.Height);
|
c.SetInt("height", s.Height);
|
||||||
c.SetInt("starter.bufferscale", s.BufferScalePercent);
|
c.SetInt("starter.bufferscale", s.BufferScalePercent);
|
||||||
int fbw = (int)Math.Round(s.Width * s.BufferScalePercent / 100.0);
|
// Over 4 the simulator takes it as percents.
|
||||||
int fbh = (int)Math.Round(s.Height * s.BufferScalePercent / 100.0);
|
c.SetInt("gfx.buffer.percent", s.BufferScalePercent);
|
||||||
c.SetInt("gfx.framebuffer.width", fbw);
|
|
||||||
c.SetInt("gfx.framebuffer.height", fbh);
|
|
||||||
c.SetInt("maxtexturesize", s.MaxTextureSize);
|
c.SetInt("maxtexturesize", s.MaxTextureSize);
|
||||||
c.SetInt("maxcabtexturesize", s.MaxCabTextureSize);
|
c.SetInt("maxcabtexturesize", s.MaxCabTextureSize);
|
||||||
c.SetInt("anisotropicfiltering", s.TextureFiltering);
|
c.SetInt("anisotropicfiltering", s.TextureFiltering);
|
||||||
c.SetInt("multisampling", s.Multisampling);
|
// multisampling is what older simulators read; gfx.antialiasing overrides it in the new ones, but only from
|
||||||
|
// a later line, since each key sets the mode as it is read.
|
||||||
|
c.SetInt("multisampling", MultisamplingLevel(s.AntiAliasing));
|
||||||
|
c.Set("gfx.antialiasing", AntiAliasingToken(s.AntiAliasing));
|
||||||
|
c.MoveAfter("gfx.antialiasing", "multisampling");
|
||||||
|
c.Set("gfx.dlss.preset", s.DlssPreset);
|
||||||
|
c.Set("gfx.framegeneration", s.FrameGeneration > 1 ? $"x{s.FrameGeneration}" : "off");
|
||||||
|
c.Set("gfx.reflex", s.Reflex switch { 1 => "on", 2 => "boost", _ => "off" });
|
||||||
c.SetInt("dynamiclights", s.DynamicLights);
|
c.SetInt("dynamiclights", s.DynamicLights);
|
||||||
c.SetDouble("gfx.drawrange.factor.max", s.DrawRangeFactor);
|
c.SetDouble("gfx.drawrange.factor.max", s.DrawRangeFactor);
|
||||||
c.SetBool("vsync", s.VSync);
|
c.SetBool("vsync", s.VSync);
|
||||||
@@ -219,9 +267,29 @@ public sealed class SettingsSerializer
|
|||||||
c.SetBool("gfx.postfx.motionblur.enabled", s.MotionBlur);
|
c.SetBool("gfx.postfx.motionblur.enabled", s.MotionBlur);
|
||||||
c.SetBool("gfx.extraeffects", s.ExtraEffects);
|
c.SetBool("gfx.extraeffects", s.ExtraEffects);
|
||||||
c.SetBool("gfx.envmap.enabled", s.EnvMap);
|
c.SetBool("gfx.envmap.enabled", s.EnvMap);
|
||||||
c.SetBool("usevbo", s.UseVbo);
|
|
||||||
c.SetBool("shadows", s.RenderShadows);
|
c.SetBool("shadows", s.RenderShadows);
|
||||||
c.SetBool("gfx.shadowmap.enabled", s.RenderShadows);
|
c.SetBool("gfx.shadowmap.enabled", s.RenderShadows);
|
||||||
|
c.SetBool("gfx.shadow.sdsm", s.ShadowSdsm);
|
||||||
|
c.Set("gfx.lights.shadows", LevelToken(s.LightShadows));
|
||||||
|
c.Set("gfx.contactshadows", LevelToken(s.ContactShadows));
|
||||||
|
c.SetBool("gfx.lights.clustered", s.LightsClustered);
|
||||||
|
c.Set("gfx.postfx.ao", s.AmbientOcclusion switch { 1 => "ssao", 2 => "gtao", _ => "no" });
|
||||||
|
c.Set("gfx.postfx.ao.quality", $"{s.AoSlices} {s.AoSteps}");
|
||||||
|
c.Set("gfx.ssr", LevelToken(s.Ssr));
|
||||||
|
c.SetBool("gfx.raytracing", s.RayTracing);
|
||||||
|
c.SetInt("gfx.raytracing.range", s.RayTracingRange);
|
||||||
|
c.Set("gfx.fog", s.VolumetricFog ? "yes" : "analytic");
|
||||||
|
c.Set("gfx.fog.quality", LevelToken(s.FogQuality));
|
||||||
|
c.Set("gfx.clouds", LevelToken(s.Clouds));
|
||||||
|
c.SetBool("gfx.clouds.shadows", s.CloudShadows);
|
||||||
|
c.SetBool("gfx.grass", s.Grass);
|
||||||
|
c.SetInt("gfx.grass.distance", s.GrassDistance);
|
||||||
|
// The grass thins out past its distance; the simulator's own default keeps a sixth of it for that.
|
||||||
|
c.SetInt("gfx.grass.fadedistance", Math.Min(600, s.GrassDistance + Math.Max(10, s.GrassDistance / 6)));
|
||||||
|
c.SetDouble("gfx.grass.density", s.GrassDensity);
|
||||||
|
c.SetInt("gfx.precipitation.particles", s.PrecipitationParticles);
|
||||||
|
c.SetBool("gfx.postfx.bloom", s.Bloom);
|
||||||
|
c.SetBool("gfx.postfx.autoexposure", s.AutoExposure);
|
||||||
c.SetInt("gfx.reflections.framerate", s.ReflectionsFramerate);
|
c.SetInt("gfx.reflections.framerate", s.ReflectionsFramerate);
|
||||||
c.Set("shadowtune",
|
c.Set("shadowtune",
|
||||||
$"{s.ShadowMapResolution} {s.ShadowProjectionRange} " +
|
$"{s.ShadowMapResolution} {s.ShadowProjectionRange} " +
|
||||||
@@ -235,7 +303,6 @@ public sealed class SettingsSerializer
|
|||||||
if (s.FpsLimitEnabled) c.SetInt("fpslimit", s.FpsLimit); else c.Remove("fpslimit");
|
if (s.FpsLimitEnabled) c.SetInt("fpslimit", s.FpsLimit); else c.Remove("fpslimit");
|
||||||
c.SetDouble("gfx.shadow.angle.min", s.ShadowAngleLimit);
|
c.SetDouble("gfx.shadow.angle.min", s.ShadowAngleLimit);
|
||||||
c.SetBool("fullscreenwindowed", s.FullscreenWindowed);
|
c.SetBool("fullscreenwindowed", s.FullscreenWindowed);
|
||||||
if (s.RenderAngleVulkan) c.Set("gfx.angleplatform", "vulkan"); else c.Remove("gfx.angleplatform");
|
|
||||||
|
|
||||||
c.SetInt("splinefidelity", s.SplineFidelity);
|
c.SetInt("splinefidelity", s.SplineFidelity);
|
||||||
c.SetBool("fullphysics", s.FullPhysics);
|
c.SetBool("fullphysics", s.FullPhysics);
|
||||||
@@ -262,7 +329,6 @@ public sealed class SettingsSerializer
|
|||||||
|
|
||||||
c.SetBool("compresstex", s.CompressTextures);
|
c.SetBool("compresstex", s.CompressTextures);
|
||||||
c.SetBool("scalespeculars", s.ScaleSpeculars);
|
c.SetBool("scalespeculars", s.ScaleSpeculars);
|
||||||
c.SetBool("gfx.usegles", s.UseGLES);
|
|
||||||
c.SetBool("gfx.shadergamma", s.ShaderGamma);
|
c.SetBool("gfx.shadergamma", s.ShaderGamma);
|
||||||
c.SetBool("python.mipmaps", s.ScreenMipmaps);
|
c.SetBool("python.mipmaps", s.ScreenMipmaps);
|
||||||
c.Set("convertmodels", s.ExtendedModelConversion ? "143" : "0");
|
c.Set("convertmodels", s.ExtendedModelConversion ? "143" : "0");
|
||||||
@@ -291,14 +357,134 @@ public sealed class SettingsSerializer
|
|||||||
private static int ParseInt(string s, int fallback) =>
|
private static int ParseInt(string s, int fallback) =>
|
||||||
int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out int n) ? n : fallback;
|
int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out int n) ? n : fallback;
|
||||||
|
|
||||||
private static int IndexOf(string[] values, string token, int fallback)
|
private static string FirstToken(ConfigFile c, string key)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < values.Length; i++)
|
var tokens = c.GetTokens(key);
|
||||||
if (string.Equals(values[i], token, StringComparison.OrdinalIgnoreCase))
|
return tokens.Length > 0 ? tokens[0].ToLowerInvariant() : string.Empty;
|
||||||
return i;
|
|
||||||
return fallback;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The aliases the simulator accepts; the removed renderers ("legacy", "simple", "experimental", ...) run as opengl.
|
||||||
|
private static GraphicsBackend ParseBackend(string value) =>
|
||||||
|
value.Trim().ToLowerInvariant() is "vulkan" or "vulkan14" ? GraphicsBackend.Vulkan : GraphicsBackend.OpenGL;
|
||||||
|
|
||||||
|
private static int ReadBufferScale(ConfigFile c)
|
||||||
|
{
|
||||||
|
if (c.Has("gfx.buffer.percent"))
|
||||||
|
{
|
||||||
|
double value = c.GetDouble("gfx.buffer.percent", 100);
|
||||||
|
// As the simulator reads it: up to 4 a part of the window, over it percents.
|
||||||
|
int percent = (int)Math.Round(value > 4 ? value : value * 100);
|
||||||
|
return Clamp(percent, 25, 200);
|
||||||
|
}
|
||||||
|
return Clamp(c.GetInt("starter.bufferscale", 100), 25, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Whichever of the two keys comes later in the file decides, as each sets the mode when the simulator reads it.
|
||||||
|
private static AntiAliasingMode ReadAntiAliasing(ConfigFile c)
|
||||||
|
{
|
||||||
|
var fromMultisampling = c.GetInt("multisampling", 2) switch
|
||||||
|
{
|
||||||
|
<= 0 => AntiAliasingMode.Off,
|
||||||
|
1 => AntiAliasingMode.Msaa2,
|
||||||
|
2 => AntiAliasingMode.Msaa4,
|
||||||
|
_ => AntiAliasingMode.Msaa8
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!c.Has("gfx.antialiasing") ||
|
||||||
|
(c.Has("multisampling") && c.LineOf("multisampling") > c.LineOf("gfx.antialiasing")))
|
||||||
|
return fromMultisampling;
|
||||||
|
|
||||||
|
return FirstToken(c, "gfx.antialiasing") switch
|
||||||
|
{
|
||||||
|
"off" or "no" or "none" or "0" => AntiAliasingMode.Off,
|
||||||
|
"msaax2" => AntiAliasingMode.Msaa2,
|
||||||
|
"msaax4" => AntiAliasingMode.Msaa4,
|
||||||
|
"msaax8" or "msaax16" => AntiAliasingMode.Msaa8,
|
||||||
|
"taa" => AntiAliasingMode.Taa,
|
||||||
|
"dlss" => AntiAliasingMode.Dlss,
|
||||||
|
"dlaa" => AntiAliasingMode.Dlaa,
|
||||||
|
_ => fromMultisampling
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string AntiAliasingToken(AntiAliasingMode mode) => mode switch
|
||||||
|
{
|
||||||
|
AntiAliasingMode.Msaa2 => "msaax2",
|
||||||
|
AntiAliasingMode.Msaa4 => "msaax4",
|
||||||
|
AntiAliasingMode.Msaa8 => "msaax8",
|
||||||
|
AntiAliasingMode.Taa => "taa",
|
||||||
|
AntiAliasingMode.Dlss => "dlss",
|
||||||
|
AntiAliasingMode.Dlaa => "dlaa",
|
||||||
|
_ => "off"
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int MultisamplingLevel(AntiAliasingMode mode) => mode switch
|
||||||
|
{
|
||||||
|
AntiAliasingMode.Msaa2 => 1,
|
||||||
|
AntiAliasingMode.Msaa4 => 2,
|
||||||
|
AntiAliasingMode.Msaa8 => 3,
|
||||||
|
_ => 0
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int ParseFrameGeneration(string value) => value switch
|
||||||
|
{
|
||||||
|
"x2" or "on" or "yes" or "2" => 2,
|
||||||
|
"x3" or "3" => 3,
|
||||||
|
"x4" or "4" => 4,
|
||||||
|
_ => 1
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int ParseReflex(string value) => value switch
|
||||||
|
{
|
||||||
|
"on" or "yes" or "1" => 1,
|
||||||
|
"boost" or "2" => 2,
|
||||||
|
_ => 0
|
||||||
|
};
|
||||||
|
|
||||||
|
// no/low/medium/high(/ultra) or the number of the level; an absent key keeps the simulator's default.
|
||||||
|
private static int ParseLevel(string value, int fallback, int max)
|
||||||
|
{
|
||||||
|
if (value.Length == 0)
|
||||||
|
return fallback;
|
||||||
|
int level = value switch
|
||||||
|
{
|
||||||
|
"low" or "1" => 1,
|
||||||
|
"medium" or "yes" or "true" or "2" => 2,
|
||||||
|
"high" or "3" => 3,
|
||||||
|
"ultra" or "4" => 4,
|
||||||
|
_ => 0
|
||||||
|
};
|
||||||
|
return Math.Min(level, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string LevelToken(int level) => level switch
|
||||||
|
{
|
||||||
|
1 => "low",
|
||||||
|
2 => "medium",
|
||||||
|
3 => "high",
|
||||||
|
4 => "ultra",
|
||||||
|
_ => "no"
|
||||||
|
};
|
||||||
|
|
||||||
|
private static int ParseAmbientOcclusion(string value) => value switch
|
||||||
|
{
|
||||||
|
"" => 2,
|
||||||
|
"yes" or "true" or "1" or "gtao" => 2,
|
||||||
|
"ssao" => 1,
|
||||||
|
_ => 0
|
||||||
|
};
|
||||||
|
|
||||||
|
private static bool ParseVolumetricFog(string value) =>
|
||||||
|
value is not ("analytic" or "old" or "no" or "false" or "0");
|
||||||
|
|
||||||
|
private static int ParseFogQuality(string value) => value switch
|
||||||
|
{
|
||||||
|
"low" or "1" => 1,
|
||||||
|
"high" or "3" => 3,
|
||||||
|
"ultra" or "4" => 4,
|
||||||
|
_ => 2
|
||||||
|
};
|
||||||
|
|
||||||
private static int MapOldPyScreenPriority(string priority) =>
|
private static int MapOldPyScreenPriority(string priority) =>
|
||||||
priority.ToLowerInvariant() switch
|
priority.ToLowerInvariant() switch
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -140,6 +140,35 @@ public class LocalizationService : INotifyPropertyChanged, ILocalizedStrings
|
|||||||
{
|
{
|
||||||
var dict = new Dictionary<string, string>(StringComparer.Ordinal);
|
var dict = new Dictionary<string, string>(StringComparer.Ordinal);
|
||||||
|
|
||||||
|
// A translation which has not caught up with new settings shows them in English
|
||||||
|
// rather than as their raw keys. Descriptions stay out: a missing one collapses.
|
||||||
|
string english = Path.Combine(Path.GetDirectoryName(path) ?? LangDirectory, "en.xml");
|
||||||
|
if (!string.Equals(code, "en", StringComparison.OrdinalIgnoreCase) && File.Exists(english))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ReadStrings(english, dict);
|
||||||
|
foreach (var key in new List<string>(dict.Keys))
|
||||||
|
if (key.EndsWith(OptionalSuffix, StringComparison.Ordinal))
|
||||||
|
dict.Remove(key);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Log($"lang/{Path.GetFileName(english)}", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadStrings(path, dict);
|
||||||
|
|
||||||
|
_strings = dict;
|
||||||
|
lock (_reportedMisses)
|
||||||
|
_reportedMisses.Clear();
|
||||||
|
CurrentLangCode = code;
|
||||||
|
CurrentLanguage = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ReadStrings(string path, Dictionary<string, string> dict)
|
||||||
|
{
|
||||||
var settings = new XmlReaderSettings { IgnoreComments = true, IgnoreWhitespace = true };
|
var settings = new XmlReaderSettings { IgnoreComments = true, IgnoreWhitespace = true };
|
||||||
using var reader = XmlReader.Create(path, settings);
|
using var reader = XmlReader.Create(path, settings);
|
||||||
|
|
||||||
@@ -157,12 +186,6 @@ public class LocalizationService : INotifyPropertyChanged, ILocalizedStrings
|
|||||||
reader.Read();
|
reader.Read();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_strings = dict;
|
|
||||||
lock (_reportedMisses)
|
|
||||||
_reportedMisses.Clear();
|
|
||||||
CurrentLangCode = code;
|
|
||||||
CurrentLanguage = name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static (string code, string name) ReadHeader(string path)
|
private static (string code, string name) ReadHeader(string path)
|
||||||
|
|||||||
@@ -197,6 +197,21 @@
|
|||||||
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||||
<Setter Property="MaxWidth" Value="360" />
|
<Setter Property="MaxWidth" Value="360" />
|
||||||
</Style>
|
</Style>
|
||||||
|
<!-- The same for a dropdown with a note under it (what the simulator will do instead). -->
|
||||||
|
<Style Selector="ctl|SettingRow:not(.Compact) > StackPanel > ComboBox">
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||||
|
<Setter Property="MaxWidth" Value="360" />
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ctl|SettingRow:not(.Compact) > TextBox">
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||||
|
<Setter Property="MaxWidth" Value="360" />
|
||||||
|
</Style>
|
||||||
|
<!-- Notes under a setting: amber, since green is the interactive accent. -->
|
||||||
|
<Style Selector="TextBlock.SettingNote">
|
||||||
|
<Setter Property="Foreground" Value="#D9A43A" />
|
||||||
|
<Setter Property="FontSize" Value="12" />
|
||||||
|
<Setter Property="TextWrapping" Value="Wrap" />
|
||||||
|
</Style>
|
||||||
<Style Selector="ctl|SettingRow:not(.Compact) > NumericUpDown">
|
<Style Selector="ctl|SettingRow:not(.Compact) > NumericUpDown">
|
||||||
<Setter Property="HorizontalAlignment" Value="Left" />
|
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||||
<Setter Property="Width" Value="140" />
|
<Setter Property="Width" Value="140" />
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ public sealed class AdvancedSettingsWindow : Window
|
|||||||
private readonly CheckBox _mipmaps = new();
|
private readonly CheckBox _mipmaps = new();
|
||||||
private readonly CheckBox _scaleSpeculars = new();
|
private readonly CheckBox _scaleSpeculars = new();
|
||||||
private readonly CheckBox _shaderGamma = new();
|
private readonly CheckBox _shaderGamma = new();
|
||||||
private readonly CheckBox _useGles = new();
|
|
||||||
private readonly CheckBox _convertModels = new();
|
private readonly CheckBox _convertModels = new();
|
||||||
private readonly CheckBox _resourceMove = new();
|
private readonly CheckBox _resourceMove = new();
|
||||||
private readonly CheckBox _resourceSweep = new();
|
private readonly CheckBox _resourceSweep = new();
|
||||||
@@ -46,7 +45,6 @@ public sealed class AdvancedSettingsWindow : Window
|
|||||||
_mipmaps.Content = App.Loc["ScreenMipmaps"];
|
_mipmaps.Content = App.Loc["ScreenMipmaps"];
|
||||||
_scaleSpeculars.Content = App.Loc["ScaleSpeculars"];
|
_scaleSpeculars.Content = App.Loc["ScaleSpeculars"];
|
||||||
_shaderGamma.Content = App.Loc["ShaderGamma"];
|
_shaderGamma.Content = App.Loc["ShaderGamma"];
|
||||||
_useGles.Content = App.Loc["UseGLES"];
|
|
||||||
_convertModels.Content = App.Loc["ExtendedModelConversion"];
|
_convertModels.Content = App.Loc["ExtendedModelConversion"];
|
||||||
_resourceMove.Content = App.Loc["GfxResourceMove"];
|
_resourceMove.Content = App.Loc["GfxResourceMove"];
|
||||||
_resourceSweep.Content = App.Loc["GfxResourceSweep"];
|
_resourceSweep.Content = App.Loc["GfxResourceSweep"];
|
||||||
@@ -111,7 +109,7 @@ public sealed class AdvancedSettingsWindow : Window
|
|||||||
var sp = new StackPanel { Margin = new Avalonia.Thickness(10), Spacing = 8 };
|
var sp = new StackPanel { Margin = new Avalonia.Thickness(10), Spacing = 8 };
|
||||||
foreach (var c in new Control[]
|
foreach (var c in new Control[]
|
||||||
{
|
{
|
||||||
_compressTex, _scaleSpeculars, _useGles, _shaderGamma, _mipmaps,
|
_compressTex, _scaleSpeculars, _shaderGamma, _mipmaps,
|
||||||
_convertModels, _resourceMove, _resourceSweep, _ignoreIrrelevant
|
_convertModels, _resourceMove, _resourceSweep, _ignoreIrrelevant
|
||||||
})
|
})
|
||||||
sp.Children.Add(c);
|
sp.Children.Add(c);
|
||||||
@@ -161,7 +159,6 @@ public sealed class AdvancedSettingsWindow : Window
|
|||||||
_mipmaps.IsChecked = s.ScreenMipmaps;
|
_mipmaps.IsChecked = s.ScreenMipmaps;
|
||||||
_scaleSpeculars.IsChecked = s.ScaleSpeculars;
|
_scaleSpeculars.IsChecked = s.ScaleSpeculars;
|
||||||
_shaderGamma.IsChecked = s.ShaderGamma;
|
_shaderGamma.IsChecked = s.ShaderGamma;
|
||||||
_useGles.IsChecked = s.UseGLES;
|
|
||||||
_convertModels.IsChecked = s.ExtendedModelConversion;
|
_convertModels.IsChecked = s.ExtendedModelConversion;
|
||||||
_resourceMove.IsChecked = s.GfxResourceMove;
|
_resourceMove.IsChecked = s.GfxResourceMove;
|
||||||
_resourceSweep.IsChecked = s.GfxResourceSweep;
|
_resourceSweep.IsChecked = s.GfxResourceSweep;
|
||||||
@@ -177,7 +174,6 @@ public sealed class AdvancedSettingsWindow : Window
|
|||||||
s.ScreenMipmaps = _mipmaps.IsChecked == true;
|
s.ScreenMipmaps = _mipmaps.IsChecked == true;
|
||||||
s.ScaleSpeculars = _scaleSpeculars.IsChecked == true;
|
s.ScaleSpeculars = _scaleSpeculars.IsChecked == true;
|
||||||
s.ShaderGamma = _shaderGamma.IsChecked == true;
|
s.ShaderGamma = _shaderGamma.IsChecked == true;
|
||||||
s.UseGLES = _useGles.IsChecked == true;
|
|
||||||
s.ExtendedModelConversion = _convertModels.IsChecked == true;
|
s.ExtendedModelConversion = _convertModels.IsChecked == true;
|
||||||
s.GfxResourceMove = _resourceMove.IsChecked == true;
|
s.GfxResourceMove = _resourceMove.IsChecked == true;
|
||||||
s.GfxResourceSweep = _resourceSweep.IsChecked == true;
|
s.GfxResourceSweep = _resourceSweep.IsChecked == true;
|
||||||
|
|||||||
468
StarterNG/Views/Settings.Graphics.cs
Normal file
468
StarterNG/Views/Settings.Graphics.cs
Normal file
@@ -0,0 +1,468 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.Platform.Storage;
|
||||||
|
using StarterNG.Application;
|
||||||
|
using StarterNG.Domain.Settings;
|
||||||
|
|
||||||
|
namespace StarterNG.Views;
|
||||||
|
|
||||||
|
// The graphics and effects categories: their controls, the dependencies between
|
||||||
|
// them (what the simulator only does on Vulkan, with DLSS, ...), the quality presets
|
||||||
|
// and the import and export of eu07.ini.
|
||||||
|
public partial class Settings
|
||||||
|
{
|
||||||
|
private static readonly CultureInfo Invariant = CultureInfo.InvariantCulture;
|
||||||
|
|
||||||
|
private static readonly FilePickerFileType[] IniTypes =
|
||||||
|
{
|
||||||
|
new("eu07.ini") { Patterns = new[] { "*.ini" } },
|
||||||
|
new("*") { Patterns = new[] { "*" } }
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>Set while the dependencies are brought in line, so the changes they make do not recurse.</summary>
|
||||||
|
private bool _updatingGraphics;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// What only Vulkan has, as it was when OpenGL got chosen, so that going back to
|
||||||
|
/// Vulkan brings it back instead of leaving it switched off.
|
||||||
|
/// </summary>
|
||||||
|
private (AntiAliasingMode AntiAliasing, int FrameGeneration, int Reflex, bool RayTracing)? _vulkanChoices;
|
||||||
|
|
||||||
|
private string? _dlssProbedFor;
|
||||||
|
private (bool Dlss, bool FrameGeneration) _dlssProbe;
|
||||||
|
|
||||||
|
private static bool DlssPlatform => AppServices.Current.SettingsStore.DlssPlatform;
|
||||||
|
|
||||||
|
private void InitGraphics()
|
||||||
|
{
|
||||||
|
RenderEngineCb.SelectionChanged += (_, _) => OnBackendChanged();
|
||||||
|
// The notes are worked out here, not bound, so they follow a change of language by hand.
|
||||||
|
App.Loc.LanguageChanged += UpdateGraphicsState;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyGraphicsToUi(SimulatorSettings s)
|
||||||
|
{
|
||||||
|
RenderEngineCb.SelectedIndex = (int)s.Backend;
|
||||||
|
VulkanDeviceTb.Text = s.VulkanDevice;
|
||||||
|
SelectResolution(s.Width, s.Height);
|
||||||
|
FullscreenWindowedCb.IsChecked = s.FullscreenWindowed;
|
||||||
|
bufferScale.Value = s.BufferScalePercent;
|
||||||
|
SelectTag(AntiAliasingCb, AntiAliasingTag(s.AntiAliasing));
|
||||||
|
SelectTag(DlssPresetCb, s.DlssPreset);
|
||||||
|
SelectTag(FrameGenerationCb, s.FrameGeneration.ToString(Invariant));
|
||||||
|
SelectTag(ReflexCb, s.Reflex.ToString(Invariant));
|
||||||
|
|
||||||
|
textureResolutionSlider.Value = Log2(s.MaxTextureSize, 12);
|
||||||
|
cabTextureResolutionSlider.Value = Log2(s.MaxCabTextureSize, 12);
|
||||||
|
TexFilteringSlider.Value = AnisotropyToSlider(s.TextureFiltering);
|
||||||
|
TrackCurvesSlider.Value = s.SplineFidelity;
|
||||||
|
RenderRangeSlider.Value = (int)Math.Round(s.DrawRangeFactor);
|
||||||
|
|
||||||
|
VSyncCb.IsChecked = s.VSync;
|
||||||
|
FpsLimitEnableCb.IsChecked = s.FpsLimitEnabled;
|
||||||
|
FpsLimitSlider.Value = s.FpsLimit;
|
||||||
|
FpsLimitSlider.IsEnabled = s.FpsLimitEnabled;
|
||||||
|
fovSlider.Value = s.FieldOfView;
|
||||||
|
AdditionalShadersCb.IsChecked = s.ExtraEffects;
|
||||||
|
SkipPipelineCb.IsChecked = s.SkipPipeline;
|
||||||
|
|
||||||
|
RenderShadowsCb.IsChecked = s.RenderShadows;
|
||||||
|
ShadowDisplayCb.SelectedIndex = Clamp(s.ShadowRankCutoff - 1, 0, 2);
|
||||||
|
shaderResolutionSlider.Value = Log2(s.ShadowMapResolution, 11);
|
||||||
|
shaderRange.Value = s.ShadowProjectionRange;
|
||||||
|
ShadowSdsmCb.IsChecked = s.ShadowSdsm;
|
||||||
|
ShadowAngleLimitSlider.Value = s.ShadowAngleLimit;
|
||||||
|
|
||||||
|
LightsClusteredCb.IsChecked = s.LightsClustered;
|
||||||
|
DynamicLightsSlider.Value = s.DynamicLights;
|
||||||
|
SelectTag(LightShadowsCb, s.LightShadows.ToString(Invariant));
|
||||||
|
SelectTag(ContactShadowsCb, s.ContactShadows.ToString(Invariant));
|
||||||
|
SelectTag(AmbientOcclusionCb, s.AmbientOcclusion.ToString(Invariant));
|
||||||
|
SelectOrAddTag(AoQualityCb, $"{s.AoSlices} {s.AoSteps}", $"{s.AoSlices} / {s.AoSteps}");
|
||||||
|
|
||||||
|
ReflectionsCubeMapCb.IsChecked = s.EnvMap;
|
||||||
|
SelectTag(SsrCb, s.Ssr.ToString(Invariant));
|
||||||
|
RayTracingCb.IsChecked = s.RayTracing;
|
||||||
|
RayTracingRangeSlider.Value = s.RayTracingRange;
|
||||||
|
ReflectionsDetailsCb.SelectedIndex = s.ReflectionsFidelity;
|
||||||
|
reflectionsFramerate.Value = s.ReflectionsFramerate;
|
||||||
|
|
||||||
|
VolumetricFogCb.IsChecked = s.VolumetricFog;
|
||||||
|
SelectTag(FogQualityCb, s.FogQuality.ToString(Invariant));
|
||||||
|
SelectTag(CloudsCb, s.Clouds.ToString(Invariant));
|
||||||
|
CloudShadowsCb.IsChecked = s.CloudShadows;
|
||||||
|
|
||||||
|
BloomCb.IsChecked = s.Bloom;
|
||||||
|
AutoExposureCb.IsChecked = s.AutoExposure;
|
||||||
|
MotionBlurCb.IsChecked = s.MotionBlur;
|
||||||
|
ChromaticAberrationCb.IsChecked = s.ChromaticAberration;
|
||||||
|
|
||||||
|
GrassCb.IsChecked = s.Grass;
|
||||||
|
GrassDistanceSlider.Value = s.GrassDistance;
|
||||||
|
GrassDensitySlider.Value = s.GrassDensity;
|
||||||
|
SmokeDisplayCb.IsChecked = s.Smoke;
|
||||||
|
SmokeParticlesSlider.Value = s.SmokeFidelity;
|
||||||
|
string particles = s.PrecipitationParticles.ToString(Invariant);
|
||||||
|
SelectOrAddTag(PrecipitationCb, particles, particles);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CaptureGraphicsInto(SimulatorSettings s)
|
||||||
|
{
|
||||||
|
s.Backend = RenderEngineCb.SelectedIndex == 1 ? GraphicsBackend.Vulkan : GraphicsBackend.OpenGL;
|
||||||
|
s.VulkanDevice = VulkanDeviceTb.Text?.Trim() ?? "";
|
||||||
|
ReadResolution(s);
|
||||||
|
s.FullscreenWindowed = IsChecked(FullscreenWindowedCb);
|
||||||
|
s.BufferScalePercent = (int)bufferScale.Value;
|
||||||
|
s.AntiAliasing = AntiAliasingFromTag(SelectedTag(AntiAliasingCb));
|
||||||
|
s.DlssPreset = SelectedTag(DlssPresetCb) ?? "default";
|
||||||
|
s.FrameGeneration = TagInt(FrameGenerationCb, 1);
|
||||||
|
s.Reflex = TagInt(ReflexCb, 0);
|
||||||
|
|
||||||
|
s.MaxTextureSize = 1 << (int)textureResolutionSlider.Value;
|
||||||
|
s.MaxCabTextureSize = 1 << (int)cabTextureResolutionSlider.Value;
|
||||||
|
s.TextureFiltering = SimulatorSettings.AnisotropySteps[
|
||||||
|
Clamp((int)TexFilteringSlider.Value - 1, 0, SimulatorSettings.AnisotropySteps.Length - 1)];
|
||||||
|
s.SplineFidelity = (int)TrackCurvesSlider.Value;
|
||||||
|
s.DrawRangeFactor = RenderRangeSlider.Value;
|
||||||
|
|
||||||
|
s.VSync = IsChecked(VSyncCb);
|
||||||
|
s.FpsLimitEnabled = IsChecked(FpsLimitEnableCb);
|
||||||
|
s.FpsLimit = (int)FpsLimitSlider.Value;
|
||||||
|
s.FieldOfView = Clamp((int)fovSlider.Value, 15, 75);
|
||||||
|
s.ExtraEffects = IsChecked(AdditionalShadersCb);
|
||||||
|
s.SkipPipeline = IsChecked(SkipPipelineCb);
|
||||||
|
|
||||||
|
s.RenderShadows = IsChecked(RenderShadowsCb);
|
||||||
|
s.ShadowRankCutoff = Math.Max(0, ShadowDisplayCb.SelectedIndex) + 1;
|
||||||
|
s.ShadowMapResolution = 1 << (int)shaderResolutionSlider.Value;
|
||||||
|
s.ShadowProjectionRange = (int)shaderRange.Value;
|
||||||
|
s.ShadowSdsm = IsChecked(ShadowSdsmCb);
|
||||||
|
s.ShadowAngleLimit = ShadowAngleLimitSlider.Value;
|
||||||
|
|
||||||
|
s.LightsClustered = IsChecked(LightsClusteredCb);
|
||||||
|
s.DynamicLights = (int)DynamicLightsSlider.Value;
|
||||||
|
s.LightShadows = TagInt(LightShadowsCb, 2);
|
||||||
|
s.ContactShadows = TagInt(ContactShadowsCb, 0);
|
||||||
|
s.AmbientOcclusion = TagInt(AmbientOcclusionCb, 2);
|
||||||
|
var ao = (SelectedTag(AoQualityCb) ?? "3 4").Split(' ');
|
||||||
|
s.AoSlices = ao.Length > 0 && int.TryParse(ao[0], NumberStyles.Integer, Invariant, out int slices) ? slices : 3;
|
||||||
|
s.AoSteps = ao.Length > 1 && int.TryParse(ao[1], NumberStyles.Integer, Invariant, out int steps) ? steps : 4;
|
||||||
|
|
||||||
|
s.EnvMap = IsChecked(ReflectionsCubeMapCb);
|
||||||
|
s.Ssr = TagInt(SsrCb, 2);
|
||||||
|
s.RayTracing = IsChecked(RayTracingCb);
|
||||||
|
s.RayTracingRange = (int)RayTracingRangeSlider.Value;
|
||||||
|
s.ReflectionsFidelity = Math.Max(0, ReflectionsDetailsCb.SelectedIndex);
|
||||||
|
s.ReflectionsFramerate = (int)reflectionsFramerate.Value;
|
||||||
|
|
||||||
|
s.VolumetricFog = IsChecked(VolumetricFogCb);
|
||||||
|
s.FogQuality = TagInt(FogQualityCb, 2);
|
||||||
|
s.Clouds = TagInt(CloudsCb, 2);
|
||||||
|
s.CloudShadows = IsChecked(CloudShadowsCb);
|
||||||
|
|
||||||
|
s.Bloom = IsChecked(BloomCb);
|
||||||
|
s.AutoExposure = IsChecked(AutoExposureCb);
|
||||||
|
s.MotionBlur = IsChecked(MotionBlurCb);
|
||||||
|
s.ChromaticAberration = IsChecked(ChromaticAberrationCb);
|
||||||
|
|
||||||
|
s.Grass = IsChecked(GrassCb);
|
||||||
|
s.GrassDistance = (int)GrassDistanceSlider.Value;
|
||||||
|
s.GrassDensity = GrassDensitySlider.Value;
|
||||||
|
s.Smoke = IsChecked(SmokeDisplayCb);
|
||||||
|
s.SmokeFidelity = (int)SmokeParticlesSlider.Value;
|
||||||
|
s.PrecipitationParticles = TagInt(PrecipitationCb, 65536);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>The settings as this screen shows them, edits included, without touching the real ones.</summary>
|
||||||
|
private SimulatorSettings SnapshotFromUi()
|
||||||
|
{
|
||||||
|
var s = new SimulatorSettings();
|
||||||
|
CaptureInto(s);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnBackendChanged()
|
||||||
|
{
|
||||||
|
if (_loading || _updatingGraphics)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_updatingGraphics = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (RenderEngineCb.SelectedIndex != 1)
|
||||||
|
{
|
||||||
|
var s = SnapshotFromUi();
|
||||||
|
_vulkanChoices ??= (s.AntiAliasing, s.FrameGeneration, s.Reflex, s.RayTracing);
|
||||||
|
if (GraphicsRules.IsDlss(s.AntiAliasing))
|
||||||
|
SelectTag(AntiAliasingCb, "taa");
|
||||||
|
FrameGenerationCb.SelectedIndex = 0;
|
||||||
|
ReflexCb.SelectedIndex = 0;
|
||||||
|
RayTracingCb.IsChecked = false;
|
||||||
|
}
|
||||||
|
else if (_vulkanChoices is { } kept)
|
||||||
|
{
|
||||||
|
if (GraphicsRules.IsDlss(kept.AntiAliasing) && DlssPlatform && SelectedTag(AntiAliasingCb) == "taa")
|
||||||
|
SelectTag(AntiAliasingCb, AntiAliasingTag(kept.AntiAliasing));
|
||||||
|
SelectTag(FrameGenerationCb, kept.FrameGeneration.ToString(Invariant));
|
||||||
|
SelectTag(ReflexCb, kept.Reflex.ToString(Invariant));
|
||||||
|
RayTracingCb.IsChecked = kept.RayTracing;
|
||||||
|
_vulkanChoices = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_updatingGraphics = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateGraphicsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Brings the graphics controls in line with one another the way the simulator
|
||||||
|
/// treats them, says why something is off, and shows which preset the settings are.
|
||||||
|
/// </summary>
|
||||||
|
private void UpdateGraphicsState()
|
||||||
|
{
|
||||||
|
if (_loading || _updatingGraphics || AntiAliasingCb is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_updatingGraphics = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var s = SnapshotFromUi();
|
||||||
|
bool vulkan = GraphicsRules.IsVulkan(s);
|
||||||
|
bool dlssAllowed = GraphicsRules.DlssAllowed(s, DlssPlatform);
|
||||||
|
|
||||||
|
foreach (var item in AntiAliasingCb.Items.OfType<ComboBoxItem>())
|
||||||
|
if (item.Tag is "dlss" or "dlaa")
|
||||||
|
item.IsEnabled = dlssAllowed;
|
||||||
|
if (GraphicsRules.IsDlss(s.AntiAliasing) && !dlssAllowed)
|
||||||
|
SelectTag(AntiAliasingCb, "taa");
|
||||||
|
|
||||||
|
s = SnapshotFromUi();
|
||||||
|
bool dlss = GraphicsRules.DlssActive(s, DlssPlatform);
|
||||||
|
DlssPresetRow.IsEnabled = dlss;
|
||||||
|
FrameGenerationRow.IsEnabled = dlss;
|
||||||
|
if (!dlss && FrameGenerationCb.SelectedIndex > 0)
|
||||||
|
FrameGenerationCb.SelectedIndex = 0;
|
||||||
|
ReflexRow.IsEnabled = vulkan;
|
||||||
|
if (!vulkan && ReflexCb.SelectedIndex > 0)
|
||||||
|
ReflexCb.SelectedIndex = 0;
|
||||||
|
VulkanDeviceRow.IsEnabled = vulkan;
|
||||||
|
RayTracingRow.IsEnabled = vulkan;
|
||||||
|
if (!vulkan)
|
||||||
|
RayTracingCb.IsChecked = false;
|
||||||
|
|
||||||
|
s = SnapshotFromUi();
|
||||||
|
BufferScaleRow.IsEnabled = GraphicsRules.BufferScaleUsed(s, DlssPlatform);
|
||||||
|
RayTracingRangeRow.IsEnabled = vulkan && s.RayTracing;
|
||||||
|
DynamicLightsRow.IsEnabled = GraphicsRules.DynamicLightsUsed(s);
|
||||||
|
AoQualityRow.IsEnabled = s.AmbientOcclusion > 0;
|
||||||
|
FogQualityRow.IsEnabled = s.VolumetricFog;
|
||||||
|
CloudShadowsRow.IsEnabled = s.Clouds > 0;
|
||||||
|
GrassDistanceRow.IsEnabled = s.Grass;
|
||||||
|
GrassDensityRow.IsEnabled = s.Grass;
|
||||||
|
|
||||||
|
DlssPresetInfo.Text = App.Loc[(SelectedTag(DlssPresetCb) ?? "default") switch
|
||||||
|
{
|
||||||
|
"k" => "DlssPresetInfoK",
|
||||||
|
"j" => "DlssPresetInfoJ",
|
||||||
|
"m" => "DlssPresetInfoM",
|
||||||
|
"l" => "DlssPresetInfoL",
|
||||||
|
_ => "DlssPresetInfoDefault"
|
||||||
|
}];
|
||||||
|
SetNote(RenderEngineNote, vulkan ? App.Loc["REVulkanNote"] : App.Loc["REOpenGLNote"]);
|
||||||
|
SetNote(AntiAliasingNote, AntiAliasingRemark(s, dlss));
|
||||||
|
SetNote(FrameGenerationNote, FrameGenerationRemark(s, dlss));
|
||||||
|
SetNote(ReflexNote, GraphicsRules.ReflexForced(s, DlssPlatform) ? App.Loc["ReflexForcedNote"] : "");
|
||||||
|
SetNote(RayTracingNote, vulkan ? "" : App.Loc["VulkanOnlyNote"]);
|
||||||
|
SetNote(SkipPipelineNote, GraphicsRules.TemporalWithoutPipeline(s) ? App.Loc["TemporalNeedsPipelineNote"] : "");
|
||||||
|
|
||||||
|
QualityPresetCb.SelectedIndex = (int)GraphicsPresets.Detect(s, DlssPlatform);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_updatingGraphics = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string AntiAliasingRemark(SimulatorSettings s, bool dlss)
|
||||||
|
{
|
||||||
|
if (!DlssPlatform && GraphicsRules.IsVulkan(s))
|
||||||
|
return App.Loc["DlssNoPlatformNote"];
|
||||||
|
if (GraphicsRules.TemporalWithoutPipeline(s))
|
||||||
|
return App.Loc["TemporalNeedsPipelineNote"];
|
||||||
|
if (dlss && !DlssLibraries(s).Dlss)
|
||||||
|
return string.Format(App.Loc["DlssMissingLibraryNote"], DlssLibraryName(frameGeneration: false));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string FrameGenerationRemark(SimulatorSettings s, bool dlss)
|
||||||
|
{
|
||||||
|
if (!dlss)
|
||||||
|
return GraphicsRules.IsVulkan(s) ? App.Loc["FrameGenerationNeedsDlssNote"] : "";
|
||||||
|
if (s.FrameGeneration > 1 && !DlssLibraries(s).FrameGeneration)
|
||||||
|
return string.Format(App.Loc["DlssMissingLibraryNote"], DlssLibraryName(frameGeneration: true));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Looked up once per simulator picked: the search for it reads the installation's directory.</summary>
|
||||||
|
private (bool Dlss, bool FrameGeneration) DlssLibraries(SimulatorSettings s)
|
||||||
|
{
|
||||||
|
string key = s.SelectExeAutomatically ? "\u0001auto" : s.ExecutablePath;
|
||||||
|
if (_dlssProbedFor != key)
|
||||||
|
{
|
||||||
|
var executables = AppServices.Current.Executables;
|
||||||
|
_dlssProbe = executables.DlssLibraries(executables.Resolve(s, out _));
|
||||||
|
_dlssProbedFor = key;
|
||||||
|
}
|
||||||
|
return _dlssProbe;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string DlssLibraryName(bool frameGeneration) =>
|
||||||
|
AppServices.Current.Environment.IsWindows
|
||||||
|
? (frameGeneration ? "nvngx_dlssg.dll" : "nvngx_dlss.dll")
|
||||||
|
: (frameGeneration ? "libnvidia-ngx-dlssg.so" : "libnvidia-ngx-dlss.so");
|
||||||
|
|
||||||
|
private void QualityPresetCb_OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (_loading || _updatingGraphics || QualityPresetCb is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int index = QualityPresetCb.SelectedIndex;
|
||||||
|
if (index < 0 || index >= GraphicsPresets.All.Length)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var s = SnapshotFromUi();
|
||||||
|
GraphicsPresets.Apply(s, GraphicsPresets.All[index], DlssPlatform);
|
||||||
|
|
||||||
|
_loading = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ApplyGraphicsToUi(s);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateQualityCaptions();
|
||||||
|
MarkDirty();
|
||||||
|
UpdateGraphicsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void ImportIniButton_OnClick(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (TopLevel.GetTopLevel(this) is not Window owner)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var picked = await owner.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
||||||
|
{
|
||||||
|
Title = App.Loc["ImportIniTitle"],
|
||||||
|
AllowMultiple = false,
|
||||||
|
FileTypeFilter = IniTypes
|
||||||
|
});
|
||||||
|
if (picked.Count == 0 || picked[0].TryGetLocalPath() is not { } path)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!AppServices.Current.SettingsStore.ImportFrom(path))
|
||||||
|
{
|
||||||
|
await MessageBox.Show(owner, string.Format(App.Loc["ImportIniFailed"], path), App.Loc["ImportIni"],
|
||||||
|
MessageBoxButtons.Ok);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_vulkanChoices = null;
|
||||||
|
ApplyToUi();
|
||||||
|
MarkDirty();
|
||||||
|
SaveStatus.Text = string.Format(App.Loc["ImportIniDone"], Path.GetFileName(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void ExportIniButton_OnClick(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (TopLevel.GetTopLevel(this) is not Window owner)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var file = await owner.StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions
|
||||||
|
{
|
||||||
|
Title = App.Loc["ExportIniTitle"],
|
||||||
|
SuggestedFileName = "eu07.ini",
|
||||||
|
DefaultExtension = "ini",
|
||||||
|
FileTypeChoices = IniTypes,
|
||||||
|
ShowOverwritePrompt = true
|
||||||
|
});
|
||||||
|
if (file?.TryGetLocalPath() is not { } path)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// The edits on screen go into the export as they would into a save, but the
|
||||||
|
// user's own eu07.ini is not written.
|
||||||
|
CaptureInto(AppServices.Current.Settings);
|
||||||
|
bool ok = AppServices.Current.SettingsStore.ExportTo(path);
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
await MessageBox.Show(owner, string.Format(App.Loc["ExportIniFailed"], path), App.Loc["ExportIni"],
|
||||||
|
MessageBoxButtons.Ok);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SaveStatus.Text = string.Format(App.Loc["ExportIniDone"], Path.GetFileName(path));
|
||||||
|
ToolTip.SetTip(SaveStatus, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetNote(TextBlock note, string text)
|
||||||
|
{
|
||||||
|
note.Text = text;
|
||||||
|
note.IsVisible = text.Length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? SelectedTag(ComboBox cb) => (cb.SelectedItem as ComboBoxItem)?.Tag as string;
|
||||||
|
|
||||||
|
private static int TagInt(ComboBox cb, int fallback) =>
|
||||||
|
int.TryParse(SelectedTag(cb), NumberStyles.Integer, Invariant, out int n) ? n : fallback;
|
||||||
|
|
||||||
|
private static void SelectTag(ComboBox cb, string? tag)
|
||||||
|
{
|
||||||
|
int index = IndexOfTag(cb, tag);
|
||||||
|
if (index >= 0)
|
||||||
|
cb.SelectedIndex = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Selects the item of the tag, adding one for a value from the file the list does not offer.</summary>
|
||||||
|
private static void SelectOrAddTag(ComboBox cb, string tag, string label)
|
||||||
|
{
|
||||||
|
int index = IndexOfTag(cb, tag);
|
||||||
|
if (index < 0)
|
||||||
|
{
|
||||||
|
cb.Items.Add(new ComboBoxItem { Tag = tag, Content = label });
|
||||||
|
index = cb.Items.Count - 1;
|
||||||
|
}
|
||||||
|
cb.SelectedIndex = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string AntiAliasingTag(AntiAliasingMode mode) => mode switch
|
||||||
|
{
|
||||||
|
AntiAliasingMode.Msaa2 => "msaax2",
|
||||||
|
AntiAliasingMode.Msaa4 => "msaax4",
|
||||||
|
AntiAliasingMode.Msaa8 => "msaax8",
|
||||||
|
AntiAliasingMode.Taa => "taa",
|
||||||
|
AntiAliasingMode.Dlss => "dlss",
|
||||||
|
AntiAliasingMode.Dlaa => "dlaa",
|
||||||
|
_ => "off"
|
||||||
|
};
|
||||||
|
|
||||||
|
private static AntiAliasingMode AntiAliasingFromTag(string? tag) => tag switch
|
||||||
|
{
|
||||||
|
"msaax2" => AntiAliasingMode.Msaa2,
|
||||||
|
"msaax4" => AntiAliasingMode.Msaa4,
|
||||||
|
"msaax8" => AntiAliasingMode.Msaa8,
|
||||||
|
"taa" => AntiAliasingMode.Taa,
|
||||||
|
"dlss" => AntiAliasingMode.Dlss,
|
||||||
|
"dlaa" => AntiAliasingMode.Dlaa,
|
||||||
|
_ => AntiAliasingMode.Off
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -53,6 +53,16 @@
|
|||||||
HorizontalContentAlignment="Center"
|
HorizontalContentAlignment="Center"
|
||||||
Content="{Binding [ProfileSaveAs], Source={x:Static starterNg:App.Loc}}"
|
Content="{Binding [ProfileSaveAs], Source={x:Static starterNg:App.Loc}}"
|
||||||
Click="ProfileSaveAsButton_OnClick" />
|
Click="ProfileSaveAsButton_OnClick" />
|
||||||
|
<TextBlock Classes="FieldLabel" Margin="0,8,0,0"
|
||||||
|
Text="{Binding [SettingsFile], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<Button x:Name="ImportIniBtn" Classes="Flat" HorizontalAlignment="Stretch"
|
||||||
|
HorizontalContentAlignment="Center"
|
||||||
|
Content="{Binding [ImportIni], Source={x:Static starterNg:App.Loc}}"
|
||||||
|
Click="ImportIniButton_OnClick" />
|
||||||
|
<Button x:Name="ExportIniBtn" Classes="Flat" HorizontalAlignment="Stretch"
|
||||||
|
HorizontalContentAlignment="Center"
|
||||||
|
Content="{Binding [ExportIni], Source={x:Static starterNg:App.Loc}}"
|
||||||
|
Click="ExportIniButton_OnClick" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<ListBox x:Name="CategoryList" Classes="SettingsNav" SelectedIndex="0"
|
<ListBox x:Name="CategoryList" Classes="SettingsNav" SelectedIndex="0"
|
||||||
@@ -60,6 +70,7 @@
|
|||||||
SelectionChanged="CategoryList_OnSelectionChanged">
|
SelectionChanged="CategoryList_OnSelectionChanged">
|
||||||
<ListBoxItem Tag="general" Content="{Binding [General], Source={x:Static starterNg:App.Loc}}" />
|
<ListBoxItem Tag="general" Content="{Binding [General], Source={x:Static starterNg:App.Loc}}" />
|
||||||
<ListBoxItem Tag="graphics" Content="{Binding [Graphic], Source={x:Static starterNg:App.Loc}}" />
|
<ListBoxItem Tag="graphics" Content="{Binding [Graphic], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ListBoxItem Tag="effects" Content="{Binding [Effects], Source={x:Static starterNg:App.Loc}}" />
|
||||||
<ListBoxItem Tag="sound" Content="{Binding [Sounds], Source={x:Static starterNg:App.Loc}}" />
|
<ListBoxItem Tag="sound" Content="{Binding [Sounds], Source={x:Static starterNg:App.Loc}}" />
|
||||||
<ListBoxItem Tag="physics" Content="{Binding [Physics], Source={x:Static starterNg:App.Loc}}" />
|
<ListBoxItem Tag="physics" Content="{Binding [Physics], Source={x:Static starterNg:App.Loc}}" />
|
||||||
<ListBoxItem Tag="devices" Content="{Binding [Communication], Source={x:Static starterNg:App.Loc}}" />
|
<ListBoxItem Tag="devices" Content="{Binding [Communication], Source={x:Static starterNg:App.Loc}}" />
|
||||||
@@ -158,9 +169,34 @@
|
|||||||
|
|
||||||
<!-- ============================ GRAPHICS =========================== -->
|
<!-- ============================ GRAPHICS =========================== -->
|
||||||
<StackPanel Tag="graphics" IsVisible="False">
|
<StackPanel Tag="graphics" IsVisible="False">
|
||||||
<TextBlock Classes="CategoryCaption" IsVisible="False"
|
<TextBlock Classes="CategoryCaption" IsVisible="False" Text="{Binding [Graphic], Source={x:Static starterNg:App.Loc}}" />
|
||||||
Text="{Binding [Graphic], Source={x:Static starterNg:App.Loc}}" />
|
<ctl:SettingsSection Header="{Binding [GfxColQuality], Source={x:Static starterNg:App.Loc}}">
|
||||||
<ctl:SettingsSection Header="{Binding [GfxColResolution], Source={x:Static starterNg:App.Loc}}">
|
<StackPanel>
|
||||||
|
<ctl:SettingRow Label="{Binding [QualityPreset], Source={x:Static starterNg:App.Loc}}" Description="{Binding [QualityPresetDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<ComboBox x:Name="QualityPresetCb" SelectedIndex="0" SelectionChanged="QualityPresetCb_OnSelectionChanged">
|
||||||
|
<ComboBoxItem Content="{Binding [PresetLowest], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Content="{Binding [PresetLow], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Content="{Binding [PresetMedium], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Content="{Binding [PresetHigh], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Content="{Binding [PresetUltra], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Content="{Binding [PresetCustom], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ComboBox>
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow ConfigKey="gfxrenderer" Label="{Binding [RenderEngine], Source={x:Static starterNg:App.Loc}}" Description="{Binding [RenderEngineDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<StackPanel Spacing="6">
|
||||||
|
<ComboBox x:Name="RenderEngineCb" SelectedIndex="0">
|
||||||
|
<ComboBoxItem Tag="full" Content="{Binding [REOpenGL], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="vulkan" Content="{Binding [REVulkan], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ComboBox>
|
||||||
|
<TextBlock x:Name="RenderEngineNote" Classes="SettingNote" IsVisible="False" />
|
||||||
|
</StackPanel>
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow x:Name="VulkanDeviceRow" ConfigKey="gfx.vulkan.device" Label="{Binding [VulkanDevice], Source={x:Static starterNg:App.Loc}}" Description="{Binding [VulkanDeviceDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<TextBox x:Name="VulkanDeviceTb" PlaceholderText="{Binding [VulkanDeviceAuto], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
</StackPanel>
|
||||||
|
</ctl:SettingsSection>
|
||||||
|
<ctl:SettingsSection Header="{Binding [GfxColImage], Source={x:Static starterNg:App.Loc}}">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<ctl:SettingRow ConfigKey="width, height" Label="{Binding [Resolution], Source={x:Static starterNg:App.Loc}}">
|
<ctl:SettingRow ConfigKey="width, height" Label="{Binding [Resolution], Source={x:Static starterNg:App.Loc}}">
|
||||||
<ComboBox x:Name="ResolutionCb" SelectedIndex="0">
|
<ComboBox x:Name="ResolutionCb" SelectedIndex="0">
|
||||||
@@ -175,202 +211,102 @@
|
|||||||
<ctl:SettingRow ConfigKey="fullscreenwindowed">
|
<ctl:SettingRow ConfigKey="fullscreenwindowed">
|
||||||
<CheckBox x:Name="FullscreenWindowedCb" Content="{Binding [FullscreenWindowed], Source={x:Static starterNg:App.Loc}}" />
|
<CheckBox x:Name="FullscreenWindowedCb" Content="{Binding [FullscreenWindowed], Source={x:Static starterNg:App.Loc}}" />
|
||||||
</ctl:SettingRow>
|
</ctl:SettingRow>
|
||||||
<ctl:SettingRow ConfigKey="starter.bufferscale" Label="{Binding [BufforResolution], Source={x:Static starterNg:App.Loc}}"
|
<ctl:SettingRow x:Name="BufferScaleRow" ConfigKey="gfx.buffer.percent" Label="{Binding [BufforResolution], Source={x:Static starterNg:App.Loc}}" Description="{Binding [BufforResolutionDesc], Source={x:Static starterNg:App.Loc}}" ValueText="{Binding #bufferScale.Value, StringFormat='{}{0:0}%'}">
|
||||||
Description="{Binding [BufforResolutionDesc], Source={x:Static starterNg:App.Loc}}"
|
<Slider Name="bufferScale" Minimum="25" Maximum="200" TickFrequency="1" IsSnapToTickEnabled="True" Value="100" />
|
||||||
ValueText="{Binding #bufferScale.Value, StringFormat='{}{0:0}%'}">
|
|
||||||
<Slider Name="bufferScale" Minimum="50" Maximum="200" TickFrequency="1"
|
|
||||||
IsSnapToTickEnabled="True" Value="100" />
|
|
||||||
</ctl:SettingRow>
|
</ctl:SettingRow>
|
||||||
<ctl:SettingRow ConfigKey="maxtexturesize" x:Name="TexResolutionRow"
|
<ctl:SettingRow ConfigKey="gfx.antialiasing" Label="{Binding [AntiAliasing], Source={x:Static starterNg:App.Loc}}" Description="{Binding [AntiAliasingDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
Label="{Binding [MaxTexResolution], Source={x:Static starterNg:App.Loc}}">
|
<StackPanel Spacing="6">
|
||||||
<Slider Name="textureResolutionSlider" Minimum="9" Maximum="14" TickFrequency="1"
|
<ComboBox x:Name="AntiAliasingCb" SelectedIndex="0">
|
||||||
IsSnapToTickEnabled="True" Value="12"
|
<ComboBoxItem Tag="off" Content="{Binding [MsaaNone], Source={x:Static starterNg:App.Loc}}" />
|
||||||
ValueChanged="TextureResolutionSlider_OnValueChanged" />
|
<ComboBoxItem Tag="msaax2" Content="MSAA x2" />
|
||||||
|
<ComboBoxItem Tag="msaax4" Content="MSAA x4" />
|
||||||
|
<ComboBoxItem Tag="msaax8" Content="MSAA x8" />
|
||||||
|
<ComboBoxItem Tag="taa" Content="{Binding [AaTaa], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="dlss" Content="{Binding [AaDlss], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="dlaa" Content="{Binding [AaDlaa], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ComboBox>
|
||||||
|
<TextBlock x:Name="AntiAliasingNote" Classes="SettingNote" IsVisible="False" />
|
||||||
|
</StackPanel>
|
||||||
</ctl:SettingRow>
|
</ctl:SettingRow>
|
||||||
<ctl:SettingRow ConfigKey="maxcabtexturesize" x:Name="CabTexResolutionRow"
|
<ctl:SettingRow x:Name="DlssPresetRow" ConfigKey="gfx.dlss.preset" Label="{Binding [DlssPreset], Source={x:Static starterNg:App.Loc}}" Description="{Binding [DlssPresetDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
Label="{Binding [MaxTexCabResolution], Source={x:Static starterNg:App.Loc}}">
|
<StackPanel Spacing="6">
|
||||||
<Slider Name="cabTextureResolutionSlider" Minimum="9" Maximum="14" TickFrequency="1"
|
<ComboBox x:Name="DlssPresetCb" SelectedIndex="0">
|
||||||
IsSnapToTickEnabled="True" Value="12"
|
<ComboBoxItem Tag="default" Content="{Binding [DlssPresetDefault], Source={x:Static starterNg:App.Loc}}" />
|
||||||
ValueChanged="CabTextureResolutionSlider_OnValueChanged" />
|
<ComboBoxItem Tag="k" Content="{Binding [DlssPresetK], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="j" Content="{Binding [DlssPresetJ], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="m" Content="{Binding [DlssPresetM], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="l" Content="{Binding [DlssPresetL], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ComboBox>
|
||||||
|
<TextBlock x:Name="DlssPresetInfo" Classes="FieldHint" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
</ctl:SettingRow>
|
</ctl:SettingRow>
|
||||||
<ctl:SettingRow ConfigKey="anisotropicfiltering" x:Name="TexFilteringRow"
|
<ctl:SettingRow x:Name="FrameGenerationRow" ConfigKey="gfx.framegeneration" Label="{Binding [FrameGeneration], Source={x:Static starterNg:App.Loc}}" Description="{Binding [FrameGenerationDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
Label="{Binding [TexFilteringQuality], Source={x:Static starterNg:App.Loc}}"
|
<StackPanel Spacing="6">
|
||||||
Description="{Binding [TexFilteringQualityDesc], Source={x:Static starterNg:App.Loc}}">
|
<ComboBox x:Name="FrameGenerationCb" SelectedIndex="0">
|
||||||
<Slider x:Name="TexFilteringSlider" Minimum="1" Maximum="5" TickFrequency="1"
|
<ComboBoxItem Tag="1" Content="{Binding [LevelOff], Source={x:Static starterNg:App.Loc}}" />
|
||||||
IsSnapToTickEnabled="True" Value="4"
|
<ComboBoxItem Tag="2" Content="x2" />
|
||||||
ValueChanged="QualitySlider_OnValueChanged" />
|
<ComboBoxItem Tag="3" Content="x3" />
|
||||||
|
<ComboBoxItem Tag="4" Content="x4" />
|
||||||
|
</ComboBox>
|
||||||
|
<TextBlock x:Name="FrameGenerationNote" Classes="SettingNote" IsVisible="False" />
|
||||||
|
</StackPanel>
|
||||||
</ctl:SettingRow>
|
</ctl:SettingRow>
|
||||||
<ctl:SettingRow ConfigKey="multisampling" x:Name="MultisamplingRow"
|
<ctl:SettingRow x:Name="ReflexRow" ConfigKey="gfx.reflex" Label="{Binding [Reflex], Source={x:Static starterNg:App.Loc}}" Description="{Binding [ReflexDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
Label="{Binding [Multisampling], Source={x:Static starterNg:App.Loc}}"
|
<StackPanel Spacing="6">
|
||||||
Description="{Binding [MultisamplingDesc], Source={x:Static starterNg:App.Loc}}">
|
<ComboBox x:Name="ReflexCb" SelectedIndex="0">
|
||||||
<Slider x:Name="MultisamplingSlider" Minimum="1" Maximum="4" TickFrequency="1"
|
<ComboBoxItem Tag="0" Content="{Binding [LevelOff], Source={x:Static starterNg:App.Loc}}" />
|
||||||
IsSnapToTickEnabled="True" Value="3"
|
<ComboBoxItem Tag="1" Content="{Binding [ReflexOn], Source={x:Static starterNg:App.Loc}}" />
|
||||||
ValueChanged="QualitySlider_OnValueChanged" />
|
<ComboBoxItem Tag="2" Content="{Binding [ReflexBoost], Source={x:Static starterNg:App.Loc}}" />
|
||||||
</ctl:SettingRow>
|
</ComboBox>
|
||||||
<ctl:SettingRow ConfigKey="splinefidelity" x:Name="TrackCurvesRow"
|
<TextBlock x:Name="ReflexNote" Classes="SettingNote" IsVisible="False" />
|
||||||
Label="{Binding [TrackCurvesQuality], Source={x:Static starterNg:App.Loc}}"
|
</StackPanel>
|
||||||
Description="{Binding [TrackCurvesQualityDesc], Source={x:Static starterNg:App.Loc}}">
|
</ctl:SettingRow>
|
||||||
<Slider x:Name="TrackCurvesSlider" Minimum="1" Maximum="4" TickFrequency="1"
|
</StackPanel>
|
||||||
IsSnapToTickEnabled="True" Value="4"
|
</ctl:SettingsSection>
|
||||||
ValueChanged="QualitySlider_OnValueChanged" />
|
<ctl:SettingsSection Header="{Binding [GfxColTextures], Source={x:Static starterNg:App.Loc}}">
|
||||||
</ctl:SettingRow>
|
<StackPanel>
|
||||||
<ctl:SettingRow ConfigKey="gfx.drawrange.factor.max" x:Name="RenderRangeRow"
|
<ctl:SettingRow x:Name="TexResolutionRow" ConfigKey="maxtexturesize" Label="{Binding [MaxTexResolution], Source={x:Static starterNg:App.Loc}}">
|
||||||
Label="{Binding [RenderRange], Source={x:Static starterNg:App.Loc}}"
|
<Slider Name="textureResolutionSlider" Minimum="9" Maximum="13" TickFrequency="1" IsSnapToTickEnabled="True" Value="12" ValueChanged="TextureResolutionSlider_OnValueChanged" />
|
||||||
Description="{Binding [RenderRangeDesc], Source={x:Static starterNg:App.Loc}}">
|
</ctl:SettingRow>
|
||||||
<Slider x:Name="RenderRangeSlider" Minimum="1" Maximum="3" TickFrequency="1"
|
<ctl:SettingRow x:Name="CabTexResolutionRow" ConfigKey="maxcabtexturesize" Label="{Binding [MaxTexCabResolution], Source={x:Static starterNg:App.Loc}}">
|
||||||
IsSnapToTickEnabled="True" Value="1"
|
<Slider Name="cabTextureResolutionSlider" Minimum="9" Maximum="13" TickFrequency="1" IsSnapToTickEnabled="True" Value="12" ValueChanged="CabTextureResolutionSlider_OnValueChanged" />
|
||||||
ValueChanged="QualitySlider_OnValueChanged" />
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow x:Name="TexFilteringRow" ConfigKey="anisotropicfiltering" Label="{Binding [TexFilteringQuality], Source={x:Static starterNg:App.Loc}}" Description="{Binding [TexFilteringQualityDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<Slider x:Name="TexFilteringSlider" Minimum="1" Maximum="5" TickFrequency="1" IsSnapToTickEnabled="True" Value="4" ValueChanged="QualitySlider_OnValueChanged" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow x:Name="TrackCurvesRow" ConfigKey="splinefidelity" Label="{Binding [TrackCurvesQuality], Source={x:Static starterNg:App.Loc}}" Description="{Binding [TrackCurvesQualityDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<Slider x:Name="TrackCurvesSlider" Minimum="1" Maximum="4" TickFrequency="1" IsSnapToTickEnabled="True" Value="4" ValueChanged="QualitySlider_OnValueChanged" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow x:Name="RenderRangeRow" ConfigKey="gfx.drawrange.factor.max" Label="{Binding [RenderRange], Source={x:Static starterNg:App.Loc}}" Description="{Binding [RenderRangeDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<Slider x:Name="RenderRangeSlider" Minimum="1" Maximum="3" TickFrequency="1" IsSnapToTickEnabled="True" Value="1" ValueChanged="QualitySlider_OnValueChanged" />
|
||||||
</ctl:SettingRow>
|
</ctl:SettingRow>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ctl:SettingsSection>
|
</ctl:SettingsSection>
|
||||||
|
|
||||||
<ctl:SettingsSection Header="{Binding [GfxColRendering], Source={x:Static starterNg:App.Loc}}">
|
<ctl:SettingsSection Header="{Binding [GfxColRendering], Source={x:Static starterNg:App.Loc}}">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<ctl:SettingRow ConfigKey="gfxrenderer" Label="{Binding [RenderEngine], Source={x:Static starterNg:App.Loc}}"
|
<ctl:SettingRow ConfigKey="vsync" Description="{Binding [VSyncDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
Description="{Binding [RenderEngineDesc], Source={x:Static starterNg:App.Loc}}">
|
<CheckBox x:Name="VSyncCb" Content="{Binding [VSync], Source={x:Static starterNg:App.Loc}}" />
|
||||||
<StackPanel Spacing="6">
|
|
||||||
<ComboBox x:Name="RenderEngineCb" SelectedIndex="0"
|
|
||||||
SelectionChanged="RenderEngineCb_OnSelectionChanged">
|
|
||||||
<ComboBoxItem Content="{Binding [REFull], Source={x:Static starterNg:App.Loc}}" />
|
|
||||||
<ComboBoxItem Content="{Binding [REOld], Source={x:Static starterNg:App.Loc}}" />
|
|
||||||
<ComboBoxItem Content="{Binding [RESimpShader], Source={x:Static starterNg:App.Loc}}" />
|
|
||||||
<ComboBoxItem Content="{Binding [RESimp], Source={x:Static starterNg:App.Loc}}" />
|
|
||||||
<ComboBoxItem Content="{Binding [REOff], Source={x:Static starterNg:App.Loc}}" />
|
|
||||||
<ComboBoxItem Content="{Binding [REExperimental], Source={x:Static starterNg:App.Loc}}" />
|
|
||||||
</ComboBox>
|
|
||||||
<TextBlock x:Name="RenderEngineWarning" IsVisible="False" TextWrapping="Wrap"
|
|
||||||
Foreground="{StaticResource CarbonAccentBright}"
|
|
||||||
Text="{Binding [REExperimentalWarning], Source={x:Static starterNg:App.Loc}}" />
|
|
||||||
</StackPanel>
|
|
||||||
</ctl:SettingRow>
|
</ctl:SettingRow>
|
||||||
<ctl:SettingRow ConfigKey="gfx.angleplatform" Description="{Binding [RenderAngleVulkanDesc], Source={x:Static starterNg:App.Loc}}">
|
<ctl:SettingRow ConfigKey="fpslimit" ValueText="{Binding #FpsLimitSlider.Value, StringFormat='{}{0:0} FPS'}" Margin="0,0,0,4">
|
||||||
<CheckBox x:Name="RenderAngleVulkanCb" Content="{Binding [RenderAngleVulkan], Source={x:Static starterNg:App.Loc}}" />
|
<CheckBox x:Name="FpsLimitEnableCb" Content="{Binding [FpsLimitEnable], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow ConfigKey="fpslimit">
|
||||||
|
<Slider x:Name="FpsLimitSlider" Minimum="1" Maximum="100" TickFrequency="1" IsSnapToTickEnabled="True" Value="30" IsEnabled="{Binding #FpsLimitEnableCb.IsChecked}" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow ConfigKey="fieldofview" Label="{Binding [FieldOfView], Source={x:Static starterNg:App.Loc}}" Description="{Binding [FieldOfViewDesc], Source={x:Static starterNg:App.Loc}}" ValueText="{Binding #fovSlider.Value, StringFormat='{}{0:0}°'}">
|
||||||
|
<Slider Name="fovSlider" Minimum="15" Maximum="75" TickFrequency="5" IsSnapToTickEnabled="True" Value="45" />
|
||||||
</ctl:SettingRow>
|
</ctl:SettingRow>
|
||||||
<ctl:SettingRow ConfigKey="gfx.extraeffects">
|
<ctl:SettingRow ConfigKey="gfx.extraeffects">
|
||||||
<CheckBox x:Name="AdditionalShadersCb" Content="{Binding [AdditionalShadersEffects], Source={x:Static starterNg:App.Loc}}" />
|
<CheckBox x:Name="AdditionalShadersCb" Content="{Binding [AdditionalShadersEffects], Source={x:Static starterNg:App.Loc}}" />
|
||||||
</ctl:SettingRow>
|
</ctl:SettingRow>
|
||||||
<ctl:SettingRow ConfigKey="gfx.postfx.chromaticaberration.enabled">
|
|
||||||
<CheckBox x:Name="ChromaticAberrationCb" Content="{Binding [ChromaticAberration], Source={x:Static starterNg:App.Loc}}" />
|
|
||||||
</ctl:SettingRow>
|
|
||||||
<ctl:SettingRow ConfigKey="gfx.postfx.motionblur.enabled">
|
|
||||||
<CheckBox x:Name="MotionBlurCb" Content="{Binding [MotionBlur], Source={x:Static starterNg:App.Loc}}" />
|
|
||||||
</ctl:SettingRow>
|
|
||||||
<ctl:SettingRow ConfigKey="gfx.skippipeline" Description="{Binding [SkipPipelineDesc], Source={x:Static starterNg:App.Loc}}">
|
<ctl:SettingRow ConfigKey="gfx.skippipeline" Description="{Binding [SkipPipelineDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
<CheckBox x:Name="SkipPipelineCb" Content="{Binding [SkipPipeline], Source={x:Static starterNg:App.Loc}}" />
|
<StackPanel Spacing="6">
|
||||||
</ctl:SettingRow>
|
<CheckBox x:Name="SkipPipelineCb" Content="{Binding [SkipPipeline], Source={x:Static starterNg:App.Loc}}" />
|
||||||
<ctl:SettingRow ConfigKey="usevbo" Description="{Binding [RenderVBODesc], Source={x:Static starterNg:App.Loc}}">
|
<TextBlock x:Name="SkipPipelineNote" Classes="SettingNote" IsVisible="False" />
|
||||||
<CheckBox x:Name="RenderVBOCb" Content="{Binding [RenderVBO], Source={x:Static starterNg:App.Loc}}" />
|
|
||||||
</ctl:SettingRow>
|
|
||||||
<ctl:SettingRow ConfigKey="vsync" Description="{Binding [VSyncDesc], Source={x:Static starterNg:App.Loc}}">
|
|
||||||
<CheckBox x:Name="VSyncCb" Content="{Binding [VSync], Source={x:Static starterNg:App.Loc}}" />
|
|
||||||
</ctl:SettingRow>
|
|
||||||
|
|
||||||
<ctl:SettingRow ConfigKey="fpslimit" Margin="0,0,0,4"
|
|
||||||
ValueText="{Binding #FpsLimitSlider.Value, StringFormat='{}{0:0} FPS'}">
|
|
||||||
<CheckBox x:Name="FpsLimitEnableCb" Content="{Binding [FpsLimitEnable], Source={x:Static starterNg:App.Loc}}" />
|
|
||||||
</ctl:SettingRow>
|
|
||||||
<ctl:SettingRow ConfigKey="fpslimit">
|
|
||||||
<Slider x:Name="FpsLimitSlider" Minimum="1" Maximum="100" TickFrequency="1"
|
|
||||||
IsSnapToTickEnabled="True" Value="30"
|
|
||||||
IsEnabled="{Binding #FpsLimitEnableCb.IsChecked}" />
|
|
||||||
</ctl:SettingRow>
|
|
||||||
|
|
||||||
<ctl:SettingRow ConfigKey="gfx.smoke" Margin="0,0,0,4">
|
|
||||||
<CheckBox x:Name="SmokeDisplayCb" Content="{Binding [SmokeDisplay], Source={x:Static starterNg:App.Loc}}" />
|
|
||||||
</ctl:SettingRow>
|
|
||||||
<ctl:SettingRow ConfigKey="gfx.smoke.fidelity" x:Name="SmokeParticlesRow"
|
|
||||||
Label="{Binding [SmokeParticlesMultiplier], Source={x:Static starterNg:App.Loc}}"
|
|
||||||
IsEnabled="{Binding #SmokeDisplayCb.IsChecked}">
|
|
||||||
<Slider x:Name="SmokeParticlesSlider" Minimum="1" Maximum="4" TickFrequency="1"
|
|
||||||
IsSnapToTickEnabled="True" Value="2"
|
|
||||||
ValueChanged="QualitySlider_OnValueChanged" />
|
|
||||||
</ctl:SettingRow>
|
|
||||||
|
|
||||||
<ctl:SettingRow Description="{Binding [DynamicLightsDesc], Source={x:Static starterNg:App.Loc}}" ConfigKey="dynamiclights" Label="{Binding [DynamicLights], Source={x:Static starterNg:App.Loc}}"
|
|
||||||
ValueText="{Binding #DynamicLightsSlider.Value, StringFormat='{}{0:0}'}">
|
|
||||||
<Slider x:Name="DynamicLightsSlider" Minimum="0" Maximum="7" TickFrequency="1"
|
|
||||||
IsSnapToTickEnabled="True" Value="7" />
|
|
||||||
</ctl:SettingRow>
|
|
||||||
<ctl:SettingRow ConfigKey="fieldofview" Label="{Binding [FieldOfView], Source={x:Static starterNg:App.Loc}}"
|
|
||||||
Description="{Binding [FieldOfViewDesc], Source={x:Static starterNg:App.Loc}}"
|
|
||||||
ValueText="{Binding #fovSlider.Value, StringFormat='{}{0:0}°'}">
|
|
||||||
<Slider Name="fovSlider" Minimum="15" Maximum="75" TickFrequency="5"
|
|
||||||
IsSnapToTickEnabled="True" Value="45" />
|
|
||||||
</ctl:SettingRow>
|
|
||||||
</StackPanel>
|
|
||||||
</ctl:SettingsSection>
|
|
||||||
|
|
||||||
<ctl:SettingsSection Header="{Binding [GfxColShadows], Source={x:Static starterNg:App.Loc}}">
|
|
||||||
<ctl:SettingsSection.Toggle>
|
|
||||||
<CheckBox x:Name="RenderShadowsCb" FontSize="12" MinHeight="0"
|
|
||||||
Content="{Binding [RenderShadows], Source={x:Static starterNg:App.Loc}}" />
|
|
||||||
</ctl:SettingsSection.Toggle>
|
|
||||||
<StackPanel IsEnabled="{Binding #RenderShadowsCb.IsChecked}">
|
|
||||||
<ctl:SettingRow Description="{Binding [ShadowDisplayDesc], Source={x:Static starterNg:App.Loc}}" ConfigKey="gfx.shadow.rank.cutoff" Label="{Binding [ShadowDisplay], Source={x:Static starterNg:App.Loc}}">
|
|
||||||
<ComboBox x:Name="ShadowDisplayCb" SelectedIndex="0">
|
|
||||||
<ComboBoxItem Content="{Binding [CSROnlyImportant], Source={x:Static starterNg:App.Loc}}" />
|
|
||||||
<ComboBoxItem Content="{Binding [CSRLimited], Source={x:Static starterNg:App.Loc}}" />
|
|
||||||
<ComboBoxItem Content="{Binding [CSRAll], Source={x:Static starterNg:App.Loc}}" />
|
|
||||||
</ComboBox>
|
|
||||||
</ctl:SettingRow>
|
|
||||||
<ctl:SettingRow ConfigKey="shadowtune" x:Name="ShadowResolutionRow"
|
|
||||||
Label="{Binding [ShadowsResolution], Source={x:Static starterNg:App.Loc}}">
|
|
||||||
<Slider Name="shaderResolutionSlider" Minimum="9" Maximum="14" TickFrequency="1"
|
|
||||||
IsSnapToTickEnabled="True" Value="12"
|
|
||||||
ValueChanged="shaderResolutionSlider_OnValueChanged" />
|
|
||||||
</ctl:SettingRow>
|
|
||||||
<ctl:SettingRow ConfigKey="shadowtune" x:Name="ShadowRangeRow"
|
|
||||||
Label="{Binding [ShaderRange], Source={x:Static starterNg:App.Loc}}">
|
|
||||||
<Slider Name="shaderRange" Minimum="25" Maximum="400" TickFrequency="5"
|
|
||||||
IsSnapToTickEnabled="True" Value="150"
|
|
||||||
ValueChanged="QualitySlider_OnValueChanged" />
|
|
||||||
</ctl:SettingRow>
|
|
||||||
<ctl:SettingRow ConfigKey="gfx.shadows.cab.range" x:Name="CabShadowRangeRow"
|
|
||||||
Label="{Binding [CabShadowsRange], Source={x:Static starterNg:App.Loc}}"
|
|
||||||
Description="{Binding [CabShadowsRangeDesc], Source={x:Static starterNg:App.Loc}}">
|
|
||||||
<Slider Name="cabShaderSourceRange" Minimum="0" Maximum="100" TickFrequency="10"
|
|
||||||
IsSnapToTickEnabled="True" Value="30"
|
|
||||||
ValueChanged="QualitySlider_OnValueChanged" />
|
|
||||||
</ctl:SettingRow>
|
|
||||||
<ctl:SettingRow ConfigKey="gfx.shadow.angle.min" Label="{Binding [ShadowAngleLimit], Source={x:Static starterNg:App.Loc}}"
|
|
||||||
Description="{Binding [ShadowAngleLimitDesc], Source={x:Static starterNg:App.Loc}}"
|
|
||||||
ValueText="{Binding #ShadowAngleLimitSlider.Value, StringFormat='{}{0:0.0}'}">
|
|
||||||
<StackPanel>
|
|
||||||
<Slider x:Name="ShadowAngleLimitSlider" Minimum="0.2" Maximum="1.0"
|
|
||||||
TickFrequency="0.1" Value="0.2" HorizontalAlignment="Stretch" />
|
|
||||||
<DockPanel>
|
|
||||||
<TextBlock DockPanel.Dock="Right" Classes="FieldHint"
|
|
||||||
Text="{Binding [ShadowLimitShort], Source={x:Static starterNg:App.Loc}}" />
|
|
||||||
<TextBlock Classes="FieldHint"
|
|
||||||
Text="{Binding [ShadowLimitNone], Source={x:Static starterNg:App.Loc}}" />
|
|
||||||
</DockPanel>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ctl:SettingRow>
|
</ctl:SettingRow>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ctl:SettingsSection>
|
</ctl:SettingsSection>
|
||||||
|
|
||||||
<ctl:SettingsSection Header="{Binding [GfxColReflections], Source={x:Static starterNg:App.Loc}}">
|
|
||||||
<StackPanel>
|
|
||||||
<ctl:SettingRow ConfigKey="gfx.envmap.enabled" Description="{Binding [ReflectionsCubeMapDesc], Source={x:Static starterNg:App.Loc}}">
|
|
||||||
<CheckBox x:Name="ReflectionsCubeMapCb" Content="{Binding [ReflectionsCubeMap], Source={x:Static starterNg:App.Loc}}" />
|
|
||||||
</ctl:SettingRow>
|
|
||||||
<ctl:SettingRow ConfigKey="gfx.reflections.fidelity" Label="{Binding [ReflectionsDetails], Source={x:Static starterNg:App.Loc}}"
|
|
||||||
Description="{Binding [ReflectionsDetailsDesc], Source={x:Static starterNg:App.Loc}}">
|
|
||||||
<ComboBox x:Name="ReflectionsDetailsCb" SelectedIndex="0">
|
|
||||||
<ComboBoxItem Content="{Binding [RDTerrain], Source={x:Static starterNg:App.Loc}}" />
|
|
||||||
<ComboBoxItem Content="{Binding [RDTerrainModels], Source={x:Static starterNg:App.Loc}}" />
|
|
||||||
<ComboBoxItem Content="{Binding [RDTerrainModelsVehicles], Source={x:Static starterNg:App.Loc}}" />
|
|
||||||
</ComboBox>
|
|
||||||
</ctl:SettingRow>
|
|
||||||
<ctl:SettingRow ConfigKey="gfx.reflections.framerate" x:Name="ReflectionsFramerateRow"
|
|
||||||
Label="{Binding [ReflectionsFramerate], Source={x:Static starterNg:App.Loc}}">
|
|
||||||
<Slider Name="reflectionsFramerate" Minimum="5" Maximum="120" TickFrequency="5"
|
|
||||||
IsSnapToTickEnabled="True" Value="30"
|
|
||||||
ValueChanged="QualitySlider_OnValueChanged" />
|
|
||||||
</ctl:SettingRow>
|
|
||||||
</StackPanel>
|
|
||||||
</ctl:SettingsSection>
|
|
||||||
|
|
||||||
<ctl:SettingsSection Header="{Binding [GfxColScripts], Source={x:Static starterNg:App.Loc}}">
|
<ctl:SettingsSection Header="{Binding [GfxColScripts], Source={x:Static starterNg:App.Loc}}">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<ctl:SettingRow ConfigKey="python.enabled" Description="{Binding [RenderScreensDesc], Source={x:Static starterNg:App.Loc}}">
|
<ctl:SettingRow ConfigKey="python.enabled" Description="{Binding [RenderScreensDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
@@ -379,8 +315,7 @@
|
|||||||
<ctl:SettingRow ConfigKey="python.threadedupload">
|
<ctl:SettingRow ConfigKey="python.threadedupload">
|
||||||
<CheckBox x:Name="RenderScreensThreadCb" Content="{Binding [RenderScreensThread], Source={x:Static starterNg:App.Loc}}" />
|
<CheckBox x:Name="RenderScreensThreadCb" Content="{Binding [RenderScreensThread], Source={x:Static starterNg:App.Loc}}" />
|
||||||
</ctl:SettingRow>
|
</ctl:SettingRow>
|
||||||
<ctl:SettingRow ConfigKey="python.updatetime" Label="{Binding [PyScreenPriority], Source={x:Static starterNg:App.Loc}}"
|
<ctl:SettingRow ConfigKey="python.updatetime" Label="{Binding [PyScreenPriority], Source={x:Static starterNg:App.Loc}}" Description="{Binding [PyScreenPriorityDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
Description="{Binding [PyScreenPriorityDesc], Source={x:Static starterNg:App.Loc}}">
|
|
||||||
<ComboBox x:Name="PyScreenPriorityCb">
|
<ComboBox x:Name="PyScreenPriorityCb">
|
||||||
<ComboBoxItem Tag="200" Content="{Binding [PyPriorityNormal], Source={x:Static starterNg:App.Loc}}" />
|
<ComboBoxItem Tag="200" Content="{Binding [PyPriorityNormal], Source={x:Static starterNg:App.Loc}}" />
|
||||||
<ComboBoxItem Tag="400" Content="{Binding [PyPriorityLower], Source={x:Static starterNg:App.Loc}}" />
|
<ComboBoxItem Tag="400" Content="{Binding [PyPriorityLower], Source={x:Static starterNg:App.Loc}}" />
|
||||||
@@ -392,6 +327,189 @@
|
|||||||
</ctl:SettingsSection>
|
</ctl:SettingsSection>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- ============================ EFFECTS ============================ -->
|
||||||
|
<StackPanel Tag="effects" IsVisible="False">
|
||||||
|
<TextBlock Classes="CategoryCaption" IsVisible="False" Text="{Binding [Effects], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ctl:SettingsSection Header="{Binding [GfxColShadows], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<ctl:SettingsSection.Toggle>
|
||||||
|
<CheckBox x:Name="RenderShadowsCb" FontSize="12" MinHeight="0" Content="{Binding [RenderShadows], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ctl:SettingsSection.Toggle>
|
||||||
|
<StackPanel IsEnabled="{Binding #RenderShadowsCb.IsChecked}">
|
||||||
|
<ctl:SettingRow ConfigKey="gfx.shadow.rank.cutoff" Label="{Binding [ShadowDisplay], Source={x:Static starterNg:App.Loc}}" Description="{Binding [ShadowDisplayDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<ComboBox x:Name="ShadowDisplayCb" SelectedIndex="0">
|
||||||
|
<ComboBoxItem Content="{Binding [CSROnlyImportant], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Content="{Binding [CSRLimited], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Content="{Binding [CSRAll], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ComboBox>
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow x:Name="ShadowResolutionRow" ConfigKey="shadowtune" Label="{Binding [ShadowsResolution], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<Slider Name="shaderResolutionSlider" Minimum="9" Maximum="13" TickFrequency="1" IsSnapToTickEnabled="True" Value="11" ValueChanged="shaderResolutionSlider_OnValueChanged" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow x:Name="ShadowRangeRow" ConfigKey="shadowtune" Label="{Binding [ShaderRange], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<Slider Name="shaderRange" Minimum="75" Maximum="400" TickFrequency="5" IsSnapToTickEnabled="True" Value="250" ValueChanged="QualitySlider_OnValueChanged" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow ConfigKey="gfx.shadow.sdsm" Description="{Binding [ShadowSdsmDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<CheckBox x:Name="ShadowSdsmCb" Content="{Binding [ShadowSdsm], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow ConfigKey="gfx.shadow.angle.min" Label="{Binding [ShadowAngleLimit], Source={x:Static starterNg:App.Loc}}" Description="{Binding [ShadowAngleLimitDesc], Source={x:Static starterNg:App.Loc}}" ValueText="{Binding #ShadowAngleLimitSlider.Value, StringFormat='{}{0:0.0}'}">
|
||||||
|
<StackPanel>
|
||||||
|
<Slider x:Name="ShadowAngleLimitSlider" Minimum="0.2" Maximum="1.0" TickFrequency="0.1" Value="0.2" HorizontalAlignment="Stretch" />
|
||||||
|
<DockPanel>
|
||||||
|
<TextBlock DockPanel.Dock="Right" Classes="FieldHint" Text="{Binding [ShadowLimitShort], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<TextBlock Classes="FieldHint" Text="{Binding [ShadowLimitNone], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</DockPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</ctl:SettingRow>
|
||||||
|
</StackPanel>
|
||||||
|
</ctl:SettingsSection>
|
||||||
|
<ctl:SettingsSection Header="{Binding [GfxColLights], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<StackPanel>
|
||||||
|
<ctl:SettingRow ConfigKey="gfx.lights.clustered" Description="{Binding [LightsClusteredDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<CheckBox x:Name="LightsClusteredCb" Content="{Binding [LightsClustered], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow x:Name="DynamicLightsRow" ConfigKey="dynamiclights" Label="{Binding [DynamicLights], Source={x:Static starterNg:App.Loc}}" Description="{Binding [DynamicLightsDesc], Source={x:Static starterNg:App.Loc}}" ValueText="{Binding #DynamicLightsSlider.Value, StringFormat='{}{0:0}'}">
|
||||||
|
<Slider x:Name="DynamicLightsSlider" Minimum="0" Maximum="7" TickFrequency="1" IsSnapToTickEnabled="True" Value="7" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow ConfigKey="gfx.lights.shadows" Label="{Binding [LightShadows], Source={x:Static starterNg:App.Loc}}" Description="{Binding [LightShadowsDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<ComboBox x:Name="LightShadowsCb" SelectedIndex="0">
|
||||||
|
<ComboBoxItem Tag="0" Content="{Binding [LevelOff], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="1" Content="{Binding [LevelLow], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="2" Content="{Binding [LevelMedium], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="3" Content="{Binding [LevelHigh], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ComboBox>
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow ConfigKey="gfx.contactshadows" Label="{Binding [ContactShadows], Source={x:Static starterNg:App.Loc}}" Description="{Binding [ContactShadowsDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<ComboBox x:Name="ContactShadowsCb" SelectedIndex="0">
|
||||||
|
<ComboBoxItem Tag="0" Content="{Binding [LevelOff], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="1" Content="{Binding [LevelLow], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="2" Content="{Binding [LevelMedium], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="3" Content="{Binding [LevelHigh], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ComboBox>
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow ConfigKey="gfx.postfx.ao" Label="{Binding [AmbientOcclusion], Source={x:Static starterNg:App.Loc}}" Description="{Binding [AmbientOcclusionDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<ComboBox x:Name="AmbientOcclusionCb" SelectedIndex="0">
|
||||||
|
<ComboBoxItem Tag="0" Content="{Binding [LevelOff], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="1" Content="SSAO" />
|
||||||
|
<ComboBoxItem Tag="2" Content="GTAO" />
|
||||||
|
</ComboBox>
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow x:Name="AoQualityRow" ConfigKey="gfx.postfx.ao.quality" Label="{Binding [AmbientOcclusionQuality], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<ComboBox x:Name="AoQualityCb" SelectedIndex="0">
|
||||||
|
<ComboBoxItem Tag="2 3" Content="{Binding [QualityLow], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="3 4" Content="{Binding [QualityNormal], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="4 6" Content="{Binding [QualityHigh], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="6 8" Content="{Binding [QualityVeryHigh], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ComboBox>
|
||||||
|
</ctl:SettingRow>
|
||||||
|
</StackPanel>
|
||||||
|
</ctl:SettingsSection>
|
||||||
|
<ctl:SettingsSection Header="{Binding [GfxColReflections], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<StackPanel>
|
||||||
|
<ctl:SettingRow ConfigKey="gfx.envmap.enabled" Description="{Binding [ReflectionsCubeMapDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<CheckBox x:Name="ReflectionsCubeMapCb" Content="{Binding [ReflectionsCubeMap], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow ConfigKey="gfx.ssr" Label="{Binding [Ssr], Source={x:Static starterNg:App.Loc}}" Description="{Binding [SsrDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<ComboBox x:Name="SsrCb" SelectedIndex="0">
|
||||||
|
<ComboBoxItem Tag="0" Content="{Binding [LevelOff], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="1" Content="{Binding [LevelLow], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="2" Content="{Binding [LevelMedium], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="3" Content="{Binding [LevelHigh], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ComboBox>
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow x:Name="RayTracingRow" ConfigKey="gfx.raytracing" Description="{Binding [RayTracingDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<StackPanel Spacing="6">
|
||||||
|
<CheckBox x:Name="RayTracingCb" Content="{Binding [RayTracing], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<TextBlock x:Name="RayTracingNote" Classes="SettingNote" IsVisible="False" />
|
||||||
|
</StackPanel>
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow x:Name="RayTracingRangeRow" ConfigKey="gfx.raytracing.range" Label="{Binding [RayTracingRange], Source={x:Static starterNg:App.Loc}}" ValueText="{Binding #RayTracingRangeSlider.Value, StringFormat='{}{0:0} m'}">
|
||||||
|
<Slider x:Name="RayTracingRangeSlider" Minimum="50" Maximum="2000" TickFrequency="50" IsSnapToTickEnabled="True" Value="500" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow ConfigKey="gfx.reflections.fidelity" Label="{Binding [ReflectionsDetails], Source={x:Static starterNg:App.Loc}}" Description="{Binding [ReflectionsDetailsDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<ComboBox x:Name="ReflectionsDetailsCb" SelectedIndex="0">
|
||||||
|
<ComboBoxItem Content="{Binding [RDTerrain], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Content="{Binding [RDTerrainModels], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Content="{Binding [RDTerrainModelsVehicles], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ComboBox>
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow x:Name="ReflectionsFramerateRow" ConfigKey="gfx.reflections.framerate" Label="{Binding [ReflectionsFramerate], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<Slider Name="reflectionsFramerate" Minimum="5" Maximum="120" TickFrequency="5" IsSnapToTickEnabled="True" Value="30" ValueChanged="QualitySlider_OnValueChanged" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
</StackPanel>
|
||||||
|
</ctl:SettingsSection>
|
||||||
|
<ctl:SettingsSection Header="{Binding [GfxColAtmosphere], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<StackPanel>
|
||||||
|
<ctl:SettingRow ConfigKey="gfx.fog" Description="{Binding [VolumetricFogDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<CheckBox x:Name="VolumetricFogCb" Content="{Binding [VolumetricFog], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow x:Name="FogQualityRow" ConfigKey="gfx.fog.quality" Label="{Binding [FogQuality], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<ComboBox x:Name="FogQualityCb" SelectedIndex="0">
|
||||||
|
<ComboBoxItem Tag="1" Content="{Binding [LevelLow], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="2" Content="{Binding [LevelMedium], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="3" Content="{Binding [LevelHigh], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="4" Content="{Binding [LevelUltra], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ComboBox>
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow ConfigKey="gfx.clouds" Label="{Binding [Clouds], Source={x:Static starterNg:App.Loc}}" Description="{Binding [CloudsDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<ComboBox x:Name="CloudsCb" SelectedIndex="0">
|
||||||
|
<ComboBoxItem Tag="0" Content="{Binding [LevelOff], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="1" Content="{Binding [LevelLow], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="2" Content="{Binding [LevelMedium], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="3" Content="{Binding [LevelHigh], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="4" Content="{Binding [LevelUltra], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ComboBox>
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow x:Name="CloudShadowsRow" ConfigKey="gfx.clouds.shadows">
|
||||||
|
<CheckBox x:Name="CloudShadowsCb" Content="{Binding [CloudShadows], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
</StackPanel>
|
||||||
|
</ctl:SettingsSection>
|
||||||
|
<ctl:SettingsSection Header="{Binding [GfxColPostFx], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<StackPanel>
|
||||||
|
<ctl:SettingRow ConfigKey="gfx.postfx.bloom">
|
||||||
|
<CheckBox x:Name="BloomCb" Content="{Binding [Bloom], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow ConfigKey="gfx.postfx.autoexposure" Description="{Binding [AutoExposureDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<CheckBox x:Name="AutoExposureCb" Content="{Binding [AutoExposure], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow ConfigKey="gfx.postfx.motionblur.enabled">
|
||||||
|
<CheckBox x:Name="MotionBlurCb" Content="{Binding [MotionBlur], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow ConfigKey="gfx.postfx.chromaticaberration.enabled">
|
||||||
|
<CheckBox x:Name="ChromaticAberrationCb" Content="{Binding [ChromaticAberration], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
</StackPanel>
|
||||||
|
</ctl:SettingsSection>
|
||||||
|
<ctl:SettingsSection Header="{Binding [GfxColNature], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<StackPanel>
|
||||||
|
<ctl:SettingRow ConfigKey="gfx.grass" Margin="0,0,0,4">
|
||||||
|
<CheckBox x:Name="GrassCb" Content="{Binding [Grass], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow x:Name="GrassDistanceRow" ConfigKey="gfx.grass.distance" Label="{Binding [GrassDistance], Source={x:Static starterNg:App.Loc}}" ValueText="{Binding #GrassDistanceSlider.Value, StringFormat='{}{0:0} m'}">
|
||||||
|
<Slider x:Name="GrassDistanceSlider" Minimum="20" Maximum="300" TickFrequency="10" IsSnapToTickEnabled="True" Value="60" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow x:Name="GrassDensityRow" ConfigKey="gfx.grass.density" Label="{Binding [GrassDensity], Source={x:Static starterNg:App.Loc}}" ValueText="{Binding #GrassDensitySlider.Value, StringFormat='{}{0:0.00}'}">
|
||||||
|
<Slider x:Name="GrassDensitySlider" Minimum="0.25" Maximum="2.0" TickFrequency="0.25" IsSnapToTickEnabled="True" Value="1.0" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow ConfigKey="gfx.smoke" Margin="0,0,0,4">
|
||||||
|
<CheckBox x:Name="SmokeDisplayCb" Content="{Binding [SmokeDisplay], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow x:Name="SmokeParticlesRow" ConfigKey="gfx.smoke.fidelity" Label="{Binding [SmokeParticlesMultiplier], Source={x:Static starterNg:App.Loc}}" IsEnabled="{Binding #SmokeDisplayCb.IsChecked}">
|
||||||
|
<Slider x:Name="SmokeParticlesSlider" Minimum="1" Maximum="4" TickFrequency="1" IsSnapToTickEnabled="True" Value="2" ValueChanged="QualitySlider_OnValueChanged" />
|
||||||
|
</ctl:SettingRow>
|
||||||
|
<ctl:SettingRow ConfigKey="gfx.precipitation.particles" Label="{Binding [Precipitation], Source={x:Static starterNg:App.Loc}}" Description="{Binding [PrecipitationDesc], Source={x:Static starterNg:App.Loc}}">
|
||||||
|
<ComboBox x:Name="PrecipitationCb" SelectedIndex="0">
|
||||||
|
<ComboBoxItem Tag="16384" Content="{Binding [QualityVeryLow], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="32768" Content="{Binding [QualityLow], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="65536" Content="{Binding [QualityNormal], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="131072" Content="{Binding [QualityHigh], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
<ComboBoxItem Tag="262144" Content="{Binding [QualityVeryHigh], Source={x:Static starterNg:App.Loc}}" />
|
||||||
|
</ComboBox>
|
||||||
|
</ctl:SettingRow>
|
||||||
|
</StackPanel>
|
||||||
|
</ctl:SettingsSection>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
<!-- ============================= SOUND ============================= -->
|
<!-- ============================= SOUND ============================= -->
|
||||||
<StackPanel Tag="sound" IsVisible="False">
|
<StackPanel Tag="sound" IsVisible="False">
|
||||||
<TextBlock Classes="CategoryCaption" IsVisible="False"
|
<TextBlock Classes="CategoryCaption" IsVisible="False"
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ public partial class Settings : UserControl, ISettingsCapture
|
|||||||
FpsLimitEnableCb.IsCheckedChanged += (_, _) => FpsLimitSlider.IsEnabled = IsChecked(FpsLimitEnableCb);
|
FpsLimitEnableCb.IsCheckedChanged += (_, _) => FpsLimitSlider.IsEnabled = IsChecked(FpsLimitEnableCb);
|
||||||
|
|
||||||
AppServices.Current.SettingsStore.RegisterCapture(this);
|
AppServices.Current.SettingsStore.RegisterCapture(this);
|
||||||
|
InitGraphics();
|
||||||
|
|
||||||
PopulateProfileCombo();
|
PopulateProfileCombo();
|
||||||
ApplyToUi();
|
ApplyToUi();
|
||||||
@@ -261,41 +262,10 @@ public partial class Settings : UserControl, ISettingsCapture
|
|||||||
LogMissingVehicleFilesCb.IsChecked = s.LogMissingVehicleFiles;
|
LogMissingVehicleFilesCb.IsChecked = s.LogMissingVehicleFiles;
|
||||||
DeveloperToolsCb.IsChecked = s.DeveloperTools;
|
DeveloperToolsCb.IsChecked = s.DeveloperTools;
|
||||||
|
|
||||||
RenderEngineCb.SelectedIndex = s.RenderEngine;
|
ApplyGraphicsToUi(s);
|
||||||
SelectResolution(s.Width, s.Height);
|
|
||||||
bufferScale.Value = s.BufferScalePercent;
|
|
||||||
textureResolutionSlider.Value = Log2(s.MaxTextureSize, 12);
|
|
||||||
cabTextureResolutionSlider.Value = Log2(s.MaxCabTextureSize, 12);
|
|
||||||
TexFilteringSlider.Value = AnisotropyToSlider(s.TextureFiltering);
|
|
||||||
MultisamplingSlider.Value = s.Multisampling + 1;
|
|
||||||
DynamicLightsSlider.Value = s.DynamicLights;
|
|
||||||
RenderRangeSlider.Value = (int)Math.Round(s.DrawRangeFactor);
|
|
||||||
VSyncCb.IsChecked = s.VSync;
|
|
||||||
SmokeDisplayCb.IsChecked = s.Smoke;
|
|
||||||
SmokeParticlesSlider.Value = s.SmokeFidelity;
|
|
||||||
ChromaticAberrationCb.IsChecked = s.ChromaticAberration;
|
|
||||||
MotionBlurCb.IsChecked = s.MotionBlur;
|
|
||||||
AdditionalShadersCb.IsChecked = s.ExtraEffects;
|
|
||||||
ReflectionsCubeMapCb.IsChecked = s.EnvMap;
|
|
||||||
RenderVBOCb.IsChecked = s.UseVbo;
|
|
||||||
RenderShadowsCb.IsChecked = s.RenderShadows;
|
|
||||||
reflectionsFramerate.Value = s.ReflectionsFramerate;
|
|
||||||
shaderResolutionSlider.Value = Log2(s.ShadowMapResolution, 12);
|
|
||||||
shaderRange.Value = s.ShadowProjectionRange;
|
|
||||||
cabShaderSourceRange.Value = s.CabShadowsRange;
|
|
||||||
ShadowDisplayCb.SelectedIndex = Clamp(s.ShadowRankCutoff - 1, 0, 2);
|
|
||||||
ReflectionsDetailsCb.SelectedIndex = s.ReflectionsFidelity;
|
|
||||||
fovSlider.Value = s.FieldOfView;
|
|
||||||
RenderScreensCb.IsChecked = s.PythonScreens;
|
RenderScreensCb.IsChecked = s.PythonScreens;
|
||||||
RenderScreensThreadCb.IsChecked = s.PythonThreadedUpload;
|
RenderScreensThreadCb.IsChecked = s.PythonThreadedUpload;
|
||||||
FpsLimitEnableCb.IsChecked = s.FpsLimitEnabled;
|
|
||||||
FpsLimitSlider.Value = s.FpsLimit;
|
|
||||||
FpsLimitSlider.IsEnabled = s.FpsLimitEnabled;
|
|
||||||
ShadowAngleLimitSlider.Value = s.ShadowAngleLimit;
|
|
||||||
FullscreenWindowedCb.IsChecked = s.FullscreenWindowed;
|
|
||||||
RenderAngleVulkanCb.IsChecked = s.RenderAngleVulkan;
|
|
||||||
|
|
||||||
TrackCurvesSlider.Value = s.SplineFidelity;
|
|
||||||
PhysicsAccuracyCb.IsChecked = s.FullPhysics;
|
PhysicsAccuracyCb.IsChecked = s.FullPhysics;
|
||||||
PantographBreakCb.IsChecked = s.EnableTraction;
|
PantographBreakCb.IsChecked = s.EnableTraction;
|
||||||
OverheadOnlyCb.IsChecked = s.LiveTraction;
|
OverheadOnlyCb.IsChecked = s.LiveTraction;
|
||||||
@@ -314,7 +284,6 @@ public partial class Settings : UserControl, ISettingsCapture
|
|||||||
VehiclesVolumeSlider.Value = s.VehiclesVolume;
|
VehiclesVolumeSlider.Value = s.VehiclesVolume;
|
||||||
PositionalVolumeSlider.Value = s.PositionalVolume;
|
PositionalVolumeSlider.Value = s.PositionalVolume;
|
||||||
AmbientVolumeSlider.Value = s.AmbientVolume;
|
AmbientVolumeSlider.Value = s.AmbientVolume;
|
||||||
SkipPipelineCb.IsChecked = s.SkipPipeline;
|
|
||||||
DebugLogVisibleCb.IsChecked = s.DebugLogVisible;
|
DebugLogVisibleCb.IsChecked = s.DebugLogVisible;
|
||||||
PyScreenPriorityCb.SelectedIndex = Math.Max(0, IndexOfTag(PyScreenPriorityCb, s.PythonScreenUpdateRate.ToString(CultureInfo.InvariantCulture)));
|
PyScreenPriorityCb.SelectedIndex = Math.Max(0, IndexOfTag(PyScreenPriorityCb, s.PythonScreenUpdateRate.ToString(CultureInfo.InvariantCulture)));
|
||||||
|
|
||||||
@@ -329,6 +298,7 @@ public partial class Settings : UserControl, ISettingsCapture
|
|||||||
}
|
}
|
||||||
|
|
||||||
UpdateQualityCaptions();
|
UpdateQualityCaptions();
|
||||||
|
UpdateGraphicsState();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -360,41 +330,10 @@ public partial class Settings : UserControl, ISettingsCapture
|
|||||||
s.LogMissingVehicleFiles = IsChecked(LogMissingVehicleFilesCb);
|
s.LogMissingVehicleFiles = IsChecked(LogMissingVehicleFilesCb);
|
||||||
s.DeveloperTools = IsChecked(DeveloperToolsCb);
|
s.DeveloperTools = IsChecked(DeveloperToolsCb);
|
||||||
|
|
||||||
s.RenderEngine = Math.Max(0, RenderEngineCb.SelectedIndex);
|
CaptureGraphicsInto(s);
|
||||||
ReadResolution(s);
|
|
||||||
s.BufferScalePercent = (int)bufferScale.Value;
|
|
||||||
s.MaxTextureSize = 1 << (int)textureResolutionSlider.Value;
|
|
||||||
s.MaxCabTextureSize = 1 << (int)cabTextureResolutionSlider.Value;
|
|
||||||
s.TextureFiltering = SimulatorSettings.AnisotropySteps[
|
|
||||||
Clamp((int)TexFilteringSlider.Value - 1, 0, SimulatorSettings.AnisotropySteps.Length - 1)];
|
|
||||||
s.Multisampling = Clamp((int)MultisamplingSlider.Value - 1, 0, 3);
|
|
||||||
s.DynamicLights = (int)DynamicLightsSlider.Value;
|
|
||||||
s.DrawRangeFactor = RenderRangeSlider.Value;
|
|
||||||
s.VSync = IsChecked(VSyncCb);
|
|
||||||
s.Smoke = IsChecked(SmokeDisplayCb);
|
|
||||||
s.SmokeFidelity = (int)SmokeParticlesSlider.Value;
|
|
||||||
s.ChromaticAberration = IsChecked(ChromaticAberrationCb);
|
|
||||||
s.MotionBlur = IsChecked(MotionBlurCb);
|
|
||||||
s.ExtraEffects = IsChecked(AdditionalShadersCb);
|
|
||||||
s.EnvMap = IsChecked(ReflectionsCubeMapCb);
|
|
||||||
s.UseVbo = IsChecked(RenderVBOCb);
|
|
||||||
s.RenderShadows = IsChecked(RenderShadowsCb);
|
|
||||||
s.ReflectionsFramerate = (int)reflectionsFramerate.Value;
|
|
||||||
s.ShadowMapResolution = 1 << (int)shaderResolutionSlider.Value;
|
|
||||||
s.ShadowProjectionRange = (int)shaderRange.Value;
|
|
||||||
s.CabShadowsRange = (int)cabShaderSourceRange.Value;
|
|
||||||
s.ShadowRankCutoff = Math.Max(0, ShadowDisplayCb.SelectedIndex) + 1;
|
|
||||||
s.ReflectionsFidelity = Math.Max(0, ReflectionsDetailsCb.SelectedIndex);
|
|
||||||
s.FieldOfView = Clamp((int)fovSlider.Value, 15, 75);
|
|
||||||
s.PythonScreens = IsChecked(RenderScreensCb);
|
s.PythonScreens = IsChecked(RenderScreensCb);
|
||||||
s.PythonThreadedUpload = IsChecked(RenderScreensThreadCb);
|
s.PythonThreadedUpload = IsChecked(RenderScreensThreadCb);
|
||||||
s.FpsLimitEnabled = IsChecked(FpsLimitEnableCb);
|
|
||||||
s.FpsLimit = (int)FpsLimitSlider.Value;
|
|
||||||
s.ShadowAngleLimit = ShadowAngleLimitSlider.Value;
|
|
||||||
s.FullscreenWindowed = IsChecked(FullscreenWindowedCb);
|
|
||||||
s.RenderAngleVulkan = IsChecked(RenderAngleVulkanCb);
|
|
||||||
|
|
||||||
s.SplineFidelity = (int)TrackCurvesSlider.Value;
|
|
||||||
s.FullPhysics = IsChecked(PhysicsAccuracyCb);
|
s.FullPhysics = IsChecked(PhysicsAccuracyCb);
|
||||||
s.EnableTraction = IsChecked(PantographBreakCb);
|
s.EnableTraction = IsChecked(PantographBreakCb);
|
||||||
s.LiveTraction = IsChecked(OverheadOnlyCb);
|
s.LiveTraction = IsChecked(OverheadOnlyCb);
|
||||||
@@ -413,7 +352,6 @@ public partial class Settings : UserControl, ISettingsCapture
|
|||||||
s.VehiclesVolume = (int)VehiclesVolumeSlider.Value;
|
s.VehiclesVolume = (int)VehiclesVolumeSlider.Value;
|
||||||
s.PositionalVolume = (int)PositionalVolumeSlider.Value;
|
s.PositionalVolume = (int)PositionalVolumeSlider.Value;
|
||||||
s.AmbientVolume = (int)AmbientVolumeSlider.Value;
|
s.AmbientVolume = (int)AmbientVolumeSlider.Value;
|
||||||
s.SkipPipeline = IsChecked(SkipPipelineCb);
|
|
||||||
s.DebugLogVisible = IsChecked(DebugLogVisibleCb);
|
s.DebugLogVisible = IsChecked(DebugLogVisibleCb);
|
||||||
s.PythonScreenUpdateRate = ParsePriorityTag((PyScreenPriorityCb.SelectedItem as ComboBoxItem)?.Tag);
|
s.PythonScreenUpdateRate = ParsePriorityTag((PyScreenPriorityCb.SelectedItem as ComboBoxItem)?.Tag);
|
||||||
|
|
||||||
@@ -444,13 +382,6 @@ public partial class Settings : UserControl, ISettingsCapture
|
|||||||
SaveStatus.Text = App.Loc["SettingsSaved"];
|
SaveStatus.Text = App.Loc["SettingsSaved"];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderEngineCb_OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
|
|
||||||
{
|
|
||||||
if (RenderEngineWarning is not null)
|
|
||||||
RenderEngineWarning.IsVisible =
|
|
||||||
SimulatorSettings.RenderEngines.ElementAtOrDefault(RenderEngineCb.SelectedIndex) == "experimental";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RedrawNavIfNeeded()
|
private void RedrawNavIfNeeded()
|
||||||
{
|
{
|
||||||
bool developer = AppServices.Current.Settings.DeveloperTools;
|
bool developer = AppServices.Current.Settings.DeveloperTools;
|
||||||
@@ -714,27 +645,37 @@ public partial class Settings : UserControl, ISettingsCapture
|
|||||||
{
|
{
|
||||||
switch (control)
|
switch (control)
|
||||||
{
|
{
|
||||||
// Choosing a profile changes nothing until Apply is pressed.
|
// Choosing a profile changes nothing until Apply is pressed, and the
|
||||||
case ComboBox combo when ReferenceEquals(combo, ProfileCb):
|
// preset marks the page itself once it has set the controls.
|
||||||
|
case ComboBox combo when ReferenceEquals(combo, ProfileCb) || ReferenceEquals(combo, QualityPresetCb):
|
||||||
break;
|
break;
|
||||||
case CheckBox cb:
|
case CheckBox cb:
|
||||||
cb.IsCheckedChanged += (_, _) => MarkDirty();
|
cb.IsCheckedChanged += (_, _) => OnEdited();
|
||||||
break;
|
break;
|
||||||
case Slider slider:
|
case Slider slider:
|
||||||
slider.ValueChanged += (_, _) => MarkDirty();
|
slider.ValueChanged += (_, _) => OnEdited();
|
||||||
break;
|
break;
|
||||||
case ComboBox combo:
|
case ComboBox combo:
|
||||||
combo.SelectionChanged += (_, _) => MarkDirty();
|
combo.SelectionChanged += (_, _) => OnEdited();
|
||||||
break;
|
break;
|
||||||
case NumericUpDown nud:
|
case NumericUpDown nud:
|
||||||
nud.ValueChanged += (_, _) => MarkDirty();
|
nud.ValueChanged += (_, _) => OnEdited();
|
||||||
|
break;
|
||||||
|
case TextBox tb when ReferenceEquals(tb, VulkanDeviceTb):
|
||||||
|
tb.TextChanged += (_, _) => OnEdited();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var section in this.GetLogicalDescendants().OfType<SettingsSection>())
|
foreach (var section in this.GetLogicalDescendants().OfType<SettingsSection>())
|
||||||
if (section.Toggle is CheckBox toggle)
|
if (section.Toggle is CheckBox toggle)
|
||||||
toggle.IsCheckedChanged += (_, _) => MarkDirty();
|
toggle.IsCheckedChanged += (_, _) => OnEdited();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEdited()
|
||||||
|
{
|
||||||
|
MarkDirty();
|
||||||
|
UpdateGraphicsState();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MarkDirty()
|
private void MarkDirty()
|
||||||
@@ -1411,10 +1352,6 @@ public partial class Settings : UserControl, ISettingsCapture
|
|||||||
if (SmokeParticlesRow != null)
|
if (SmokeParticlesRow != null)
|
||||||
SmokeParticlesRow.ValueText = four[Clamp((int)SmokeParticlesSlider.Value, 1, 4) - 1];
|
SmokeParticlesRow.ValueText = four[Clamp((int)SmokeParticlesSlider.Value, 1, 4) - 1];
|
||||||
|
|
||||||
string[] msaa = { App.Loc["MsaaNone"], "x2", "x4", "x8" };
|
|
||||||
if (MultisamplingRow != null)
|
|
||||||
MultisamplingRow.ValueText = msaa[Clamp((int)MultisamplingSlider.Value, 1, 4) - 1];
|
|
||||||
|
|
||||||
string[] range = { App.Loc["RangeNormal"], App.Loc["RangeHigh"], App.Loc["RangeVeryHigh"] };
|
string[] range = { App.Loc["RangeNormal"], App.Loc["RangeHigh"], App.Loc["RangeVeryHigh"] };
|
||||||
if (RenderRangeRow != null)
|
if (RenderRangeRow != null)
|
||||||
RenderRangeRow.ValueText = range[Clamp((int)RenderRangeSlider.Value, 1, 3) - 1];
|
RenderRangeRow.ValueText = range[Clamp((int)RenderRangeSlider.Value, 1, 3) - 1];
|
||||||
@@ -1435,13 +1372,6 @@ public partial class Settings : UserControl, ISettingsCapture
|
|||||||
ToolTip.SetTip(shaderRange, ShadowRangeWord(metres));
|
ToolTip.SetTip(shaderRange, ShadowRangeWord(metres));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CabShadowRangeRow != null)
|
|
||||||
{
|
|
||||||
int metres = (int)cabShaderSourceRange.Value;
|
|
||||||
CabShadowRangeRow.ValueText = metres <= 0 ? App.Loc["RangeDisabled"] : $"{metres} m";
|
|
||||||
ToolTip.SetTip(cabShaderSourceRange, CabShadowRangeWord(metres));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ReflectionsFramerateRow != null)
|
if (ReflectionsFramerateRow != null)
|
||||||
{
|
{
|
||||||
int fps = (int)reflectionsFramerate.Value;
|
int fps = (int)reflectionsFramerate.Value;
|
||||||
@@ -1469,15 +1399,6 @@ public partial class Settings : UserControl, ISettingsCapture
|
|||||||
_ => App.Loc["RangeVeryHigh"]
|
_ => App.Loc["RangeVeryHigh"]
|
||||||
};
|
};
|
||||||
|
|
||||||
private static string CabShadowRangeWord(int metres) => metres switch
|
|
||||||
{
|
|
||||||
<= 10 => App.Loc["RangeVeryLow"],
|
|
||||||
<= 20 => App.Loc["RangeLow"],
|
|
||||||
<= 30 => App.Loc["RangeStandard"],
|
|
||||||
<= 50 => App.Loc["RangeHigh"],
|
|
||||||
_ => App.Loc["RangeVeryHigh"]
|
|
||||||
};
|
|
||||||
|
|
||||||
private static string ReflectionsRefreshWord(int fps) => fps switch
|
private static string ReflectionsRefreshWord(int fps) => fps switch
|
||||||
{
|
{
|
||||||
<= 5 => App.Loc["QualityVeryLow"],
|
<= 5 => App.Loc["QualityVeryLow"],
|
||||||
|
|||||||
@@ -364,20 +364,12 @@
|
|||||||
|
|
||||||
<String key="Graphic">Grafika</String>
|
<String key="Graphic">Grafika</String>
|
||||||
<String key="RenderEngine">Vykreslovací engine</String>
|
<String key="RenderEngine">Vykreslovací engine</String>
|
||||||
<String key="REFull">Plný</String>
|
|
||||||
<String key="REOld">Starý</String>
|
|
||||||
<String key="RESimpShader">Zjednodušený shader</String>
|
|
||||||
<String key="RESimp">Zjednodušený</String>
|
|
||||||
<String key="REOff">Vypnout vizuální vrstvu</String>
|
|
||||||
<String key="REExperimental">Experimentální</String>
|
|
||||||
<String key="REExperimentalWarning">Upozornění: experimentální renderer je ve vývoji. Může být nestabilní, nezobrazovat části scény nebo se na některých grafických kartách nespustit. Pokud se simulátor nespustí nebo vypadá špatně, vraťte se k rendereru „Plný“.</String>
|
|
||||||
|
|
||||||
<String key="Resolution">Rozlišení</String>
|
<String key="Resolution">Rozlišení</String>
|
||||||
<String key="BufforResolution">Rozlišení bufferu</String>
|
<String key="BufforResolution">Rozlišení bufferu</String>
|
||||||
<String key="MaxTexResolution">Maximální rozlišení textur</String>
|
<String key="MaxTexResolution">Maximální rozlišení textur</String>
|
||||||
<String key="MaxTexCabResolution">Maximální rozlišení textur kabiny</String>
|
<String key="MaxTexCabResolution">Maximální rozlišení textur kabiny</String>
|
||||||
<String key="TexFilteringQuality">Kvalita filtrování textur</String>
|
<String key="TexFilteringQuality">Kvalita filtrování textur</String>
|
||||||
<String key="Multisampling">Multisampling</String>
|
|
||||||
<String key="QualityVeryLow">Velmi nízká</String>
|
<String key="QualityVeryLow">Velmi nízká</String>
|
||||||
<String key="QualityLow">Nízká</String>
|
<String key="QualityLow">Nízká</String>
|
||||||
<String key="QualityNormal">Normální</String>
|
<String key="QualityNormal">Normální</String>
|
||||||
@@ -401,7 +393,6 @@
|
|||||||
<String key="ShadowLimitNone">Bez omezení</String>
|
<String key="ShadowLimitNone">Bez omezení</String>
|
||||||
<String key="ShadowLimitShort">Zkrácené</String>
|
<String key="ShadowLimitShort">Zkrácené</String>
|
||||||
<String key="FullscreenWindowed">Automatické rozlišení (celá obrazovka bez okrajů)</String>
|
<String key="FullscreenWindowed">Automatické rozlišení (celá obrazovka bez okrajů)</String>
|
||||||
<String key="RenderAngleVulkan">Použít renderer ANGLE Vulkan</String>
|
|
||||||
<String key="VSync">VSync</String>
|
<String key="VSync">VSync</String>
|
||||||
<String key="SmokeDisplay">Zobrazení kouře</String>
|
<String key="SmokeDisplay">Zobrazení kouře</String>
|
||||||
<String key="SmokeParticlesMultiplier">Násobitel částic kouře</String>
|
<String key="SmokeParticlesMultiplier">Násobitel částic kouře</String>
|
||||||
@@ -411,12 +402,10 @@
|
|||||||
<String key="AdditionalShadersEffects">Další efekty shaderů</String>
|
<String key="AdditionalShadersEffects">Další efekty shaderů</String>
|
||||||
<String key="ReflectionsCubeMap">Odrazy jako cubemapa</String>
|
<String key="ReflectionsCubeMap">Odrazy jako cubemapa</String>
|
||||||
<String key="SkipPipeline">SkipPipeline</String>
|
<String key="SkipPipeline">SkipPipeline</String>
|
||||||
<String key="RenderVBO">Vykreslování VBO</String>
|
|
||||||
<String key="RenderShadows">Vykreslovat stíny</String>
|
<String key="RenderShadows">Vykreslovat stíny</String>
|
||||||
<String key="ReflectionsFramerate">Frekvence obnovy odrazů</String>
|
<String key="ReflectionsFramerate">Frekvence obnovy odrazů</String>
|
||||||
<String key="ShadowsResolution">Rozlišení stínů</String>
|
<String key="ShadowsResolution">Rozlišení stínů</String>
|
||||||
<String key="ShaderRange">Dosah stínů</String>
|
<String key="ShaderRange">Dosah stínů</String>
|
||||||
<String key="CabShadowsRange">Dosah zdrojů stínů v kabině</String>
|
|
||||||
|
|
||||||
<String key="ShadowDisplay">Zobrazovat stíny</String>
|
<String key="ShadowDisplay">Zobrazovat stíny</String>
|
||||||
<String key="CSROnlyImportant">Jen důležité</String>
|
<String key="CSROnlyImportant">Jen důležité</String>
|
||||||
@@ -458,7 +447,6 @@
|
|||||||
<String key="Advanced">Pokročilé</String>
|
<String key="Advanced">Pokročilé</String>
|
||||||
<String key="CompressTextures">Komprimovat textury TGA</String>
|
<String key="CompressTextures">Komprimovat textury TGA</String>
|
||||||
<String key="ScaleSpeculars">Škálovat odlesky (kompatibilita starých modelů)</String>
|
<String key="ScaleSpeculars">Škálovat odlesky (kompatibilita starých modelů)</String>
|
||||||
<String key="UseGLES">Použít OpenGL ES</String>
|
|
||||||
<String key="ShaderGamma">Gama korekce v shaderech</String>
|
<String key="ShaderGamma">Gama korekce v shaderech</String>
|
||||||
<String key="ScreenMipmaps">Generovat mipmapy pro textury displejů v kabině (Python)</String>
|
<String key="ScreenMipmaps">Generovat mipmapy pro textury displejů v kabině (Python)</String>
|
||||||
<String key="ExtendedModelConversion">Rozšířený převod modelů E3D (experimentální)</String>
|
<String key="ExtendedModelConversion">Rozšířený převod modelů E3D (experimentální)</String>
|
||||||
@@ -590,7 +578,6 @@
|
|||||||
<String key="RuleNew">— nové pravidlo —</String>
|
<String key="RuleNew">— nové pravidlo —</String>
|
||||||
<String key="RuleRemove">Odebrat z pravidla</String>
|
<String key="RuleRemove">Odebrat z pravidla</String>
|
||||||
<String key="CatAll">Vše</String>
|
<String key="CatAll">Vše</String>
|
||||||
<String key="GfxColResolution">Rozlišení a textury</String>
|
|
||||||
<String key="GfxColRendering">Vykreslování</String>
|
<String key="GfxColRendering">Vykreslování</String>
|
||||||
<String key="GfxColShadows">Stíny</String>
|
<String key="GfxColShadows">Stíny</String>
|
||||||
<String key="GfxColReflections">Odrazy a pohled</String>
|
<String key="GfxColReflections">Odrazy a pohled</String>
|
||||||
|
|||||||
@@ -371,24 +371,15 @@
|
|||||||
|
|
||||||
<String key="Graphic">Graphics</String>
|
<String key="Graphic">Graphics</String>
|
||||||
<String key="RenderEngine">Render engine</String>
|
<String key="RenderEngine">Render engine</String>
|
||||||
<String key="RenderEngineDesc">OpenGL rendering path. 'Simplified' and 'Old' use the legacy renderer.</String>
|
<String key="RenderEngineDesc">OpenGL 4.6 runs everywhere. Vulkan 1.4 adds DLSS, frame generation, Reflex and ray tracing; where it cannot start on this computer the simulator falls back to OpenGL by itself.</String>
|
||||||
<String key="REFull">Full</String>
|
|
||||||
<String key="REOld">Old</String>
|
|
||||||
<String key="RESimpShader">Simplified (legacy)</String>
|
|
||||||
<String key="RESimp">Simplified</String>
|
|
||||||
<String key="REOff">Disable visual layer</String>
|
|
||||||
<String key="REExperimental">Experimental</String>
|
|
||||||
<String key="REExperimentalWarning">Note: the experimental renderer is still being developed. It may be unstable, miss parts of the scene or not start on some graphics cards. If the simulator does not start or looks wrong, go back to the “Full” renderer.</String>
|
|
||||||
|
|
||||||
<String key="Resolution">Resolution</String>
|
<String key="Resolution">Resolution</String>
|
||||||
<String key="BufforResolution">Buffer resolution</String>
|
<String key="BufforResolution">Render scale</String>
|
||||||
<String key="BufforResolutionDesc">Scales the internal render buffer relative to the window resolution.</String>
|
<String key="BufforResolutionDesc">The size of the scene image relative to the window. With DLSS it is the resolution DLSS upscales from (about 67% quality, 50% performance); DLAA always draws at full resolution.</String>
|
||||||
<String key="MaxTexResolution">Maximum texture resolution</String>
|
<String key="MaxTexResolution">Maximum texture resolution</String>
|
||||||
<String key="MaxTexCabResolution">Maximum cabin texture resolution</String>
|
<String key="MaxTexCabResolution">Maximum cabin texture resolution</String>
|
||||||
<String key="TexFilteringQuality">Texture filtering quality</String>
|
<String key="TexFilteringQuality">Texture filtering quality</String>
|
||||||
<String key="TexFilteringQualityDesc">Anisotropic texture filtering level.</String>
|
<String key="TexFilteringQualityDesc">Anisotropic texture filtering level.</String>
|
||||||
<String key="Multisampling">Multisampling</String>
|
|
||||||
<String key="MultisamplingDesc">Anti-aliasing of object edges. Higher settings cost more GPU time.</String>
|
|
||||||
<String key="QualityVeryLow">Very low</String>
|
<String key="QualityVeryLow">Very low</String>
|
||||||
<String key="QualityLow">Low</String>
|
<String key="QualityLow">Low</String>
|
||||||
<String key="QualityNormal">Normal</String>
|
<String key="QualityNormal">Normal</String>
|
||||||
@@ -406,7 +397,7 @@
|
|||||||
<String key="RangeVeryHigh">Very high</String>
|
<String key="RangeVeryHigh">Very high</String>
|
||||||
<String key="RangeDisabled">Disabled</String>
|
<String key="RangeDisabled">Disabled</String>
|
||||||
<String key="DynamicLights">Dynamic light sources</String>
|
<String key="DynamicLights">Dynamic light sources</String>
|
||||||
<String key="DynamicLightsDesc">Maximum number of simultaneous dynamic light sources.</String>
|
<String key="DynamicLightsDesc">How many vehicle headlights shine at once. Used only without clustered lighting.</String>
|
||||||
<String key="RenderRange">Rendering range</String>
|
<String key="RenderRange">Rendering range</String>
|
||||||
<String key="RenderRangeDesc">Maximum draw-distance multiplier; the engine lowers it automatically when the FPS drops.</String>
|
<String key="RenderRangeDesc">Maximum draw-distance multiplier; the engine lowers it automatically when the FPS drops.</String>
|
||||||
<String key="FpsLimitEnable">Limit frame rate</String>
|
<String key="FpsLimitEnable">Limit frame rate</String>
|
||||||
@@ -415,8 +406,6 @@
|
|||||||
<String key="ShadowLimitNone">No limit</String>
|
<String key="ShadowLimitNone">No limit</String>
|
||||||
<String key="ShadowLimitShort">Shortened</String>
|
<String key="ShadowLimitShort">Shortened</String>
|
||||||
<String key="FullscreenWindowed">Automatic resolution (borderless fullscreen)</String>
|
<String key="FullscreenWindowed">Automatic resolution (borderless fullscreen)</String>
|
||||||
<String key="RenderAngleVulkan">Use ANGLE Vulkan renderer</String>
|
|
||||||
<String key="RenderAngleVulkanDesc">Runs the ANGLE renderer on Vulkan instead of the default backend. Useful when OpenGL misbehaves.</String>
|
|
||||||
<String key="VSync">VSync</String>
|
<String key="VSync">VSync</String>
|
||||||
<String key="VSyncDesc">Synchronizes frame rate with the monitor refresh rate.</String>
|
<String key="VSyncDesc">Synchronizes frame rate with the monitor refresh rate.</String>
|
||||||
<String key="SmokeDisplay">Smoke display</String>
|
<String key="SmokeDisplay">Smoke display</String>
|
||||||
@@ -427,16 +416,12 @@
|
|||||||
<String key="AdditionalShadersEffects">Additional shader effects</String>
|
<String key="AdditionalShadersEffects">Additional shader effects</String>
|
||||||
<String key="ReflectionsCubeMap">Reflections as cubemap</String>
|
<String key="ReflectionsCubeMap">Reflections as cubemap</String>
|
||||||
<String key="ReflectionsCubeMapDesc">Renders reflections into a cube map, so surfaces mirror the surroundings from every direction.</String>
|
<String key="ReflectionsCubeMapDesc">Renders reflections into a cube map, so surfaces mirror the surroundings from every direction.</String>
|
||||||
<String key="SkipPipeline">Simplified depth read (compatibility)</String>
|
<String key="SkipPipeline">Skip the post-processing pipeline</String>
|
||||||
<String key="SkipPipelineDesc">Alternative depth-buffer read path with MSAA; enable it if your GPU has compatibility issues.</String>
|
<String key="SkipPipelineDesc">Draws the scene straight to the screen, without TAA/DLSS, exposure, bloom and blur. Only for problems with the graphics card.</String>
|
||||||
<String key="RenderVBO">Render VBO</String>
|
|
||||||
<String key="RenderVBODesc">Keeps geometry in GPU buffers (faster). Disable only if you have problems with an old GPU.</String>
|
|
||||||
<String key="RenderShadows">Render shadows</String>
|
<String key="RenderShadows">Render shadows</String>
|
||||||
<String key="ReflectionsFramerate">Reflections refresh rate</String>
|
<String key="ReflectionsFramerate">Reflections refresh rate</String>
|
||||||
<String key="ShadowsResolution">Shadows resolution</String>
|
<String key="ShadowsResolution">Shadows resolution</String>
|
||||||
<String key="ShaderRange">Shadow range</String>
|
<String key="ShaderRange">Shadow range</String>
|
||||||
<String key="CabShadowsRange">Cabin shadow sources range</String>
|
|
||||||
<String key="CabShadowsRangeDesc">Distance at which light sources still cast shadows inside the cab. Zero turns cab shadows off.</String>
|
|
||||||
|
|
||||||
<String key="ShadowDisplay">Display shadows</String>
|
<String key="ShadowDisplay">Display shadows</String>
|
||||||
<String key="ShadowDisplayDesc">Sets which objects cast shadows based on material priority. Lower value = fewer shadows, higher performance.</String>
|
<String key="ShadowDisplayDesc">Sets which objects cast shadows based on material priority. Lower value = fewer shadows, higher performance.</String>
|
||||||
@@ -445,7 +430,7 @@
|
|||||||
<String key="CSRAll">All</String>
|
<String key="CSRAll">All</String>
|
||||||
|
|
||||||
<String key="ReflectionsDetails">Reflections detail level</String>
|
<String key="ReflectionsDetails">Reflections detail level</String>
|
||||||
<String key="ReflectionsDetailsDesc">Which objects are rendered into the reflection cubemap.</String>
|
<String key="ReflectionsDetailsDesc">What the environment map and ray traced reflections show.</String>
|
||||||
<String key="RDTerrain">Terrain geometry only</String>
|
<String key="RDTerrain">Terrain geometry only</String>
|
||||||
<String key="RDTerrainModels">Terrain geometry and static models</String>
|
<String key="RDTerrainModels">Terrain geometry and static models</String>
|
||||||
<String key="RDTerrainModelsVehicles">Terrain geometry, static models and vehicles</String>
|
<String key="RDTerrainModelsVehicles">Terrain geometry, static models and vehicles</String>
|
||||||
@@ -493,7 +478,6 @@
|
|||||||
<String key="Advanced">Advanced</String>
|
<String key="Advanced">Advanced</String>
|
||||||
<String key="CompressTextures">Compress TGA textures</String>
|
<String key="CompressTextures">Compress TGA textures</String>
|
||||||
<String key="ScaleSpeculars">Scale specular highlights (old-model compatibility)</String>
|
<String key="ScaleSpeculars">Scale specular highlights (old-model compatibility)</String>
|
||||||
<String key="UseGLES">Use OpenGL ES</String>
|
|
||||||
<String key="ShaderGamma">Gamma correction in shaders</String>
|
<String key="ShaderGamma">Gamma correction in shaders</String>
|
||||||
<String key="ScreenMipmaps">Generate mipmaps for in-cab (Python) screen textures</String>
|
<String key="ScreenMipmaps">Generate mipmaps for in-cab (Python) screen textures</String>
|
||||||
<String key="ExtendedModelConversion">Extended E3D model conversion (experimental)</String>
|
<String key="ExtendedModelConversion">Extended E3D model conversion (experimental)</String>
|
||||||
@@ -626,10 +610,9 @@
|
|||||||
<String key="RuleNew">— new rule —</String>
|
<String key="RuleNew">— new rule —</String>
|
||||||
<String key="RuleRemove">Remove from rule</String>
|
<String key="RuleRemove">Remove from rule</String>
|
||||||
<String key="CatAll">All</String>
|
<String key="CatAll">All</String>
|
||||||
<String key="GfxColResolution">Resolution and textures</String>
|
|
||||||
<String key="GfxColRendering">Rendering</String>
|
<String key="GfxColRendering">Rendering</String>
|
||||||
<String key="GfxColShadows">Shadows</String>
|
<String key="GfxColShadows">Shadows</String>
|
||||||
<String key="GfxColReflections">Reflections and view</String>
|
<String key="GfxColReflections">Reflections</String>
|
||||||
<String key="GfxColScripts">Python scripts</String>
|
<String key="GfxColScripts">Python scripts</String>
|
||||||
<String key="UartHint">Port name / leave alone / data send rate</String>
|
<String key="UartHint">Port name / leave alone / data send rate</String>
|
||||||
<String key="UartFeature">UARTfeature:</String>
|
<String key="UartFeature">UARTfeature:</String>
|
||||||
@@ -671,4 +654,103 @@
|
|||||||
<String key="DevLocation">Copy folder</String>
|
<String key="DevLocation">Copy folder</String>
|
||||||
<String key="DevRebuild">Rebuild copy</String>
|
<String key="DevRebuild">Rebuild copy</String>
|
||||||
<String key="DevRebuilt">Rebuilt</String>
|
<String key="DevRebuilt">Rebuilt</String>
|
||||||
|
<!-- Graphics: renderer, anti-aliasing, effects, presets, eu07.ini import and export -->
|
||||||
|
<String key="Effects">Effects</String>
|
||||||
|
<String key="GfxColQuality">Quality and renderer</String>
|
||||||
|
<String key="GfxColImage">Resolution and anti-aliasing</String>
|
||||||
|
<String key="GfxColTextures">Textures and geometry</String>
|
||||||
|
<String key="GfxColLights">Lighting</String>
|
||||||
|
<String key="GfxColAtmosphere">Atmosphere and weather</String>
|
||||||
|
<String key="GfxColPostFx">Post-processing</String>
|
||||||
|
<String key="GfxColNature">Vegetation and particles</String>
|
||||||
|
<String key="QualityPreset">Quality preset</String>
|
||||||
|
<String key="QualityPresetDesc">Sets the quality of the graphics and effects at once. Resolution, render scale, VSync, field of view, motion blur, chromatic aberration and DLSS stay as they are. After a manual change the preset shows “Custom”.</String>
|
||||||
|
<String key="PresetLowest">Lowest</String>
|
||||||
|
<String key="PresetLow">Low</String>
|
||||||
|
<String key="PresetMedium">Medium</String>
|
||||||
|
<String key="PresetHigh">High</String>
|
||||||
|
<String key="PresetUltra">Ultra</String>
|
||||||
|
<String key="PresetCustom">Custom</String>
|
||||||
|
<String key="REOpenGL">OpenGL 4.6</String>
|
||||||
|
<String key="REVulkan">Vulkan 1.4</String>
|
||||||
|
<String key="REVulkanNote"></String>
|
||||||
|
<String key="REOpenGLNote">DLSS, frame generation, Reflex and ray tracing are available with the Vulkan renderer only.</String>
|
||||||
|
<String key="VulkanDevice">Graphics card (Vulkan)</String>
|
||||||
|
<String key="VulkanDeviceDesc">The number of the card from the list in the log, or part of its name, e.g. “RTX”. Empty: chosen automatically.</String>
|
||||||
|
<String key="VulkanDeviceAuto">automatic</String>
|
||||||
|
<String key="AntiAliasing">Anti-aliasing</String>
|
||||||
|
<String key="AntiAliasingDesc">MSAA smooths the edges of objects, TAA the whole image at the cost of a slight blur. DLSS and DLAA need Vulkan and an NVIDIA RTX card; otherwise the simulator uses TAA.</String>
|
||||||
|
<String key="AaTaa">TAA</String>
|
||||||
|
<String key="AaDlss">DLSS (upscaling)</String>
|
||||||
|
<String key="AaDlaa">DLAA (native resolution)</String>
|
||||||
|
<String key="DlssPreset">DLSS preset</String>
|
||||||
|
<String key="DlssPresetDesc">The network model DLSS rebuilds the image with. The DLSS mode follows the render scale: about 67% Quality, 58% Balanced, 50% Performance, 33% Ultra Performance.</String>
|
||||||
|
<String key="DlssPresetDefault">Automatic (chosen by the driver)</String>
|
||||||
|
<String key="DlssPresetK">K – best image quality</String>
|
||||||
|
<String key="DlssPresetJ">J – less ghosting, more flicker</String>
|
||||||
|
<String key="DlssPresetM">M – for Performance mode (about 50%)</String>
|
||||||
|
<String key="DlssPresetL">L – for Ultra Performance mode (about 33%)</String>
|
||||||
|
<String key="DlssPresetInfoDefault">K for DLAA, Quality and Balanced, M for Performance, L for Ultra Performance. The driver may change this with an update.</String>
|
||||||
|
<String key="DlssPresetInfoK">The transformer model with the best image quality, but the most expensive to compute. The default for DLAA, Quality and Balanced.</String>
|
||||||
|
<String key="DlssPresetInfoJ">Similar to K: slightly less ghosting behind moving objects at the cost of more flicker. NVIDIA recommends K instead.</String>
|
||||||
|
<String key="DlssPresetInfoM">The model tuned for Performance mode (about 50% scale), its default there. Works out the image exposure itself.</String>
|
||||||
|
<String key="DlssPresetInfoL">The model tuned for Ultra Performance mode (about 33% scale), its default there. Works out the image exposure itself.</String>
|
||||||
|
<String key="FrameGeneration">Frame generation</String>
|
||||||
|
<String key="FrameGenerationDesc">Extra frames shown between the drawn ones (DLSS Frame Generation). x3 and x4 on RTX 50 cards only, older ones get x2.</String>
|
||||||
|
<String key="FrameGenerationNeedsDlssNote">Frame generation works with DLSS or DLAA only.</String>
|
||||||
|
<String key="Reflex">NVIDIA Reflex</String>
|
||||||
|
<String key="ReflexDesc">Lowers the delay between input and image. Vulkan only.</String>
|
||||||
|
<String key="ReflexOn">On</String>
|
||||||
|
<String key="ReflexBoost">On + boost</String>
|
||||||
|
<String key="ReflexForcedNote">Frame generation turns Reflex on by itself, whatever is chosen here.</String>
|
||||||
|
<String key="DlssMissingLibraryNote">{0} is not next to the simulator – without it the simulator cannot use this DLSS feature.</String>
|
||||||
|
<String key="DlssNoPlatformNote">DLSS is not available on macOS.</String>
|
||||||
|
<String key="TemporalNeedsPipelineNote">TAA and DLSS run in the post-processing – with the post-processing pipeline skipped the edges will not be smoothed.</String>
|
||||||
|
<String key="VulkanOnlyNote">Available with the Vulkan renderer only.</String>
|
||||||
|
<String key="ShadowSdsm">Shadow cascades fitted to the scene (SDSM)</String>
|
||||||
|
<String key="ShadowSdsmDesc">Spreads the resolution of the sun shadows over what is actually in view instead of fixed distances.</String>
|
||||||
|
<String key="LightsClustered">Clustered lighting</String>
|
||||||
|
<String key="LightsClusteredDesc">Vehicle lights and lamps without a limit on their number. Needed for the point lights of the scenery and the cab lamp.</String>
|
||||||
|
<String key="LightShadows">Shadows of lamps and headlights</String>
|
||||||
|
<String key="LightShadowsDesc">Shadows cast by the cab lamp, street lamps and vehicle headlights.</String>
|
||||||
|
<String key="ContactShadows">Contact shadows</String>
|
||||||
|
<String key="ContactShadowsDesc">Small shadows where objects touch, which the shadow map misses.</String>
|
||||||
|
<String key="AmbientOcclusion">Ambient occlusion</String>
|
||||||
|
<String key="AmbientOcclusionDesc">Darkens corners and creases. GTAO is more accurate than the older SSAO.</String>
|
||||||
|
<String key="AmbientOcclusionQuality">Occlusion quality</String>
|
||||||
|
<String key="Ssr">Screen space reflections (SSR)</String>
|
||||||
|
<String key="SsrDesc">Reflections of what is on screen on wet and smooth surfaces.</String>
|
||||||
|
<String key="RayTracing">Ray traced reflections</String>
|
||||||
|
<String key="RayTracingDesc">Fills in reflections where SSR finds nothing. Vulkan and a card with ray tracing (ray queries) only.</String>
|
||||||
|
<String key="RayTracingRange">Ray tracing range</String>
|
||||||
|
<String key="VolumetricFog">Volumetric fog</String>
|
||||||
|
<String key="VolumetricFogDesc">Fog with sun shafts, cloud shadows and the light of lamps. Off: the simpler analytic fog.</String>
|
||||||
|
<String key="FogQuality">Fog quality</String>
|
||||||
|
<String key="Clouds">Volumetric clouds</String>
|
||||||
|
<String key="CloudsDesc">The quality of the clouds drawn in the sky.</String>
|
||||||
|
<String key="CloudShadows">Cloud shadows on the ground</String>
|
||||||
|
<String key="Bloom">Glow of bright areas (bloom)</String>
|
||||||
|
<String key="AutoExposure">Automatic exposure</String>
|
||||||
|
<String key="AutoExposureDesc">The image brightness follows the scene, e.g. entering a tunnel.</String>
|
||||||
|
<String key="Grass">Grass</String>
|
||||||
|
<String key="GrassDistance">Grass distance</String>
|
||||||
|
<String key="GrassDensity">Grass density</String>
|
||||||
|
<String key="Precipitation">Precipitation (particles)</String>
|
||||||
|
<String key="PrecipitationDesc">The number of raindrops and snowflakes.</String>
|
||||||
|
<String key="LevelOff">Off</String>
|
||||||
|
<String key="LevelLow">Low</String>
|
||||||
|
<String key="LevelMedium">Medium</String>
|
||||||
|
<String key="LevelHigh">High</String>
|
||||||
|
<String key="LevelUltra">Ultra</String>
|
||||||
|
<String key="SettingsFile">eu07.ini file</String>
|
||||||
|
<String key="ImportIni">Import…</String>
|
||||||
|
<String key="ImportIniTitle">Import settings from eu07.ini</String>
|
||||||
|
<String key="ImportIniFailed">The file could not be read:
|
||||||
|
{0}</String>
|
||||||
|
<String key="ImportIniDone">Imported {0} – save to keep it</String>
|
||||||
|
<String key="ExportIni">Export…</String>
|
||||||
|
<String key="ExportIniTitle">Export settings to eu07.ini</String>
|
||||||
|
<String key="ExportIniFailed">The file could not be written:
|
||||||
|
{0}</String>
|
||||||
|
<String key="ExportIniDone">Exported to {0}</String>
|
||||||
</Language>
|
</Language>
|
||||||
|
|||||||
@@ -364,20 +364,12 @@
|
|||||||
|
|
||||||
<String key="Graphic">Grafika</String>
|
<String key="Graphic">Grafika</String>
|
||||||
<String key="RenderEngine">Megjelenítő motor</String>
|
<String key="RenderEngine">Megjelenítő motor</String>
|
||||||
<String key="REFull">Teljes</String>
|
|
||||||
<String key="REOld">Régi</String>
|
|
||||||
<String key="RESimpShader">Egyszerűsített shader</String>
|
|
||||||
<String key="RESimp">Egyszerűsített</String>
|
|
||||||
<String key="REOff">Vizuális réteg kikapcsolása</String>
|
|
||||||
<String key="REExperimental">Kísérleti</String>
|
|
||||||
<String key="REExperimentalWarning">Figyelem: a kísérleti renderelő még fejlesztés alatt áll. Instabil lehet, a jelenet egyes részei hiányozhatnak, vagy egyes videokártyákon el sem indul. Ha a szimulátor nem indul el vagy hibásan jelenik meg, válts vissza a „Teljes” renderelőre.</String>
|
|
||||||
|
|
||||||
<String key="Resolution">Felbontás</String>
|
<String key="Resolution">Felbontás</String>
|
||||||
<String key="BufforResolution">Puffer felbontása</String>
|
<String key="BufforResolution">Puffer felbontása</String>
|
||||||
<String key="MaxTexResolution">Textúrák legnagyobb felbontása</String>
|
<String key="MaxTexResolution">Textúrák legnagyobb felbontása</String>
|
||||||
<String key="MaxTexCabResolution">Vezetőállás-textúrák legnagyobb felbontása</String>
|
<String key="MaxTexCabResolution">Vezetőállás-textúrák legnagyobb felbontása</String>
|
||||||
<String key="TexFilteringQuality">Textúraszűrés minősége</String>
|
<String key="TexFilteringQuality">Textúraszűrés minősége</String>
|
||||||
<String key="Multisampling">Multisampling</String>
|
|
||||||
<String key="QualityVeryLow">Nagyon alacsony</String>
|
<String key="QualityVeryLow">Nagyon alacsony</String>
|
||||||
<String key="QualityLow">Alacsony</String>
|
<String key="QualityLow">Alacsony</String>
|
||||||
<String key="QualityNormal">Normál</String>
|
<String key="QualityNormal">Normál</String>
|
||||||
@@ -401,7 +393,6 @@
|
|||||||
<String key="ShadowLimitNone">Nincs korlát</String>
|
<String key="ShadowLimitNone">Nincs korlát</String>
|
||||||
<String key="ShadowLimitShort">Rövidített</String>
|
<String key="ShadowLimitShort">Rövidített</String>
|
||||||
<String key="FullscreenWindowed">Automatikus felbontás (keret nélküli teljes képernyő)</String>
|
<String key="FullscreenWindowed">Automatikus felbontás (keret nélküli teljes képernyő)</String>
|
||||||
<String key="RenderAngleVulkan">ANGLE Vulkan megjelenítő használata</String>
|
|
||||||
<String key="VSync">VSync</String>
|
<String key="VSync">VSync</String>
|
||||||
<String key="SmokeDisplay">Füst megjelenítése</String>
|
<String key="SmokeDisplay">Füst megjelenítése</String>
|
||||||
<String key="SmokeParticlesMultiplier">Füstrészecskék szorzója</String>
|
<String key="SmokeParticlesMultiplier">Füstrészecskék szorzója</String>
|
||||||
@@ -411,12 +402,10 @@
|
|||||||
<String key="AdditionalShadersEffects">További shader-effektek</String>
|
<String key="AdditionalShadersEffects">További shader-effektek</String>
|
||||||
<String key="ReflectionsCubeMap">Tükröződések cubemapként</String>
|
<String key="ReflectionsCubeMap">Tükröződések cubemapként</String>
|
||||||
<String key="SkipPipeline">SkipPipeline</String>
|
<String key="SkipPipeline">SkipPipeline</String>
|
||||||
<String key="RenderVBO">VBO megjelenítés</String>
|
|
||||||
<String key="RenderShadows">Árnyékok megjelenítése</String>
|
<String key="RenderShadows">Árnyékok megjelenítése</String>
|
||||||
<String key="ReflectionsFramerate">Tükröződések frissítési gyakorisága</String>
|
<String key="ReflectionsFramerate">Tükröződések frissítési gyakorisága</String>
|
||||||
<String key="ShadowsResolution">Árnyékok felbontása</String>
|
<String key="ShadowsResolution">Árnyékok felbontása</String>
|
||||||
<String key="ShaderRange">Árnyékok hatótávolsága</String>
|
<String key="ShaderRange">Árnyékok hatótávolsága</String>
|
||||||
<String key="CabShadowsRange">Vezetőállás árnyékforrásainak hatótávolsága</String>
|
|
||||||
|
|
||||||
<String key="ShadowDisplay">Árnyékok megjelenítése</String>
|
<String key="ShadowDisplay">Árnyékok megjelenítése</String>
|
||||||
<String key="CSROnlyImportant">Csak a fontosak</String>
|
<String key="CSROnlyImportant">Csak a fontosak</String>
|
||||||
@@ -458,7 +447,6 @@
|
|||||||
<String key="Advanced">Speciális</String>
|
<String key="Advanced">Speciális</String>
|
||||||
<String key="CompressTextures">TGA textúrák tömörítése</String>
|
<String key="CompressTextures">TGA textúrák tömörítése</String>
|
||||||
<String key="ScaleSpeculars">Csillanások skálázása (régi modellek kompatibilitása)</String>
|
<String key="ScaleSpeculars">Csillanások skálázása (régi modellek kompatibilitása)</String>
|
||||||
<String key="UseGLES">OpenGL ES használata</String>
|
|
||||||
<String key="ShaderGamma">Gammakorrekció a shaderekben</String>
|
<String key="ShaderGamma">Gammakorrekció a shaderekben</String>
|
||||||
<String key="ScreenMipmaps">Mipmapok készítése a vezetőállás (Python) kijelzőtextúráihoz</String>
|
<String key="ScreenMipmaps">Mipmapok készítése a vezetőállás (Python) kijelzőtextúráihoz</String>
|
||||||
<String key="ExtendedModelConversion">Kiterjesztett E3D modellkonverzió (kísérleti)</String>
|
<String key="ExtendedModelConversion">Kiterjesztett E3D modellkonverzió (kísérleti)</String>
|
||||||
@@ -590,7 +578,6 @@
|
|||||||
<String key="RuleNew">— új szabály —</String>
|
<String key="RuleNew">— új szabály —</String>
|
||||||
<String key="RuleRemove">Eltávolítás a szabályból</String>
|
<String key="RuleRemove">Eltávolítás a szabályból</String>
|
||||||
<String key="CatAll">Összes</String>
|
<String key="CatAll">Összes</String>
|
||||||
<String key="GfxColResolution">Felbontás és textúrák</String>
|
|
||||||
<String key="GfxColRendering">Megjelenítés</String>
|
<String key="GfxColRendering">Megjelenítés</String>
|
||||||
<String key="GfxColShadows">Árnyékok</String>
|
<String key="GfxColShadows">Árnyékok</String>
|
||||||
<String key="GfxColReflections">Tükröződés és nézet</String>
|
<String key="GfxColReflections">Tükröződés és nézet</String>
|
||||||
|
|||||||
@@ -371,24 +371,15 @@
|
|||||||
|
|
||||||
<String key="Graphic">Grafika</String>
|
<String key="Graphic">Grafika</String>
|
||||||
<String key="RenderEngine">Silnik renderowania</String>
|
<String key="RenderEngine">Silnik renderowania</String>
|
||||||
<String key="RenderEngineDesc">Wybór ścieżki renderowania OpenGL. 'Uproszczony' i 'Stary' to starszy renderer.</String>
|
<String key="RenderEngineDesc">OpenGL 4.6 działa wszędzie. Vulkan 1.4 daje DLSS, generowanie klatek, Reflex i ray tracing; gdy nie może wystartować na tym komputerze, symulator sam wraca do OpenGL.</String>
|
||||||
<String key="REFull">Pełny</String>
|
|
||||||
<String key="REOld">Stary</String>
|
|
||||||
<String key="RESimpShader">Uproszczony (legacy)</String>
|
|
||||||
<String key="RESimp">Uproszczony</String>
|
|
||||||
<String key="REOff">Wyłącz warstwę wizualną</String>
|
|
||||||
<String key="REExperimental">Eksperymentalny</String>
|
|
||||||
<String key="REExperimentalWarning">Uwaga: renderer eksperymentalny jest w trakcie rozwoju. Może działać niestabilnie, nie pokazywać części obiektów albo nie uruchomić się na niektórych kartach graficznych. Gdy symulator nie startuje lub wygląda źle, wróć do renderera „Pełny”.</String>
|
|
||||||
|
|
||||||
<String key="Resolution">Rozdzielczość</String>
|
<String key="Resolution">Rozdzielczość</String>
|
||||||
<String key="BufforResolution">Rozdzielczość bufora</String>
|
<String key="BufforResolution">Skala renderowania</String>
|
||||||
<String key="BufforResolutionDesc">Skaluje wewnętrzny bufor renderowania względem rozdzielczości okna.</String>
|
<String key="BufforResolutionDesc">Wielkość obrazu sceny względem okna. Z DLSS to rozdzielczość, z której DLSS skaluje (ok. 67% – jakość, 50% – wydajność); DLAA zawsze rysuje w pełnej rozdzielczości.</String>
|
||||||
<String key="MaxTexResolution">Maksymalna rozdzielczość tekstur</String>
|
<String key="MaxTexResolution">Maksymalna rozdzielczość tekstur</String>
|
||||||
<String key="MaxTexCabResolution">Maksymalna rozdzielczość tekstur kabiny</String>
|
<String key="MaxTexCabResolution">Maksymalna rozdzielczość tekstur kabiny</String>
|
||||||
<String key="TexFilteringQuality">Jakość filtrowania tekstur</String>
|
<String key="TexFilteringQuality">Jakość filtrowania tekstur</String>
|
||||||
<String key="TexFilteringQualityDesc">Poziom anizotropowego filtrowania tekstur.</String>
|
<String key="TexFilteringQualityDesc">Poziom anizotropowego filtrowania tekstur.</String>
|
||||||
<String key="Multisampling">Multisampling</String>
|
|
||||||
<String key="MultisamplingDesc">Wygładzanie krawędzi obiektów.</String>
|
|
||||||
<String key="QualityVeryLow">Bardzo niska</String>
|
<String key="QualityVeryLow">Bardzo niska</String>
|
||||||
<String key="QualityLow">Niska</String>
|
<String key="QualityLow">Niska</String>
|
||||||
<String key="QualityNormal">Normalna</String>
|
<String key="QualityNormal">Normalna</String>
|
||||||
@@ -406,7 +397,7 @@
|
|||||||
<String key="RangeVeryHigh">Bardzo wysoki</String>
|
<String key="RangeVeryHigh">Bardzo wysoki</String>
|
||||||
<String key="RangeDisabled">Wyłączone</String>
|
<String key="RangeDisabled">Wyłączone</String>
|
||||||
<String key="DynamicLights">Dynamiczne źródła światła</String>
|
<String key="DynamicLights">Dynamiczne źródła światła</String>
|
||||||
<String key="DynamicLightsDesc">Maksymalna liczba jednoczesnych źródeł światła dynamicznego.</String>
|
<String key="DynamicLightsDesc">Ile reflektorów pojazdów świeci naraz. Używane tylko bez oświetlenia klastrowego.</String>
|
||||||
<String key="RenderRange">Zasięg renderowania</String>
|
<String key="RenderRange">Zasięg renderowania</String>
|
||||||
<String key="RenderRangeDesc">Maksymalny mnożnik zasięgu rysowania; silnik zmniejsza go automatycznie przy niskim FPS.</String>
|
<String key="RenderRangeDesc">Maksymalny mnożnik zasięgu rysowania; silnik zmniejsza go automatycznie przy niskim FPS.</String>
|
||||||
<String key="FpsLimitEnable">Ogranicz liczbę klatek na sekundę</String>
|
<String key="FpsLimitEnable">Ogranicz liczbę klatek na sekundę</String>
|
||||||
@@ -415,8 +406,6 @@
|
|||||||
<String key="ShadowLimitNone">Bez ograniczeń</String>
|
<String key="ShadowLimitNone">Bez ograniczeń</String>
|
||||||
<String key="ShadowLimitShort">Skrócone</String>
|
<String key="ShadowLimitShort">Skrócone</String>
|
||||||
<String key="FullscreenWindowed">Automatyczna rozdzielczość (pełny ekran bez obramowania)</String>
|
<String key="FullscreenWindowed">Automatyczna rozdzielczość (pełny ekran bez obramowania)</String>
|
||||||
<String key="RenderAngleVulkan">Użyj renderera ANGLE Vulkan</String>
|
|
||||||
<String key="RenderAngleVulkanDesc">Uruchamia renderer ANGLE na Vulkanie zamiast domyślnego backendu. Przydatne, gdy OpenGL sprawia problemy.</String>
|
|
||||||
<String key="VSync">VSync</String>
|
<String key="VSync">VSync</String>
|
||||||
<String key="VSyncDesc">Synchronizacja klatek z odświeżaniem monitora.</String>
|
<String key="VSyncDesc">Synchronizacja klatek z odświeżaniem monitora.</String>
|
||||||
<String key="SmokeDisplay">Wyświetlanie dymu</String>
|
<String key="SmokeDisplay">Wyświetlanie dymu</String>
|
||||||
@@ -427,16 +416,12 @@
|
|||||||
<String key="AdditionalShadersEffects">Dodatkowe efekty shaderów</String>
|
<String key="AdditionalShadersEffects">Dodatkowe efekty shaderów</String>
|
||||||
<String key="ReflectionsCubeMap">Odbicia jako cubemapa</String>
|
<String key="ReflectionsCubeMap">Odbicia jako cubemapa</String>
|
||||||
<String key="ReflectionsCubeMapDesc">Renderuje odbicia do mapy sześciennej, dzięki czemu powierzchnie odbijają otoczenie ze wszystkich stron.</String>
|
<String key="ReflectionsCubeMapDesc">Renderuje odbicia do mapy sześciennej, dzięki czemu powierzchnie odbijają otoczenie ze wszystkich stron.</String>
|
||||||
<String key="SkipPipeline">Uproszczony odczyt głębi (zgodność)</String>
|
<String key="SkipPipeline">Pomiń potok postprocessingu</String>
|
||||||
<String key="SkipPipelineDesc">Alternatywna ścieżka odczytu bufora głębi przy MSAA; włącz przy problemach z kompatybilnością karty graficznej.</String>
|
<String key="SkipPipelineDesc">Rysuje scenę prosto na ekran, bez TAA/DLSS, ekspozycji, bloomu i rozmycia. Tylko przy problemach z kartą graficzną.</String>
|
||||||
<String key="RenderVBO">Renderowanie VBO</String>
|
|
||||||
<String key="RenderVBODesc">Trzyma geometrię w buforach karty graficznej. Wyłącz tylko przy problemach ze starszymi kartami.</String>
|
|
||||||
<String key="RenderShadows">Renderowanie cieni</String>
|
<String key="RenderShadows">Renderowanie cieni</String>
|
||||||
<String key="ReflectionsFramerate">Odświeżanie odbić</String>
|
<String key="ReflectionsFramerate">Odświeżanie odbić</String>
|
||||||
<String key="ShadowsResolution">Rozdzielczość cieni</String>
|
<String key="ShadowsResolution">Rozdzielczość cieni</String>
|
||||||
<String key="ShaderRange">Zasięg cieni</String>
|
<String key="ShaderRange">Zasięg cieni</String>
|
||||||
<String key="CabShadowsRange">Zasięg źródeł cieni w kabinie</String>
|
|
||||||
<String key="CabShadowsRangeDesc">Odległość, z jakiej źródła światła nadal rzucają cień w kabinie. Zero wyłącza cienie w kabinie.</String>
|
|
||||||
|
|
||||||
<String key="ShadowDisplay">Wyświetlanie cieni</String>
|
<String key="ShadowDisplay">Wyświetlanie cieni</String>
|
||||||
<String key="ShadowDisplayDesc">Określa, które obiekty rzucają cień według priorytetu materiału. Niższa wartość = mniej cieni, wyższa wydajność.</String>
|
<String key="ShadowDisplayDesc">Określa, które obiekty rzucają cień według priorytetu materiału. Niższa wartość = mniej cieni, wyższa wydajność.</String>
|
||||||
@@ -445,7 +430,7 @@
|
|||||||
<String key="CSRAll">Wszystkie</String>
|
<String key="CSRAll">Wszystkie</String>
|
||||||
|
|
||||||
<String key="ReflectionsDetails">Szczegółowość odbić</String>
|
<String key="ReflectionsDetails">Szczegółowość odbić</String>
|
||||||
<String key="ReflectionsDetailsDesc">Jakie obiekty są renderowane w odbiciach cubemap.</String>
|
<String key="ReflectionsDetailsDesc">Co jest widoczne w odbiciach mapy otoczenia i ray tracingu.</String>
|
||||||
<String key="RDTerrain">Tylko geometria terenu</String>
|
<String key="RDTerrain">Tylko geometria terenu</String>
|
||||||
<String key="RDTerrainModels">Geometria terenu i modele statyczne</String>
|
<String key="RDTerrainModels">Geometria terenu i modele statyczne</String>
|
||||||
<String key="RDTerrainModelsVehicles">Geometria terenu, modele statyczne i pojazdy</String>
|
<String key="RDTerrainModelsVehicles">Geometria terenu, modele statyczne i pojazdy</String>
|
||||||
@@ -493,7 +478,6 @@
|
|||||||
<String key="Advanced">Zaawansowane</String>
|
<String key="Advanced">Zaawansowane</String>
|
||||||
<String key="CompressTextures">Kompresuj tekstury TGA</String>
|
<String key="CompressTextures">Kompresuj tekstury TGA</String>
|
||||||
<String key="ScaleSpeculars">Skaluj odbicia specularne (kompatybilność ze starymi modelami)</String>
|
<String key="ScaleSpeculars">Skaluj odbicia specularne (kompatybilność ze starymi modelami)</String>
|
||||||
<String key="UseGLES">Używaj OpenGL ES</String>
|
|
||||||
<String key="ShaderGamma">Korekcja gamma w shaderach</String>
|
<String key="ShaderGamma">Korekcja gamma w shaderach</String>
|
||||||
<String key="ScreenMipmaps">Generuj mipmapy dla tekstur ekranów kabinowych (Python)</String>
|
<String key="ScreenMipmaps">Generuj mipmapy dla tekstur ekranów kabinowych (Python)</String>
|
||||||
<String key="ExtendedModelConversion">Rozszerzona konwersja modeli E3D (eksperymentalne)</String>
|
<String key="ExtendedModelConversion">Rozszerzona konwersja modeli E3D (eksperymentalne)</String>
|
||||||
@@ -626,10 +610,9 @@
|
|||||||
<String key="RuleNew">— nowa reguła —</String>
|
<String key="RuleNew">— nowa reguła —</String>
|
||||||
<String key="RuleRemove">Usuń z reguły</String>
|
<String key="RuleRemove">Usuń z reguły</String>
|
||||||
<String key="CatAll">Wszystkie</String>
|
<String key="CatAll">Wszystkie</String>
|
||||||
<String key="GfxColResolution">Rozdzielczość i tekstury</String>
|
|
||||||
<String key="GfxColRendering">Renderowanie</String>
|
<String key="GfxColRendering">Renderowanie</String>
|
||||||
<String key="GfxColShadows">Cienie</String>
|
<String key="GfxColShadows">Cienie</String>
|
||||||
<String key="GfxColReflections">Odbicia i widok</String>
|
<String key="GfxColReflections">Odbicia</String>
|
||||||
<String key="GfxColScripts">Skrypty Python</String>
|
<String key="GfxColScripts">Skrypty Python</String>
|
||||||
<String key="UartHint">Nazwa portu / nie zmieniać / częstotliwość wysyłania danych</String>
|
<String key="UartHint">Nazwa portu / nie zmieniać / częstotliwość wysyłania danych</String>
|
||||||
<String key="UartFeature">UARTfeature:</String>
|
<String key="UartFeature">UARTfeature:</String>
|
||||||
@@ -671,4 +654,103 @@
|
|||||||
<String key="DevLocation">Katalog kopii</String>
|
<String key="DevLocation">Katalog kopii</String>
|
||||||
<String key="DevRebuild">Odbuduj kopię</String>
|
<String key="DevRebuild">Odbuduj kopię</String>
|
||||||
<String key="DevRebuilt">Odbudowano</String>
|
<String key="DevRebuilt">Odbudowano</String>
|
||||||
|
<!-- Grafika: renderer, wygładzanie, efekty, presety, import i eksport eu07.ini -->
|
||||||
|
<String key="Effects">Efekty</String>
|
||||||
|
<String key="GfxColQuality">Jakość i renderer</String>
|
||||||
|
<String key="GfxColImage">Rozdzielczość i wygładzanie</String>
|
||||||
|
<String key="GfxColTextures">Tekstury i geometria</String>
|
||||||
|
<String key="GfxColLights">Oświetlenie</String>
|
||||||
|
<String key="GfxColAtmosphere">Atmosfera i pogoda</String>
|
||||||
|
<String key="GfxColPostFx">Postprocessing</String>
|
||||||
|
<String key="GfxColNature">Roślinność i cząsteczki</String>
|
||||||
|
<String key="QualityPreset">Preset jakości</String>
|
||||||
|
<String key="QualityPresetDesc">Ustawia naraz jakość grafiki i efektów. Rozdzielczość, skala renderowania, VSync, pole widzenia, rozmycie ruchu, aberracja chromatyczna i DLSS zostają bez zmian. Po ręcznej zmianie preset pokazuje „Własne”.</String>
|
||||||
|
<String key="PresetLowest">Najniższe</String>
|
||||||
|
<String key="PresetLow">Niskie</String>
|
||||||
|
<String key="PresetMedium">Średnie</String>
|
||||||
|
<String key="PresetHigh">Wysokie</String>
|
||||||
|
<String key="PresetUltra">Ultra</String>
|
||||||
|
<String key="PresetCustom">Własne</String>
|
||||||
|
<String key="REOpenGL">OpenGL 4.6</String>
|
||||||
|
<String key="REVulkan">Vulkan 1.4</String>
|
||||||
|
<String key="REVulkanNote"></String>
|
||||||
|
<String key="REOpenGLNote">DLSS, generowanie klatek, Reflex i ray tracing są dostępne tylko z rendererem Vulkan.</String>
|
||||||
|
<String key="VulkanDevice">Karta graficzna (Vulkan)</String>
|
||||||
|
<String key="VulkanDeviceDesc">Numer karty z listy w logu albo fragment jej nazwy, np. „RTX”. Puste: wybór automatyczny.</String>
|
||||||
|
<String key="VulkanDeviceAuto">automatycznie</String>
|
||||||
|
<String key="AntiAliasing">Wygładzanie krawędzi</String>
|
||||||
|
<String key="AntiAliasingDesc">MSAA wygładza krawędzie obiektów, TAA cały obraz kosztem lekkiego rozmycia. DLSS i DLAA tylko z Vulkanem na kartach NVIDIA RTX – w innym wypadku symulator użyje TAA.</String>
|
||||||
|
<String key="AaTaa">TAA</String>
|
||||||
|
<String key="AaDlss">DLSS (skalowanie)</String>
|
||||||
|
<String key="AaDlaa">DLAA (natywna rozdzielczość)</String>
|
||||||
|
<String key="DlssPreset">Preset DLSS</String>
|
||||||
|
<String key="DlssPresetDesc">Model sieci, którym DLSS odtwarza obraz. Tryb DLSS wynika ze skali renderowania: ok. 67% Jakość, 58% Zrównoważony, 50% Wydajność, 33% Ultra wydajność.</String>
|
||||||
|
<String key="DlssPresetDefault">Automatyczny (wybiera sterownik)</String>
|
||||||
|
<String key="DlssPresetK">K – najlepsza jakość obrazu</String>
|
||||||
|
<String key="DlssPresetJ">J – mniej smużenia, więcej migotania</String>
|
||||||
|
<String key="DlssPresetM">M – pod tryb Wydajność (ok. 50%)</String>
|
||||||
|
<String key="DlssPresetL">L – pod tryb Ultra wydajność (ok. 33%)</String>
|
||||||
|
<String key="DlssPresetInfoDefault">K dla DLAA, Jakości i Zrównoważonego, M dla Wydajności, L dla Ultra wydajności. Sterownik może to zmienić przy aktualizacji.</String>
|
||||||
|
<String key="DlssPresetInfoK">Model transformer o najlepszej jakości obrazu, ale najdroższy w obliczeniach. Domyślny dla DLAA, Jakości i Zrównoważonego.</String>
|
||||||
|
<String key="DlssPresetInfoJ">Podobny do K: trochę mniej smug za ruchomymi obiektami kosztem większego migotania. NVIDIA zaleca raczej K.</String>
|
||||||
|
<String key="DlssPresetInfoM">Model dobrany do trybu Wydajność (skala ok. 50%), w nim domyślny. Sam liczy ekspozycję obrazu.</String>
|
||||||
|
<String key="DlssPresetInfoL">Model dobrany do trybu Ultra wydajność (skala ok. 33%), w nim domyślny. Sam liczy ekspozycję obrazu.</String>
|
||||||
|
<String key="FrameGeneration">Generowanie klatek</String>
|
||||||
|
<String key="FrameGenerationDesc">Dodatkowe klatki wyświetlane między rysowanymi (DLSS Frame Generation). x3 i x4 tylko na kartach RTX 50, słabsze dostaną x2.</String>
|
||||||
|
<String key="FrameGenerationNeedsDlssNote">Generowanie klatek działa tylko z DLSS albo DLAA.</String>
|
||||||
|
<String key="Reflex">NVIDIA Reflex</String>
|
||||||
|
<String key="ReflexDesc">Zmniejsza opóźnienie między sterowaniem a obrazem. Tylko Vulkan.</String>
|
||||||
|
<String key="ReflexOn">Włączony</String>
|
||||||
|
<String key="ReflexBoost">Włączony + boost</String>
|
||||||
|
<String key="ReflexForcedNote">Generowanie klatek włącza Reflex samo, niezależnie od tego wyboru.</String>
|
||||||
|
<String key="DlssMissingLibraryNote">Nie ma {0} obok symulatora – bez tej biblioteki symulator nie użyje tej funkcji DLSS.</String>
|
||||||
|
<String key="DlssNoPlatformNote">Na macOS DLSS nie jest dostępny.</String>
|
||||||
|
<String key="TemporalNeedsPipelineNote">TAA i DLSS działają w postprocessingu – przy pominiętym potoku postprocessingu krawędzie nie będą wygładzane.</String>
|
||||||
|
<String key="VulkanOnlyNote">Dostępne tylko z rendererem Vulkan.</String>
|
||||||
|
<String key="ShadowSdsm">Kaskady cieni dopasowane do sceny (SDSM)</String>
|
||||||
|
<String key="ShadowSdsmDesc">Rozkłada rozdzielczość cieni słońca na to, co faktycznie widać, zamiast stałych odległości.</String>
|
||||||
|
<String key="LightsClustered">Oświetlenie klastrowe</String>
|
||||||
|
<String key="LightsClusteredDesc">Światła pojazdów i latarnie bez limitu liczby. Potrzebne dla świateł punktowych scenerii i lampy w kabinie.</String>
|
||||||
|
<String key="LightShadows">Cienie lamp i reflektorów</String>
|
||||||
|
<String key="LightShadowsDesc">Cienie rzucane przez lampę kabiny, latarnie i reflektory pojazdów.</String>
|
||||||
|
<String key="ContactShadows">Cienie kontaktowe</String>
|
||||||
|
<String key="ContactShadowsDesc">Drobne cienie w miejscach styku obiektów, których mapa cieni nie łapie.</String>
|
||||||
|
<String key="AmbientOcclusion">Okluzja otoczenia</String>
|
||||||
|
<String key="AmbientOcclusionDesc">Przyciemnia zakamarki i styki powierzchni. GTAO jest dokładniejsze od starszego SSAO.</String>
|
||||||
|
<String key="AmbientOcclusionQuality">Jakość okluzji</String>
|
||||||
|
<String key="Ssr">Odbicia w przestrzeni ekranu (SSR)</String>
|
||||||
|
<String key="SsrDesc">Odbicia tego, co widać na ekranie, na mokrych i gładkich powierzchniach.</String>
|
||||||
|
<String key="RayTracing">Odbicia ray tracing</String>
|
||||||
|
<String key="RayTracingDesc">Uzupełnia odbicia tam, gdzie SSR nic nie znajduje. Tylko Vulkan i karta z ray tracingiem (ray query).</String>
|
||||||
|
<String key="RayTracingRange">Zasięg ray tracingu</String>
|
||||||
|
<String key="VolumetricFog">Mgła wolumetryczna</String>
|
||||||
|
<String key="VolumetricFogDesc">Mgła z promieniami słońca, cieniami chmur i światłem lamp. Wyłączona: prostsza mgła analityczna.</String>
|
||||||
|
<String key="FogQuality">Jakość mgły</String>
|
||||||
|
<String key="Clouds">Chmury wolumetryczne</String>
|
||||||
|
<String key="CloudsDesc">Jakość chmur rysowanych na niebie.</String>
|
||||||
|
<String key="CloudShadows">Cienie chmur na ziemi</String>
|
||||||
|
<String key="Bloom">Poświata jasnych miejsc (bloom)</String>
|
||||||
|
<String key="AutoExposure">Automatyczna ekspozycja</String>
|
||||||
|
<String key="AutoExposureDesc">Jasność obrazu dopasowuje się do sceny, np. przy wjeździe do tunelu.</String>
|
||||||
|
<String key="Grass">Trawa</String>
|
||||||
|
<String key="GrassDistance">Zasięg trawy</String>
|
||||||
|
<String key="GrassDensity">Gęstość trawy</String>
|
||||||
|
<String key="Precipitation">Opady (cząsteczki)</String>
|
||||||
|
<String key="PrecipitationDesc">Liczba kropli deszczu i płatków śniegu.</String>
|
||||||
|
<String key="LevelOff">Wyłączone</String>
|
||||||
|
<String key="LevelLow">Niskie</String>
|
||||||
|
<String key="LevelMedium">Średnie</String>
|
||||||
|
<String key="LevelHigh">Wysokie</String>
|
||||||
|
<String key="LevelUltra">Ultra</String>
|
||||||
|
<String key="SettingsFile">Plik eu07.ini</String>
|
||||||
|
<String key="ImportIni">Importuj…</String>
|
||||||
|
<String key="ImportIniTitle">Importuj ustawienia z eu07.ini</String>
|
||||||
|
<String key="ImportIniFailed">Nie udało się odczytać pliku:
|
||||||
|
{0}</String>
|
||||||
|
<String key="ImportIniDone">Zaimportowano {0} – zapisz, aby zachować</String>
|
||||||
|
<String key="ExportIni">Eksportuj…</String>
|
||||||
|
<String key="ExportIniTitle">Eksportuj ustawienia do eu07.ini</String>
|
||||||
|
<String key="ExportIniFailed">Nie udało się zapisać pliku:
|
||||||
|
{0}</String>
|
||||||
|
<String key="ExportIniDone">Wyeksportowano do {0}</String>
|
||||||
</Language>
|
</Language>
|
||||||
|
|||||||
@@ -364,20 +364,12 @@
|
|||||||
|
|
||||||
<String key="Graphic">Графика</String>
|
<String key="Graphic">Графика</String>
|
||||||
<String key="RenderEngine">Движок отрисовки</String>
|
<String key="RenderEngine">Движок отрисовки</String>
|
||||||
<String key="REFull">Полный</String>
|
|
||||||
<String key="REOld">Старый</String>
|
|
||||||
<String key="RESimpShader">Упрощённый шейдер</String>
|
|
||||||
<String key="RESimp">Упрощённый</String>
|
|
||||||
<String key="REOff">Отключить визуальный слой</String>
|
|
||||||
<String key="REExperimental">Экспериментальный</String>
|
|
||||||
<String key="REExperimentalWarning">Внимание: экспериментальный рендерер находится в разработке. Он может работать нестабильно, не показывать части сцены или не запускаться на некоторых видеокартах. Если симулятор не запускается или выглядит неправильно, вернитесь к рендереру «Полный».</String>
|
|
||||||
|
|
||||||
<String key="Resolution">Разрешение</String>
|
<String key="Resolution">Разрешение</String>
|
||||||
<String key="BufforResolution">Разрешение буфера</String>
|
<String key="BufforResolution">Разрешение буфера</String>
|
||||||
<String key="MaxTexResolution">Максимальное разрешение текстур</String>
|
<String key="MaxTexResolution">Максимальное разрешение текстур</String>
|
||||||
<String key="MaxTexCabResolution">Максимальное разрешение текстур кабины</String>
|
<String key="MaxTexCabResolution">Максимальное разрешение текстур кабины</String>
|
||||||
<String key="TexFilteringQuality">Качество фильтрации текстур</String>
|
<String key="TexFilteringQuality">Качество фильтрации текстур</String>
|
||||||
<String key="Multisampling">Multisampling</String>
|
|
||||||
<String key="QualityVeryLow">Очень низкое</String>
|
<String key="QualityVeryLow">Очень низкое</String>
|
||||||
<String key="QualityLow">Низкое</String>
|
<String key="QualityLow">Низкое</String>
|
||||||
<String key="QualityNormal">Нормальное</String>
|
<String key="QualityNormal">Нормальное</String>
|
||||||
@@ -401,7 +393,6 @@
|
|||||||
<String key="ShadowLimitNone">Без ограничений</String>
|
<String key="ShadowLimitNone">Без ограничений</String>
|
||||||
<String key="ShadowLimitShort">Укороченные</String>
|
<String key="ShadowLimitShort">Укороченные</String>
|
||||||
<String key="FullscreenWindowed">Автоматическое разрешение (полный экран без рамки)</String>
|
<String key="FullscreenWindowed">Автоматическое разрешение (полный экран без рамки)</String>
|
||||||
<String key="RenderAngleVulkan">Использовать рендерер ANGLE Vulkan</String>
|
|
||||||
<String key="VSync">VSync</String>
|
<String key="VSync">VSync</String>
|
||||||
<String key="SmokeDisplay">Отображение дыма</String>
|
<String key="SmokeDisplay">Отображение дыма</String>
|
||||||
<String key="SmokeParticlesMultiplier">Множитель частиц дыма</String>
|
<String key="SmokeParticlesMultiplier">Множитель частиц дыма</String>
|
||||||
@@ -411,12 +402,10 @@
|
|||||||
<String key="AdditionalShadersEffects">Дополнительные эффекты шейдеров</String>
|
<String key="AdditionalShadersEffects">Дополнительные эффекты шейдеров</String>
|
||||||
<String key="ReflectionsCubeMap">Отражения как кубическая карта</String>
|
<String key="ReflectionsCubeMap">Отражения как кубическая карта</String>
|
||||||
<String key="SkipPipeline">SkipPipeline</String>
|
<String key="SkipPipeline">SkipPipeline</String>
|
||||||
<String key="RenderVBO">Отрисовка VBO</String>
|
|
||||||
<String key="RenderShadows">Отрисовывать тени</String>
|
<String key="RenderShadows">Отрисовывать тени</String>
|
||||||
<String key="ReflectionsFramerate">Частота обновления отражений</String>
|
<String key="ReflectionsFramerate">Частота обновления отражений</String>
|
||||||
<String key="ShadowsResolution">Разрешение теней</String>
|
<String key="ShadowsResolution">Разрешение теней</String>
|
||||||
<String key="ShaderRange">Дальность теней</String>
|
<String key="ShaderRange">Дальность теней</String>
|
||||||
<String key="CabShadowsRange">Дальность источников теней в кабине</String>
|
|
||||||
|
|
||||||
<String key="ShadowDisplay">Показывать тени</String>
|
<String key="ShadowDisplay">Показывать тени</String>
|
||||||
<String key="CSROnlyImportant">Только важные</String>
|
<String key="CSROnlyImportant">Только важные</String>
|
||||||
@@ -458,7 +447,6 @@
|
|||||||
<String key="Advanced">Дополнительно</String>
|
<String key="Advanced">Дополнительно</String>
|
||||||
<String key="CompressTextures">Сжимать текстуры TGA</String>
|
<String key="CompressTextures">Сжимать текстуры TGA</String>
|
||||||
<String key="ScaleSpeculars">Масштабировать блики (совместимость со старыми моделями)</String>
|
<String key="ScaleSpeculars">Масштабировать блики (совместимость со старыми моделями)</String>
|
||||||
<String key="UseGLES">Использовать OpenGL ES</String>
|
|
||||||
<String key="ShaderGamma">Гамма-коррекция в шейдерах</String>
|
<String key="ShaderGamma">Гамма-коррекция в шейдерах</String>
|
||||||
<String key="ScreenMipmaps">Создавать мипмапы для текстур экранов кабины (Python)</String>
|
<String key="ScreenMipmaps">Создавать мипмапы для текстур экранов кабины (Python)</String>
|
||||||
<String key="ExtendedModelConversion">Расширенное преобразование моделей E3D (экспериментально)</String>
|
<String key="ExtendedModelConversion">Расширенное преобразование моделей E3D (экспериментально)</String>
|
||||||
@@ -590,7 +578,6 @@
|
|||||||
<String key="RuleNew">— новое правило —</String>
|
<String key="RuleNew">— новое правило —</String>
|
||||||
<String key="RuleRemove">Удалить из правила</String>
|
<String key="RuleRemove">Удалить из правила</String>
|
||||||
<String key="CatAll">Все</String>
|
<String key="CatAll">Все</String>
|
||||||
<String key="GfxColResolution">Разрешение и текстуры</String>
|
|
||||||
<String key="GfxColRendering">Рендеринг</String>
|
<String key="GfxColRendering">Рендеринг</String>
|
||||||
<String key="GfxColShadows">Тени</String>
|
<String key="GfxColShadows">Тени</String>
|
||||||
<String key="GfxColReflections">Отражения и вид</String>
|
<String key="GfxColReflections">Отражения и вид</String>
|
||||||
|
|||||||
Reference in New Issue
Block a user