Skip to main content

modde_games/tools/
vkbasalt.rs

1//! vkBasalt — Vulkan post-processing layer.
2//!
3//! Enabled via `ENABLE_VKBASALT=1` env var. Per-game config written to
4//! `~/.local/share/modde/tools/{game_id}/vkBasalt.conf` and pointed to
5//! via `VKBASALT_CONFIG_FILE`.
6
7use smallvec::{SmallVec, smallvec};
8
9use super::{
10    GameTool, GeneratedConfig, ToolAvailability, ToolCategory, ToolConfig, tool_config_dir, which,
11};
12
13pub static VKBASALT: VkBasalt = VkBasalt;
14
15pub struct VkBasalt;
16
17impl GameTool for VkBasalt {
18    fn tool_id(&self) -> &'static str {
19        "vkbasalt"
20    }
21
22    fn display_name(&self) -> &'static str {
23        "vkBasalt"
24    }
25
26    fn category(&self) -> ToolCategory {
27        ToolCategory::PostProcess
28    }
29
30    fn description(&self) -> &'static str {
31        "Vulkan post-processing layer for CAS sharpening and shader effects."
32    }
33
34    fn settings_schema(&self) -> Vec<super::ToolSettingSpec> {
35        vec![
36            super::ToolSettingSpec::text("toggleKey", "Toggle key", "Key used to toggle vkBasalt.")
37                .section("Activation"),
38            super::ToolSettingSpec::bool(
39                "enableOnLaunch",
40                "Enable on launch",
41                "Start with vkBasalt effects enabled.",
42            )
43            .section("Activation"),
44            super::ToolSettingSpec::text(
45                "effects",
46                "Effects",
47                "Colon or comma separated effect list, such as cas or cas:fxaa.",
48            )
49            .section("Effects"),
50            super::ToolSettingSpec::number(
51                "casSharpness",
52                "CAS sharpness",
53                "Contrast Adaptive Sharpening amount.",
54                0.0,
55                1.0,
56                0.05,
57            )
58            .section("Effects"),
59            super::ToolSettingSpec::path(
60                "reshadeTexturePath",
61                "ReShade texture path",
62                "Optional ReShade texture directory for vkBasalt.",
63            )
64            .section("ReShade Paths"),
65            super::ToolSettingSpec::path(
66                "reshadeIncludePath",
67                "ReShade shader path",
68                "Optional ReShade shader include directory for vkBasalt.",
69            )
70            .section("ReShade Paths"),
71        ]
72    }
73
74    fn detect_available(&self) -> ToolAvailability {
75        #[cfg(not(target_os = "linux"))]
76        {
77            return ToolAvailability::NotInstalled {
78                install_hint: "vkBasalt is only available on Linux".into(),
79            };
80        }
81
82        // vkBasalt doesn't have a CLI binary; it's a Vulkan layer.
83        // Check for the layer JSON or the library.
84        #[cfg(target_os = "linux")]
85        {
86            let layer_paths = [
87                "/usr/share/vulkan/implicit_layer.d/vkBasalt.json",
88                "/etc/vulkan/implicit_layer.d/vkBasalt.json",
89            ];
90
91            if layer_paths.iter().any(|p| std::path::Path::new(p).exists())
92                || which("vkbasalt").is_some()
93            {
94                ToolAvailability::Available { version: None }
95            } else {
96                // Also check via nix profile paths
97                if let Ok(paths) = std::env::var("VK_LAYER_PATH") {
98                    for dir in std::env::split_paths(&std::ffi::OsString::from(&paths)) {
99                        if dir.join("vkBasalt.json").exists() {
100                            return ToolAvailability::Available { version: None };
101                        }
102                    }
103                }
104
105                ToolAvailability::NotInstalled {
106                    install_hint: "Install vkbasalt from your package manager".into(),
107                }
108            }
109        }
110    }
111
112    fn env_vars(&self, config: &ToolConfig) -> SmallVec<[(String, String); 4]> {
113        let mut vars = smallvec![("ENABLE_VKBASALT".into(), "1".into())];
114
115        if let Some(game_id) = config.get_str("_game_id") {
116            let conf_path = tool_config_dir(game_id).join("vkBasalt.conf");
117            vars.push((
118                "VKBASALT_CONFIG_FILE".into(),
119                conf_path.to_string_lossy().into(),
120            ));
121        }
122
123        vars
124    }
125
126    fn generate_config(&self, config: &ToolConfig) -> Option<GeneratedConfig> {
127        let game_id = config.get_str("_game_id")?;
128
129        let mut lines = Vec::new();
130        lines.push("# Generated by modde — do not edit manually".to_string());
131
132        // Toggle key
133        let toggle_key = config.get_str("toggleKey").unwrap_or("Home");
134        lines.push(format!("toggleKey = {toggle_key}"));
135
136        // Enable on launch
137        let enable_on_launch = config.get_bool("enableOnLaunch");
138        lines.push(format!(
139            "enableOnLaunch = {}",
140            if enable_on_launch { "True" } else { "False" }
141        ));
142
143        // Effects
144        if let Some(effects) = config.settings.get("effects").and_then(|v| v.as_array()) {
145            let effect_names: Vec<&str> = effects.iter().filter_map(|v| v.as_str()).collect();
146            if !effect_names.is_empty() {
147                lines.push(format!("effects = {}", effect_names.join(":")));
148            }
149        }
150
151        // CAS sharpness
152        if let Some(sharpness) = config.settings.get("casSharpness") {
153            lines.push(format!("casSharpness = {sharpness}"));
154        }
155
156        // Reshade shader/texture paths
157        if let Some(path) = config.get_str("reshadeTexturePath") {
158            lines.push(format!("reshadeTexturePath = {path}"));
159        }
160        if let Some(path) = config.get_str("reshadeIncludePath") {
161            lines.push(format!("reshadeIncludePath = {path}"));
162        }
163
164        let dir = tool_config_dir(game_id);
165        Some(GeneratedConfig {
166            path: dir.join("vkBasalt.conf"),
167            content: lines.join("\n") + "\n",
168        })
169    }
170
171    fn default_config(&self) -> ToolConfig {
172        let mut config = ToolConfig::new("vkbasalt");
173        config.set("toggleKey", serde_json::json!("Home"));
174        config.set("enableOnLaunch", serde_json::json!(true));
175        config.set("effects", serde_json::json!(["cas"]));
176        config.set("casSharpness", serde_json::json!(0.4));
177        config
178    }
179}