feat: wire vertical exaggeration through the shell #13
+50
-23
@@ -205,6 +205,13 @@ impl OpenVistaProApp {
|
||||
|
||||
ui.separator();
|
||||
ui.label("Hydrology");
|
||||
ui.horizontal(|ui| {
|
||||
if ui.button("Reset hydrology").clicked() {
|
||||
self.data.apply(AppAction::ResetHydrology);
|
||||
changed = true;
|
||||
}
|
||||
ui.label("Lake and river overlays are clean-room defaults");
|
||||
});
|
||||
let mut river_level = self.data.scene.hydrology.river_level;
|
||||
let mut lake_level = self.data.scene.hydrology.lake_level;
|
||||
let mut drainage = self.data.scene.hydrology.drainage;
|
||||
@@ -217,39 +224,59 @@ impl OpenVistaProApp {
|
||||
changed |= ui
|
||||
.add(egui::Slider::new(&mut drainage, 0.0..=5.0).text("Drainage"))
|
||||
.changed();
|
||||
ui.label("Lake placement");
|
||||
let mut lake_center_x = self.data.scene.hydrology.lake_center_x;
|
||||
let mut lake_center_z = self.data.scene.hydrology.lake_center_z;
|
||||
let mut lake_radius = self.data.scene.hydrology.lake_radius;
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Center X/Z");
|
||||
changed |= ui
|
||||
.add(
|
||||
egui::DragValue::new(&mut lake_center_x)
|
||||
.speed(0.01)
|
||||
.range(0.0..=1.0),
|
||||
)
|
||||
.changed();
|
||||
changed |= ui
|
||||
.add(
|
||||
egui::DragValue::new(&mut lake_center_z)
|
||||
.speed(0.01)
|
||||
.range(0.0..=1.0),
|
||||
)
|
||||
.changed();
|
||||
});
|
||||
changed |= ui
|
||||
.add(egui::Slider::new(&mut lake_radius, 0.0..=0.5).text("Radius"))
|
||||
.changed();
|
||||
ui.label("River placement");
|
||||
let mut river_center_x = self.data.scene.hydrology.river_center_x;
|
||||
let mut river_width = self.data.scene.hydrology.river_width;
|
||||
let mut river_bend = self.data.scene.hydrology.river_bend;
|
||||
changed |= ui
|
||||
.add(egui::Slider::new(&mut river_center_x, 0.0..=1.0).text("Center X"))
|
||||
.changed();
|
||||
changed |= ui
|
||||
.add(egui::Slider::new(&mut river_width, 0.0..=0.25).text("Width"))
|
||||
.changed();
|
||||
changed |= ui
|
||||
.add(egui::Slider::new(&mut river_bend, 0.0..=0.35).text("Bend"))
|
||||
.changed();
|
||||
self.data.apply(AppAction::SetHydrology {
|
||||
river_level,
|
||||
lake_level,
|
||||
drainage,
|
||||
lake_center_x,
|
||||
lake_center_z,
|
||||
lake_radius,
|
||||
river_center_x,
|
||||
river_width,
|
||||
river_bend,
|
||||
});
|
||||
|
||||
ui.separator();
|
||||
ui.label("Color map");
|
||||
ui.label("Core elevation bands");
|
||||
let mut palette = self.data.scene.palette;
|
||||
changed |= ui
|
||||
.add(egui::Slider::new(&mut palette.water_level, -5.0..=15.0).text("Water level"))
|
||||
.changed();
|
||||
changed |= ui
|
||||
.add(egui::Slider::new(&mut palette.tree_line, -5.0..=15.0).text("Tree line"))
|
||||
.changed();
|
||||
changed |= ui
|
||||
.add(egui::Slider::new(&mut palette.snow_line, -5.0..=15.0).text("Snow line"))
|
||||
.changed();
|
||||
if palette.tree_line < palette.water_level + 0.1 {
|
||||
palette.tree_line = palette.water_level + 0.1;
|
||||
changed = true;
|
||||
}
|
||||
if palette.snow_line < palette.tree_line + 0.1 {
|
||||
palette.snow_line = palette.tree_line + 0.1;
|
||||
changed = true;
|
||||
}
|
||||
if palette.water_level > palette.tree_line - 0.1 {
|
||||
palette.water_level = palette.tree_line - 0.1;
|
||||
changed = true;
|
||||
}
|
||||
ui.separator();
|
||||
ui.label("Band colors");
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Water");
|
||||
changed |= ui.color_edit_button_srgb(&mut palette.water).changed();
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ use image::RgbImage;
|
||||
|
||||
use crate::path::{CameraPath, build_demo_path};
|
||||
use crate::render::{
|
||||
render_perspective_with_quality, render_top_down_with_quality, RenderQualityPreset,
|
||||
RenderQualityPreset, render_perspective_with_quality, render_top_down_with_quality,
|
||||
};
|
||||
use crate::scene::{Scene, Vec3};
|
||||
use crate::scene_file::{self, SceneFileError};
|
||||
|
||||
+20
-1
@@ -3,7 +3,9 @@ use std::path::PathBuf;
|
||||
use clap::{Args, Parser, Subcommand, ValueEnum};
|
||||
use image::ImageError;
|
||||
|
||||
use crate::render::{demo_camera_for, render_perspective_to_path, render_top_down_to_path};
|
||||
use crate::render::{
|
||||
RenderQualityPreset, demo_camera_for, render_perspective_to_path, render_top_down_to_path,
|
||||
};
|
||||
use crate::scene::Scene;
|
||||
use crate::scene_file::{self, SceneFileError};
|
||||
use crate::script_exec::{self, ScriptError};
|
||||
@@ -55,6 +57,9 @@ pub struct RenderArgs {
|
||||
/// the top-down preview.
|
||||
#[arg(long, default_value_t = false)]
|
||||
pub camera_demo: bool,
|
||||
/// Render-quality preset for the CPU spike.
|
||||
#[arg(long, value_enum, default_value_t = RenderQualityPreset::Preview)]
|
||||
pub quality: RenderQualityPreset,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Args)]
|
||||
@@ -146,10 +151,23 @@ impl From<ScriptError> for CliError {
|
||||
}
|
||||
}
|
||||
|
||||
impl Preset {
|
||||
pub fn slug(self) -> &'static str {
|
||||
match self {
|
||||
Preset::Plane => "plane",
|
||||
Preset::Hill => "hill",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn supported_presets() -> &'static [&'static str] {
|
||||
&["plane", "hill"]
|
||||
}
|
||||
|
||||
pub fn supported_quality_presets() -> &'static [&'static str] {
|
||||
&["preview", "balanced", "final"]
|
||||
}
|
||||
|
||||
pub fn supported_importers() -> &'static [&'static str] {
|
||||
#[cfg(all(
|
||||
feature = "hgt",
|
||||
@@ -223,6 +241,7 @@ pub fn info_text() -> String {
|
||||
let mut text = String::new();
|
||||
writeln!(&mut text, "openvistapro {}", env!("CARGO_PKG_VERSION")).unwrap();
|
||||
writeln!(&mut text, "presets: {}", supported_presets().join(", ")).unwrap();
|
||||
writeln!(&mut text, "quality: {}", supported_quality_presets().join(", ")).unwrap();
|
||||
let importers = supported_importers();
|
||||
if importers.is_empty() {
|
||||
writeln!(&mut text, "importers: (none)").unwrap();
|
||||
|
||||
+6
-8
@@ -184,7 +184,11 @@ fn hydrology_overlay_color(scene: &Scene, nx: f32, nz: f32) -> Option<[u8; 3]> {
|
||||
};
|
||||
let colored = mix_color(scene.palette.water, tint, coverage);
|
||||
Some(if coverage > 0.72 {
|
||||
mix_color(colored, [245, 250, 255], (coverage - 0.72).clamp(0.0, 0.28) * 3.0)
|
||||
mix_color(
|
||||
colored,
|
||||
[245, 250, 255],
|
||||
(coverage - 0.72).clamp(0.0, 0.28) * 3.0,
|
||||
)
|
||||
} else {
|
||||
colored
|
||||
})
|
||||
@@ -321,13 +325,7 @@ pub fn demo_camera_for(grid: &HeightGrid) -> Camera {
|
||||
/// Coordinate convention: world X and Z map onto the grid's `(x, y)` indices,
|
||||
/// world Y is elevation, up = +Y.
|
||||
pub fn render_perspective(grid: &HeightGrid, scene: &Scene, width: u32, height: u32) -> RgbImage {
|
||||
render_perspective_with_quality(
|
||||
grid,
|
||||
scene,
|
||||
width,
|
||||
height,
|
||||
RenderQualityPreset::Preview,
|
||||
)
|
||||
render_perspective_with_quality(grid, scene, width, height, RenderQualityPreset::Preview)
|
||||
}
|
||||
|
||||
pub fn render_perspective_with_quality(
|
||||
|
||||
+16
-2
@@ -88,7 +88,11 @@ impl From<toml::de::Error> for SceneFileError {
|
||||
|
||||
/// Serialize `scene` into a TOML string with schema and version headers.
|
||||
pub fn to_toml_string(scene: &Scene) -> Result<String, SceneFileError> {
|
||||
let file = SceneFile::new(*scene);
|
||||
let mut scene = *scene;
|
||||
scene
|
||||
.palette
|
||||
.sync_thresholds_from_scene(scene.water_level, scene.tree_line, scene.snow_line);
|
||||
let file = SceneFile::new(scene);
|
||||
Ok(toml::to_string_pretty(&file)?)
|
||||
}
|
||||
|
||||
@@ -101,7 +105,11 @@ pub fn from_toml_str(text: &str) -> Result<Scene, SceneFileError> {
|
||||
if file.version != SCENE_VERSION {
|
||||
return Err(SceneFileError::UnsupportedVersion(file.version));
|
||||
}
|
||||
Ok(file.scene)
|
||||
let mut scene = file.scene;
|
||||
scene
|
||||
.palette
|
||||
.sync_thresholds_from_scene(scene.water_level, scene.tree_line, scene.snow_line);
|
||||
Ok(scene)
|
||||
}
|
||||
|
||||
/// Write `scene` to `path` as an OpenVistaPro `.ovp.toml` scene file.
|
||||
@@ -150,6 +158,12 @@ mod tests {
|
||||
river_level: 0.8,
|
||||
lake_level: 1.1,
|
||||
drainage: 0.2,
|
||||
lake_center_x: 0.42,
|
||||
lake_center_z: 0.58,
|
||||
lake_radius: 0.11,
|
||||
river_center_x: 0.6,
|
||||
river_width: 0.09,
|
||||
river_bend: 0.04,
|
||||
},
|
||||
palette: Palette {
|
||||
water_level: 0.5,
|
||||
|
||||
Reference in New Issue
Block a user