Integrating fog and adding color grading to tweakfile

main
Elijah Voigt 2 years ago
parent 3429e8f0bd
commit 0f17a2523a

5
Cargo.lock generated

@ -396,6 +396,7 @@ dependencies = [
"bevy_tasks",
"bevy_utils",
"bytemuck",
"serde",
]
[[package]]
@ -593,6 +594,7 @@ dependencies = [
"bevy_math",
"bevy_reflect",
"bevy_utils",
"serde",
"thiserror",
]
@ -927,6 +929,7 @@ dependencies = [
"bevy_reflect",
"bevy_utils",
"crossbeam-channel",
"serde",
"thiserror",
]
@ -941,6 +944,7 @@ dependencies = [
"bevy_hierarchy",
"bevy_math",
"bevy_reflect",
"serde",
]
[[package]]
@ -1014,6 +1018,7 @@ dependencies = [
"bevy_reflect",
"bevy_utils",
"raw-window-handle",
"serde",
]
[[package]]

@ -6,7 +6,7 @@ build = "build.rs"
[dependencies]
bevy_fmod = { version = "0.3", features = ["live-update"] }
bevy = { version = "0.11", features = ["jpeg", "hdr"] }
bevy = { version = "0.11", features = ["jpeg", "hdr", "serialize"] }
serde = "1"
toml = { version = "0.8", features = ["parse"] }

@ -15,12 +15,22 @@ main = "/Music/Main Track2"
select = "/SFX/MenuSelect"
[display3d.fog]
exponent = 2.0
exponent = 1.0
# https://docs.rs/bevy/latest/bevy/pbr/enum.FogFalloff.html
falloff = "Atmospheric (extinction 1.0 1.0 1.0) (inscattering 1.0 1.0 1.0)"
falloff = "Exponential 0.1"
# Examples:
# "Linear start end"
# "Exponential density"
# "ExponentialSquared density"
# "Exponential (extinction 1.0 1.0 1.0) (inscattering 1.0 1.0 1.0)"
[display3d.fog.color]
Rgba = { red = 1.0, green = 1.0, blue = 1.0, alpha = 1.0 }
Rgba = { red = 1.0, green = 0.2, blue = 0.1, alpha = 0.1 }
[display3d.fog.light_color]
Rgba = { red = 1.0, green = 1.0, blue = 1.0, alpha = 1.0 }
Rgba = { red = 1.0, green = 1.0, blue = 1.0, alpha = 0.1 }
# https://docs.rs/bevy/latest/bevy/render/view/struct.ColorGrading.html
[display3d.color.grading]
exposure = 0.0
gamma = 1.0
pre_saturation = 1.0
post_saturation = 1.0

