|
|
|
|
@ -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"))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|