|
|
|
|
@ -4,23 +4,18 @@ use crate::{
|
|
|
|
|
tweak::Tweaks,
|
|
|
|
|
};
|
|
|
|
|
use bevy::{
|
|
|
|
|
animation::RepeatAnimation,
|
|
|
|
|
core_pipeline::{
|
|
|
|
|
animation::RepeatAnimation, core_pipeline::{
|
|
|
|
|
experimental::taa::{TemporalAntiAliasPlugin, TemporalAntiAliasSettings},
|
|
|
|
|
prepass::MotionVectorPrepass,
|
|
|
|
|
tonemapping::{DebandDither, Tonemapping},
|
|
|
|
|
Skybox,
|
|
|
|
|
},
|
|
|
|
|
input::mouse::{MouseButtonInput, MouseMotion, MouseScrollUnit, MouseWheel},
|
|
|
|
|
pbr::{
|
|
|
|
|
}, input::mouse::{MouseButtonInput, MouseMotion, MouseScrollUnit, MouseWheel}, pbr::{
|
|
|
|
|
ExtendedMaterial, MaterialExtension, OpaqueRendererMethod,
|
|
|
|
|
ScreenSpaceAmbientOcclusionBundle, ScreenSpaceAmbientOcclusionSettings,
|
|
|
|
|
},
|
|
|
|
|
render::{
|
|
|
|
|
}, render::{
|
|
|
|
|
render_resource::{AsBindGroup, ShaderRef, TextureViewDescriptor, TextureViewDimension},
|
|
|
|
|
view::ColorGrading,
|
|
|
|
|
},
|
|
|
|
|
window::PrimaryWindow,
|
|
|
|
|
}, utils::HashMap, window::PrimaryWindow
|
|
|
|
|
};
|
|
|
|
|
use tweaks::*;
|
|
|
|
|
|
|
|
|
|
@ -75,6 +70,7 @@ impl Plugin for Display3dPlugin {
|
|
|
|
|
.or_else(any_component_added::<PointLight>)
|
|
|
|
|
.or_else(on_event::<AssetEvent<Tweaks>>()),
|
|
|
|
|
),
|
|
|
|
|
setup_capture_piece.run_if(any_component_added::<Piece>),
|
|
|
|
|
capture_piece.run_if(any_with_component::<game::Captured>()),
|
|
|
|
|
),
|
|
|
|
|
)
|
|
|
|
|
@ -1283,6 +1279,58 @@ impl MaterialExtension for DissolveExtension {
|
|
|
|
|
#[derive(Debug, Component, Clone)]
|
|
|
|
|
struct Backup<T: Component>(T);
|
|
|
|
|
|
|
|
|
|
/// Sets up all pieces to have an associated "dissolve" material ready for capture
|
|
|
|
|
fn setup_capture_piece(
|
|
|
|
|
// Only process newly created pieces (we do not delete pieces at runtime)
|
|
|
|
|
events: Query<Entity, Added<Piece>>,
|
|
|
|
|
// Children of pieces are the actual meshes that need materials
|
|
|
|
|
children: Query<&Children>,
|
|
|
|
|
// All entities with materials are candidates for this procedure
|
|
|
|
|
query: Query<(Entity, &Handle<StandardMaterial>)>,
|
|
|
|
|
// Used to create DissovleMaterial
|
|
|
|
|
standard_materials: Res<Assets<StandardMaterial>>,
|
|
|
|
|
// Used to create Handle<DissolveMaterial>
|
|
|
|
|
mut dissolve_materials: ResMut<Assets<DissolveMaterial>>,
|
|
|
|
|
// Used to insert Backup(Handle<DissolveMaterial>);
|
|
|
|
|
mut commands: Commands,
|
|
|
|
|
// Cache dissolve textures that have already been created
|
|
|
|
|
mut cache: Local<HashMap<Handle<StandardMaterial>, Handle<DissolveMaterial>>>,
|
|
|
|
|
) {
|
|
|
|
|
events.iter().for_each(|entity| {
|
|
|
|
|
query
|
|
|
|
|
.iter_many(children.iter_descendants(entity))
|
|
|
|
|
.for_each(|(child, std_handle)| {
|
|
|
|
|
let dis_handle = match cache.get(std_handle) {
|
|
|
|
|
// We have not seen this material, so create a new dissolve material
|
|
|
|
|
None => {
|
|
|
|
|
// Extension we will add to existing gltf-sourced materials
|
|
|
|
|
let extension = DissolveExtension { percentage: 1.0 };
|
|
|
|
|
// Base material we will extend for the duration of the dissolve effect
|
|
|
|
|
let mut base = standard_materials
|
|
|
|
|
.get(std_handle)
|
|
|
|
|
.expect("Resolve material data")
|
|
|
|
|
.clone();
|
|
|
|
|
|
|
|
|
|
base.opaque_render_method = OpaqueRendererMethod::Auto;
|
|
|
|
|
base.alpha_mode = AlphaMode::Mask(0.5);
|
|
|
|
|
|
|
|
|
|
dissolve_materials.add(ExtendedMaterial { base, extension })
|
|
|
|
|
},
|
|
|
|
|
Some(dis_handle) => dis_handle.clone(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
cache.insert(std_handle.clone(), dis_handle.clone());
|
|
|
|
|
|
|
|
|
|
commands
|
|
|
|
|
.entity(child)
|
|
|
|
|
.insert(dis_handle.clone())
|
|
|
|
|
.insert(Backup(std_handle.clone()))
|
|
|
|
|
.remove::<Handle<StandardMaterial>>();
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// When a piece is captured...
|
|
|
|
|
/// 1. Play a cool "captured" animation and a neat sound
|
|
|
|
|
/// 2. Move the piece to the side of the board
|
|
|
|
|
@ -1295,11 +1343,11 @@ fn capture_piece(
|
|
|
|
|
(With<Display3d>, With<game::Captured>),
|
|
|
|
|
>,
|
|
|
|
|
mut state: Local<Option<game::CaptureFlow>>,
|
|
|
|
|
standard_materials: ResMut<Assets<StandardMaterial>>,
|
|
|
|
|
mut kids: Local<Vec<Entity>>,
|
|
|
|
|
mut prog: Local<f32>,
|
|
|
|
|
mut dissolve_materials: ResMut<Assets<DissolveMaterial>>,
|
|
|
|
|
object_standard_materials: Query<&Handle<StandardMaterial>>,
|
|
|
|
|
object_dissolve_materials: Query<&Handle<DissolveMaterial>>,
|
|
|
|
|
backup_material: Query<&Backup<Handle<StandardMaterial>>>,
|
|
|
|
|
object_standard_materials: Query<(Entity, &Handle<StandardMaterial>, &Backup<Handle<DissolveMaterial>>)>,
|
|
|
|
|
object_dissolve_materials: Query<(Entity, &Handle<DissolveMaterial>, &Backup<Handle<StandardMaterial>>)>,
|
|
|
|
|
children: Query<&Children>,
|
|
|
|
|
mut commands: Commands,
|
|
|
|
|
time: Res<Time>,
|
|
|
|
|
@ -1308,40 +1356,70 @@ fn capture_piece(
|
|
|
|
|
let duration: f32 = 3.0;
|
|
|
|
|
|
|
|
|
|
match *state {
|
|
|
|
|
// State is None, so we need to initiate the animation by swapping the StadardMaterial for the DissolveMaterial
|
|
|
|
|
None => {
|
|
|
|
|
*state = events.iter().next().map(|entity| {
|
|
|
|
|
// Reset dissolve progress
|
|
|
|
|
*prog = 1.0;
|
|
|
|
|
|
|
|
|
|
// store the kids we want to process
|
|
|
|
|
*kids = children
|
|
|
|
|
.iter_descendants(entity)
|
|
|
|
|
.filter_map(|e| object_standard_materials.get(e).ok())
|
|
|
|
|
.map(|(child, std_handle, Backup(dis_handle))| {
|
|
|
|
|
// Swap standard and dissolve material
|
|
|
|
|
commands
|
|
|
|
|
.entity(child)
|
|
|
|
|
.insert(dis_handle.clone())
|
|
|
|
|
.insert(Backup(std_handle.clone()))
|
|
|
|
|
.remove::<Handle<StandardMaterial>>()
|
|
|
|
|
.remove::<Backup<Handle<DissolveMaterial>>>();
|
|
|
|
|
|
|
|
|
|
// Return child entity to be processed later in flow
|
|
|
|
|
child
|
|
|
|
|
}).collect();
|
|
|
|
|
|
|
|
|
|
// Set the next state to start fading out
|
|
|
|
|
game::CaptureFlow::FadeOut(entity)
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
Some(s) => {
|
|
|
|
|
match s {
|
|
|
|
|
game::CaptureFlow::FadeOut(entity) => {
|
|
|
|
|
// TODO: Do we need this?
|
|
|
|
|
let (_, _, _) = query
|
|
|
|
|
.get_mut(entity)
|
|
|
|
|
.expect("Visibility and Transform of captured piece");
|
|
|
|
|
|
|
|
|
|
game::CaptureFlow::FadeOut(_entity) => {
|
|
|
|
|
// Play fade-out animation
|
|
|
|
|
{
|
|
|
|
|
object_dissolve_materials.iter().for_each(|handle| {
|
|
|
|
|
let extended_material = dissolve_materials
|
|
|
|
|
.get_mut(handle)
|
|
|
|
|
.expect("Get the dissolve material");
|
|
|
|
|
|
|
|
|
|
// Calculate how much of the animation has passed
|
|
|
|
|
let delta = time.delta_seconds() / duration;
|
|
|
|
|
|
|
|
|
|
// Change the material's value to create animation
|
|
|
|
|
extended_material.extension.percentage -= delta; // TODO: Tweak this timing
|
|
|
|
|
// Set progress to current - delta
|
|
|
|
|
*prog -= delta;
|
|
|
|
|
|
|
|
|
|
debug!(
|
|
|
|
|
"Play fade out animation {:?} {:?}",
|
|
|
|
|
delta, extended_material.extension.percentage
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if extended_material.extension.percentage <= 0.0 {
|
|
|
|
|
// If progress is less than zero
|
|
|
|
|
if *prog <= 0.0 {
|
|
|
|
|
// Set to exactly 0 for simplicity
|
|
|
|
|
extended_material.extension.percentage = 0.0;
|
|
|
|
|
*prog = 0.0;
|
|
|
|
|
|
|
|
|
|
// Move to next state now that animation is done
|
|
|
|
|
*state = s.next();
|
|
|
|
|
// This takes effect after updating all children
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
object_dissolve_materials
|
|
|
|
|
.iter_many(kids.iter())
|
|
|
|
|
.for_each(|(_child, dis_handle, _)| {
|
|
|
|
|
let dissolve_material = dissolve_materials
|
|
|
|
|
.get_mut(dis_handle)
|
|
|
|
|
.expect("Get the dissolve material");
|
|
|
|
|
|
|
|
|
|
// Change the material's value to create animation
|
|
|
|
|
dissolve_material.extension.percentage = *prog;
|
|
|
|
|
|
|
|
|
|
debug!(
|
|
|
|
|
"Play fade out animation {:?} {:?}",
|
|
|
|
|
delta, dissolve_material.extension.percentage
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
game::CaptureFlow::Store(entity) => {
|
|
|
|
|
@ -1366,76 +1444,50 @@ fn capture_piece(
|
|
|
|
|
// Show piece now that it is moved
|
|
|
|
|
*v = Visibility::Inherited;
|
|
|
|
|
|
|
|
|
|
// Play fade-in animation
|
|
|
|
|
{
|
|
|
|
|
object_dissolve_materials.iter().for_each(|handle| {
|
|
|
|
|
let extended_material = dissolve_materials
|
|
|
|
|
.get_mut(handle)
|
|
|
|
|
.expect("Get the dissolve material");
|
|
|
|
|
|
|
|
|
|
// Calculate how much of the animation has passed
|
|
|
|
|
let delta = time.delta_seconds() / duration;
|
|
|
|
|
|
|
|
|
|
// Change the material's value to create animation
|
|
|
|
|
extended_material.extension.percentage += delta; // TODO: Tweak this timing
|
|
|
|
|
// Move the animation forward by delta
|
|
|
|
|
*prog += delta;
|
|
|
|
|
|
|
|
|
|
debug!(
|
|
|
|
|
"Play fade in animation {:?} {:?}",
|
|
|
|
|
delta, extended_material.extension.percentage
|
|
|
|
|
);
|
|
|
|
|
// If we have completed the animation
|
|
|
|
|
if *prog >= 1.0 {
|
|
|
|
|
// Remove the captured component for bookkeeping
|
|
|
|
|
commands.entity(entity).remove::<game::Captured>();
|
|
|
|
|
|
|
|
|
|
if extended_material.extension.percentage >= 1.0 {
|
|
|
|
|
// Move to next state now that animation is done
|
|
|
|
|
*state = s.next();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Remove the captured component for bookkeeping
|
|
|
|
|
commands.entity(entity).remove::<game::Captured>();
|
|
|
|
|
// Play fade-in animation
|
|
|
|
|
{
|
|
|
|
|
object_dissolve_materials.iter_many(kids.iter()).for_each(|(child, dis_handle, Backup(std_handle))| {
|
|
|
|
|
let dissolve_material = dissolve_materials
|
|
|
|
|
.get_mut(dis_handle)
|
|
|
|
|
.expect("Get the dissolve material");
|
|
|
|
|
|
|
|
|
|
// Remove the dissolve material
|
|
|
|
|
commands.entity(entity).remove::<Handle<DissolveMaterial>>();
|
|
|
|
|
// Change the material's value to create animation
|
|
|
|
|
dissolve_material.extension.percentage = *prog;
|
|
|
|
|
|
|
|
|
|
debug!(
|
|
|
|
|
"Play fade in animation {:?} {:?}",
|
|
|
|
|
delta, dissolve_material.extension.percentage
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// If we are done with the animation cleanup
|
|
|
|
|
if dissolve_material.extension.percentage >= 1.0 {
|
|
|
|
|
// Re-add the original material
|
|
|
|
|
if let Ok(Backup(orig)) = backup_material.get(entity) {
|
|
|
|
|
commands.entity(entity).insert(orig.clone());
|
|
|
|
|
commands
|
|
|
|
|
.entity(entity)
|
|
|
|
|
.entity(child)
|
|
|
|
|
.insert(std_handle.clone())
|
|
|
|
|
.insert(Backup(dis_handle.clone()))
|
|
|
|
|
.remove::<Handle<DissolveMaterial>>()
|
|
|
|
|
.remove::<Backup<Handle<StandardMaterial>>>();
|
|
|
|
|
} else {
|
|
|
|
|
warn!("Entity {:?} does not have original material", entity)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
None => {
|
|
|
|
|
*state = events.iter().next().map(|entity| {
|
|
|
|
|
children
|
|
|
|
|
.iter_descendants(entity)
|
|
|
|
|
.filter_map(|e| object_standard_materials.get(e).ok().map(|h| (e, h)))
|
|
|
|
|
.for_each(|(child, handle)| {
|
|
|
|
|
// Extension we will add to existing gltf-sourced materials
|
|
|
|
|
let extension = DissolveExtension { percentage: 1.0 };
|
|
|
|
|
// Base material we will extend for the duration of the dissolve effect
|
|
|
|
|
let mut base = standard_materials
|
|
|
|
|
.get(handle)
|
|
|
|
|
.expect("Resolve material data")
|
|
|
|
|
.clone();
|
|
|
|
|
|
|
|
|
|
base.opaque_render_method = OpaqueRendererMethod::Auto;
|
|
|
|
|
base.alpha_mode = AlphaMode::Mask(0.5);
|
|
|
|
|
|
|
|
|
|
commands
|
|
|
|
|
.entity(child)
|
|
|
|
|
.insert(dissolve_materials.add(ExtendedMaterial { base, extension }))
|
|
|
|
|
.insert(Backup(handle.clone()))
|
|
|
|
|
.remove::<Handle<StandardMaterial>>();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Set the next state to start fading out
|
|
|
|
|
game::CaptureFlow::FadeOut(entity)
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|