@ -1,6 +1,7 @@
use crate::{
game::{Board, BoardIndex, Piece, Side},
prelude::*,
tweak::Tweakfile,
};
use bevy::{
core_pipeline::{tonemapping::DebandDither, Skybox},
@ -11,7 +12,7 @@ use bevy::{
},
window::PrimaryWindow,
};
use serde::{Deserialize, Deserializer, de};
use serde::{de, Deserialize, Deserializer};
pub(crate) struct Display3dPlugin;
@ -44,6 +45,7 @@ impl Plugin for Display3dPlugin {
create_valid_move_entity.run_if(any_component_added::<game::Selected>),
remove_valid_move_entity.run_if(any_component_removed::<game::Selected>()),
set_valid_move_model.run_if(any_component_added::<game::ValidMove>),
update_tweaks.run_if(on_event::<AssetEvent<Tweakfile>>()),
),
)
.add_systems(
@ -83,92 +85,6 @@ impl Plugin for Display3dPlugin {
}
}
#[derive(Debug, Deserialize, Default)]
pub(crate) struct Display3dTweaks {
#[serde(default)]
fog: FogTweaks,
}
#[derive(Debug, Deserialize)]
struct FogTweaks {
#[serde(default)]
color: Color,
#[serde(default)]
light_color: Color,
#[serde(default)]
exponent: f32,
#[serde(default = "default_fog_falloff", deserialize_with = "deserialize_fog_falloff")]
falloff: FogFalloff,
}
impl Default for FogTweaks {
fn default() -> Self {
FogTweaks {
color: Color::WHITE,
light_color: Color::WHITE,
exponent: 1.0,
falloff: FogFalloff::Exponential {
density: 1.0,
}
}
}
}
fn default_fog_falloff() -> FogFalloff {
FogFalloff::Exponential {
density: 1.0,
}
}
fn deserialize_fog_falloff<'de, D: Deserializer<'de>>(deserializer: D) -> Result<FogFalloff, D::Error> {
if let Ok(s) = String::deserialize(deserializer) {
// Linear [start f32] [end f32]
if s.starts_with("Linear") {
let mut parts = s.split(' ');
let start: f32 = parts.nth(1).expect("Fog Linear Start").parse().expect("Floating point number");
let end: f32 = parts.nth(2).expect("Fog Linear End").parse().expect("Floating point number");
Ok(FogFalloff::Linear { start, end })
// Exponential [density f32]
} else if s.starts_with("Exponential") {
let mut parts = s.split(' ');
let density: f32 = parts.nth(1).expect("Fog Exponential Density").parse().expect("Floating point number");
Ok(FogFalloff::Exponential { density })
// ExponentialSquared [density f32]
} else if s.starts_with("ExponentialSquared") {
let mut parts = s.split(' ');
let density: f32 = parts.nth(1).expect("Fog Exponential Density Squared").parse().expect("Floating point number");
Ok(FogFalloff::ExponentialSquared { density })
// Atmospheric (extinction [r: f32] [g: f32] [b: f32]) (inscattering [r: f32] [g: f32] [b: f32])
} else if s.starts_with("Atmospheric") {
let extinction = {
let start = s.find("extinction").expect("Extinction start");
let end = s[start..].match_indices(')').find_map(|(i, _)| Some(i)).expect("Extinction end");
let mut parts = s[start..start+end].split(' ');
let _ = parts.next();
let r: f32 = parts.next().expect("red value").parse().expect("Floating point number");
let g: f32 = parts.next().expect("green value").parse().expect("Floating point number");
let b: f32 = parts.next().expect("blue value").parse().expect("Floating point number");
Vec3::new(r, g, b)
};
let inscattering = {
let start = s.find("inscattering").expect("Inscattering start");
let end = s[start..].match_indices(')').find_map(|(i, _)| Some(i)).expect("Inscattering end");
let mut parts = s[start..start+end].split(' ');
let _ = parts.next();
let r: f32 = parts.next().expect("red value").parse().expect("Floating point number");
let g: f32 = parts.next().expect("green value").parse().expect("Floating point number");
let b: f32 = parts.next().expect("blue value").parse().expect("Floating point number");
Vec3::new(r, g, b)
};
Ok(FogFalloff::Atmospheric { extinction, inscattering })
} else {
Err(de::Error::custom("Failed to parse fog value"))
}
} else {
Err(de::Error::custom("Failed to parse fog value"))
}
}
#[derive(Debug, Component)]
pub(crate) struct Display3d;
@ -318,6 +234,26 @@ fn hydrate_camera(
});
}
fn update_tweaks(
mut events: EventReader<AssetEvent<Tweakfile>>,
mut camera_settings: Query<(&mut FogSettings, &mut ColorGrading), With<Display3d>>,
tweaks: Res<Assets<Tweakfile>>,
) {
events.iter().for_each(|event| match event {
AssetEvent::Created { handle } | AssetEvent::Modified { handle } => {
if let Some(tweak) = tweaks.get(handle) {
camera_settings
.iter_mut()
.for_each(|(mut fog, mut color_grading)| {
*fog = tweak.display3d.fog.clone().into();
*color_grading = tweak.display3d.color.grading.clone().into();
});
}
}
AssetEvent::Removed { .. } => debug!("Tweakfile removal not handled"),
});
}
fn fix_skybox(mut images: ResMut<Assets<Image>>, assets: Res<AssetsMap>) {
let image = images.get_mut(&assets.skybox).unwrap();
info!("Loaded skybox image");
@ -353,8 +289,22 @@ fn set_piece_model(
}
fn set_board_model(
mut boards: Query<&mut Handle<Scene>, (With<game::BoardComponent>, Without<TilesComponent>, With<Display3d>)>,
mut tiles: Query<&mut Handle<Scene>, (With<TilesComponent>, Without<game::BoardComponent>, With<Display3d>)>,
mut boards: Query<
&mut Handle<Scene>,
(
With<game::BoardComponent>,
Without<TilesComponent>,
With<Display3d>,
),
>,
mut tiles: Query<
&mut Handle<Scene>,
(
With<TilesComponent>,
Without<game::BoardComponent>,
With<Display3d>,
),
>,
assets_map: Res<AssetsMap>,
gltfs: Res<Assets<Gltf>>,
) {
@ -668,7 +618,9 @@ fn create_valid_move_entity(
.map(|i| Transform::from_translation(board_translation(i)))
.for_each(|t| {
commands.entity(board_entity).with_children(|parent| {
parent.spawn((Display3d, game::ValidMove, SceneBundle { ..default() })).insert(t);
parent
.spawn((Display3d, game::ValidMove, SceneBundle { ..default() }))
.insert(t);
});
});
}
@ -681,13 +633,13 @@ fn set_valid_move_model(
assets_map: Res<AssetsMap>,
) {
if let Some(gltf) = gltfs.get(&assets_map.models) {
events.iter_mut().for_each(|mut handle| *handle = gltf.named_scenes.get("Valid Move Spot").unwrap().clone())
events.iter_mut().for_each(|mut handle| {
*handle = gltf.named_scenes.get("Valid Move Spot").unwrap().clone()
})
}
}
fn play_valid_move_animation(
players: Query<&AnimationPlayer>,
) {
fn play_valid_move_animation(players: Query<&AnimationPlayer>) {
todo!();
}
@ -797,3 +749,184 @@ fn switch_sides(
);
});
}
pub(crate) mod tweaks {
use super::*;
#[derive(Debug, Deserialize, Default)]
pub(crate) struct Display3dTweaks {
#[serde(default)]
pub fog: FogTweaks,
#[serde(default)]
pub color: ColorTweaks,
}
#[derive(Debug, Deserialize, Default)]
pub(super) struct ColorTweaks {
#[serde(default)]
pub grading: ColorGradingTweaks,
}
#[derive(Debug, Deserialize, Default, Clone)]
pub(super) struct ColorGradingTweaks {
pub exposure: f32,
pub gamma: f32,
pub pre_saturation: f32,
pub post_saturation: f32,
}
impl Into<ColorGrading> for ColorGradingTweaks {
fn into(self) -> ColorGrading {
ColorGrading {
exposure: self.exposure,
gamma: self.gamma,
pre_saturation: self.pre_saturation,
post_saturation: self.post_saturation,
}
}
}
#[derive(Debug, Clone, Deserialize)]
pub(super) struct FogTweaks {
#[serde(default)]
color: Color,
#[serde(default)]
light_color: Color,
#[serde(default)]
exponent: f32,
#[serde(
default = "default_fog_falloff",
deserialize_with = "deserialize_fog_falloff"
)]
falloff: FogFalloff,
}
impl Default for FogTweaks {
fn default() -> Self {
FogTweaks {
color: Color::WHITE,
light_color: Color::WHITE,
exponent: 1.0,
falloff: FogFalloff::Exponential { density: 1.0 },
}
}
}
impl Into<FogSettings> for FogTweaks {
fn into(self) -> FogSettings {
FogSettings {
color: self.color,
directional_light_color: self.light_color,
directional_light_exponent: self.exponent,
falloff: self.falloff.clone(),
}
}
}
fn default_fog_falloff() -> FogFalloff {
FogFalloff::Exponential { density: 1.0 }
}
fn deserialize_fog_falloff<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<FogFalloff, D::Error> {
if let Ok(s) = String::deserialize(deserializer) {
// Linear [start f32] [end f32]
if s.starts_with("Linear") {
let mut parts = s.split(' ');
let _ = parts.next();
let start: f32 = parts
.next()
.expect("Fog Linear Start")
.parse()
.expect("Floating point number");
let end: f32 = parts
.next()
.expect("Fog Linear End")
.parse()
.expect("Floating point number");
Ok(FogFalloff::Linear { start, end })
// Exponential [density f32]
} else if s.starts_with("Exponential") {
let mut parts = s.split(' ');
let _ = parts.next();
let density: f32 = parts
.next()
.expect("Fog Exponential Density")
.parse()
.expect("Floating point number");
Ok(FogFalloff::Exponential { density })
// ExponentialSquared [density f32]
} else if s.starts_with("ExponentialSquared") {
let mut parts = s.split(' ');
let _ = parts.next();
let density: f32 = parts
.next()
.expect("Fog Exponential Density Squared")
.parse()
.expect("Floating point number");
Ok(FogFalloff::ExponentialSquared { density })
// Atmospheric (extinction [r: f32] [g: f32] [b: f32]) (inscattering [r: f32] [g: f32] [b: f32])
} else if s.starts_with("Atmospheric") {
let extinction = {
let start = s.find("extinction").expect("Extinction start");
let end = s[start..]
.match_indices(')')
.find_map(|(i, _)| Some(i))
.expect("Extinction end");
let mut parts = s[start..start + end].split(' ');
let _ = parts.next();
let r: f32 = parts
.next()
.expect("red value")
.parse()
.expect("Floating point number");
let g: f32 = parts
.next()
.expect("green value")
.parse()
.expect("Floating point number");
let b: f32 = parts
.next()
.expect("blue value")
.parse()
.expect("Floating point number");
Vec3::new(r, g, b)
};
let inscattering = {
let start = s.find("inscattering").expect("Inscattering start");
let end = s[start..]
.match_indices(')')
.find_map(|(i, _)| Some(i))
.expect("Inscattering end");
let mut parts = s[start..start + end].split(' ');
let _ = parts.next();
let r: f32 = parts
.next()
.expect("red value")
.parse()
.expect("Floating point number");
let g: f32 = parts
.next()
.expect("green value")
.parse()
.expect("Floating point number");
let b: f32 = parts
.next()
.expect("blue value")
.parse()
.expect("Floating point number");
Vec3::new(r, g, b)
};
Ok(FogFalloff::Atmospheric {
extinction,
inscattering,
})
} else {
Err(de::Error::custom("Failed to parse fog value"))
}
} else {
Err(de::Error::custom("Failed to parse fog value"))
}
}
}

@ -12,7 +12,6 @@ pub(crate) struct TweakPlugin;
impl Plugin for TweakPlugin {
fn build(&self, app: &mut App) {
app.add_systems(OnEnter(GameState::Loading), load_tweakfile);
app.add_asset::<Tweakfile>()
@ -35,10 +34,9 @@ pub(crate) struct Tweakfile {
#[serde(default)]
pub audio: audio::AudioTweaks,
#[serde(default)]
pub display3d: display3d::Display3dTweaks,
pub display3d: display3d::tweaks::Display3dTweaks,
}
#[derive(Default)]
pub struct TweakfileLoader;

Loading…
Cancel
Save