Skip to content

Commit c1736a6

Browse files
committed
default data editor code
1 parent dda1f00 commit c1736a6

11 files changed

Lines changed: 311 additions & 168 deletions

File tree

crates/bevy_animation_graph_core/src/edge_data/bone_mask.rs

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,29 @@ use serde::{Deserialize, Serialize};
66

77
use crate::pose::BoneId;
88

9-
#[derive(Reflect, Clone, Debug, Serialize, Deserialize)]
9+
#[derive(Reflect, Clone, Debug, Serialize, Deserialize, Default)]
1010
#[reflect(Default)]
11-
pub enum BoneMask {
12-
/// If a bone is in the bones map, weight is given. Otherwise, weight is zero
13-
Positive { bones: HashMap<BoneId, f32> },
14-
/// If a bone is not in bones map, weight is 1. Otherwise, weight is as given
15-
Negative { bones: HashMap<BoneId, f32> },
16-
}
17-
18-
impl Default for BoneMask {
19-
fn default() -> Self {
20-
Self::Positive {
21-
bones: Default::default(),
22-
}
23-
}
11+
pub struct BoneMask {
12+
pub weights: HashMap<BoneId, f32>,
13+
pub base: BoneMaskType,
2414
}
2515

2616
impl BoneMask {
2717
pub fn bone_weight(&self, bone_id: &BoneId) -> f32 {
28-
match self {
29-
BoneMask::Positive { bones } => bones.get(bone_id).copied().unwrap_or(0.),
30-
BoneMask::Negative { bones } => bones.get(bone_id).copied().unwrap_or(1.),
31-
}
18+
let default = match self.base {
19+
BoneMaskType::Positive => 0.,
20+
BoneMaskType::Negative => 1.,
21+
};
22+
self.weights.get(bone_id).copied().unwrap_or(default)
3223
}
3324
}
25+
26+
#[derive(Reflect, Clone, Copy, Debug, Serialize, Deserialize, Default, PartialEq, Eq)]
27+
#[reflect(Default)]
28+
pub enum BoneMaskType {
29+
/// If a bone is in the bones map, weight is given. Otherwise, weight is zero
30+
#[default]
31+
Positive,
32+
/// If a bone is not in bones map, weight is 1. Otherwise, weight is as given
33+
Negative,
34+
}

crates/bevy_animation_graph_core/src/edge_data/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,23 @@ pub enum DataValue {
7575
RagdollConfig(RagdollConfig),
7676
}
7777

78+
impl DataValue {
79+
pub fn default_from_spec(spec: DataSpec) -> Self {
80+
match spec {
81+
DataSpec::F32 => DataValue::F32(Default::default()),
82+
DataSpec::Bool => DataValue::Bool(Default::default()),
83+
DataSpec::Vec2 => DataValue::Vec2(Default::default()),
84+
DataSpec::Vec3 => DataValue::Vec3(Default::default()),
85+
DataSpec::EntityPath => DataValue::EntityPath(Default::default()),
86+
DataSpec::Quat => DataValue::Quat(Default::default()),
87+
DataSpec::BoneMask => DataValue::BoneMask(Default::default()),
88+
DataSpec::Pose => DataValue::Pose(Default::default()),
89+
DataSpec::EventQueue => DataValue::EventQueue(Default::default()),
90+
DataSpec::RagdollConfig => DataValue::RagdollConfig(Default::default()),
91+
}
92+
}
93+
}
94+
7895
impl Default for DataValue {
7996
fn default() -> Self {
8097
Self::F32(0.)

crates/bevy_animation_graph_editor/src/ui/actions/graph.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use bevy::{
88
},
99
log::{error, info, warn},
1010
math::Vec2,
11+
platform::collections::HashMap,
1112
};
1213
use bevy_animation_graph::core::{
1314
animation_graph::{AnimationGraph, Edge, NodeId, PinId, SourcePin, TargetPin},
@@ -20,7 +21,7 @@ use bevy_animation_graph::core::{
2021
use super::{DynamicAction, run_handler, saving::DirtyAssets};
2122
use crate::{
2223
graph_show::{GraphIndicesMap, make_graph_indices},
23-
ui::{actions::ActionContext, egui_inspector_impls::OrderedMap},
24+
ui::actions::ActionContext,
2425
};
2526

2627
pub enum GraphAction {
@@ -90,7 +91,7 @@ pub struct RemoveNode {
9091

9192
pub struct UpdateDefaultData {
9293
pub graph: Handle<AnimationGraph>,
93-
pub input_data: OrderedMap<PinId, DataValue>,
94+
pub input_data: HashMap<PinId, DataValue>,
9495
}
9596

9697
pub struct UpdateGraphSpec {
@@ -267,8 +268,7 @@ pub fn remove_node_system(In(action): In<RemoveNode>, mut provider: GraphAndCont
267268

268269
pub fn update_input_data_system(In(action): In<UpdateDefaultData>, mut provider: GraphAndContext) {
269270
provider.provide_mut(&action.graph, |graph, _| {
270-
graph.default_data = action.input_data.values;
271-
graph.editor_metadata.input_param_order = action.input_data.order;
271+
graph.default_data = action.input_data;
272272
});
273273
provider.validate(&action.graph);
274274
provider.generate_indices(&action.graph);

crates/bevy_animation_graph_editor/src/ui/egui_inspector_impls.rs

Lines changed: 1 addition & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use bevy::{
1414
use bevy_animation_graph::core::{
1515
animation_clip::EntityPath,
1616
animation_graph::PinId,
17-
edge_data::{DataSpec, DataValue, bone_mask::BoneMask},
17+
edge_data::{DataSpec, DataValue},
1818
};
1919
use bevy_inspector_egui::{
2020
egui,
@@ -99,7 +99,6 @@ impl Plugin for BetterInspectorPlugin {
9999
let type_registry = &mut type_registry;
100100

101101
add_no_many::<String>(type_registry, string_mut, string_readonly);
102-
add_no_many::<BoneMask>(type_registry, bone_mask_ui_mut, todo_readonly_ui);
103102
add_no_many::<HashMap<EntityPath, f32>>(
104103
type_registry,
105104
better_hashmap::<EntityPath, f32>,
@@ -228,67 +227,6 @@ fn string_readonly(
228227
ui.label(value);
229228
}
230229

231-
pub fn bone_mask_ui_mut(
232-
value: &mut dyn Any,
233-
ui: &mut egui::Ui,
234-
_options: &dyn Any,
235-
id: egui::Id,
236-
mut env: InspectorUi<'_, '_>,
237-
) -> bool {
238-
let value = value.downcast_mut::<BoneMask>().unwrap();
239-
let (curr_val, curr_label) = if matches!(value, BoneMask::Positive { .. }) {
240-
(0, "Positive".to_string())
241-
} else {
242-
(1, "Negative".to_string())
243-
};
244-
245-
let mut hasher = std::collections::hash_map::DefaultHasher::new();
246-
hasher.write_u64(unsafe { std::mem::transmute_copy(&id) });
247-
hasher.write_usize(0);
248-
let bones_id = egui::Id::new(Hasher::finish(&hasher));
249-
250-
let mut new_val = curr_val;
251-
252-
egui::ComboBox::new(id, "Mask type")
253-
.selected_text(curr_label)
254-
.show_ui(ui, |ui| {
255-
ui.selectable_value(&mut new_val, 0, "Positive")
256-
.on_hover_ui(|ui| {
257-
ui.label("Bones not in the bone mask are given a weight of 0.");
258-
});
259-
ui.selectable_value(&mut new_val, 1, "Negative")
260-
.on_hover_ui(|ui| {
261-
ui.label("Bones not in the bone mask are given a weight of 1.");
262-
});
263-
});
264-
if new_val != curr_val {
265-
match new_val {
266-
0 => {
267-
*value = BoneMask::Positive {
268-
bones: Default::default(),
269-
};
270-
*value = BoneMask::Negative {
271-
bones: Default::default(),
272-
};
273-
}
274-
1 => {}
275-
_ => unreachable!(),
276-
}
277-
return true;
278-
}
279-
280-
let bones = match value {
281-
BoneMask::Positive { bones } => bones,
282-
BoneMask::Negative { bones } => bones,
283-
};
284-
285-
ui.horizontal(|ui| {
286-
ui.label("Bones");
287-
env.ui_for_reflect_with_options(bones, ui, bones_id, &())
288-
})
289-
.inner
290-
}
291-
292230
pub fn better_hashmap<
293231
K: Clone + FromReflect + TypePath + Default + Hash + Eq + PartialEq,
294232
T: Clone + FromReflect + TypePath + Default,
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use bevy_animation_graph::core::edge_data::bone_mask::{BoneMask, BoneMaskType};
2+
3+
use crate::ui::generic_widgets::{
4+
bone_id::{BoneIdReadonlyWidget, BoneIdWidget},
5+
hashmap::HashMapWidget,
6+
picker::PickerWidget,
7+
};
8+
9+
pub struct BoneMaskWidget<'a> {
10+
pub bone_mask: &'a mut BoneMask,
11+
pub id_hash: egui::Id,
12+
}
13+
14+
impl<'a> BoneMaskWidget<'a> {
15+
pub fn new_salted(bone_mask: &'a mut BoneMask, salt: impl std::hash::Hash) -> Self {
16+
Self {
17+
bone_mask,
18+
id_hash: egui::Id::new(salt),
19+
}
20+
}
21+
}
22+
23+
impl<'a> egui::Widget for BoneMaskWidget<'a> {
24+
fn ui(self, ui: &mut egui::Ui) -> egui::Response {
25+
ui.push_id(self.id_hash, |ui| {
26+
let previous_base = self.bone_mask.base;
27+
let mut response = PickerWidget::new_salted("bone mask type")
28+
.ui(ui, format!("{:?}", self.bone_mask.base), |ui| {
29+
for val in [BoneMaskType::Positive, BoneMaskType::Negative] {
30+
ui.selectable_value(&mut self.bone_mask.base, val, format!("{:?}", val));
31+
}
32+
})
33+
.response;
34+
if previous_base != self.bone_mask.base {
35+
response.mark_changed();
36+
}
37+
38+
response |= HashMapWidget::new_salted(&mut self.bone_mask.weights, "bone mask weights")
39+
.ui(
40+
ui,
41+
|ui, key| ui.add(BoneIdWidget::new_salted(key, "bone mask bone id")),
42+
|ui, key| ui.add(BoneIdReadonlyWidget::new_salted(key, "bone mask bone id")),
43+
|ui, weight| ui.add(egui::DragValue::new(weight).speed(0.01)),
44+
);
45+
46+
response
47+
})
48+
.inner
49+
}
50+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
use bevy_animation_graph::core::edge_data::{DataSpec, DataValue};
2+
3+
use crate::ui::generic_widgets::{
4+
bone_mask::BoneMaskWidget, entity_path::EntityPathWidget, picker::PickerWidget,
5+
quat::QuatWidget, ragdoll_config::RagdollConfigWidget, vec2::Vec2Widget, vec3::Vec3Widget,
6+
};
7+
8+
pub struct DataValueWidget<'a> {
9+
pub data_value: &'a mut DataValue,
10+
pub id_hash: egui::Id,
11+
}
12+
13+
impl<'a> DataValueWidget<'a> {
14+
pub fn new_salted(data_value: &'a mut DataValue, salt: impl std::hash::Hash) -> Self {
15+
Self {
16+
data_value,
17+
id_hash: egui::Id::new(salt),
18+
}
19+
}
20+
}
21+
22+
impl<'a> egui::Widget for DataValueWidget<'a> {
23+
fn ui(self, ui: &mut egui::Ui) -> egui::Response {
24+
ui.push_id(self.id_hash, |ui| {
25+
let mut selected = DataSpec::from(&*self.data_value);
26+
let mut response = PickerWidget::new_salted("data spec picker")
27+
.ui(ui, format!("{:?}", selected), |ui| {
28+
for val in [
29+
DataSpec::F32,
30+
DataSpec::Bool,
31+
DataSpec::Vec2,
32+
DataSpec::Vec3,
33+
DataSpec::EntityPath,
34+
DataSpec::Quat,
35+
DataSpec::BoneMask,
36+
DataSpec::Pose,
37+
DataSpec::EventQueue,
38+
DataSpec::RagdollConfig,
39+
] {
40+
ui.selectable_value(&mut selected, val, format!("{:?}", val));
41+
}
42+
})
43+
.response;
44+
45+
if selected != DataSpec::from(&*self.data_value) {
46+
response.mark_changed();
47+
*self.data_value = DataValue::default_from_spec(selected);
48+
}
49+
50+
match self.data_value {
51+
DataValue::F32(val) => {
52+
response |= ui.add(egui::DragValue::new(val));
53+
}
54+
DataValue::Bool(val) => {
55+
response |= ui.add(egui::Checkbox::without_text(val));
56+
}
57+
DataValue::Vec2(vec2) => {
58+
response |= ui.add(Vec2Widget::new_salted(vec2, "vec2"));
59+
}
60+
DataValue::Vec3(vec3) => {
61+
response |= ui.add(Vec3Widget::new_salted(vec3, "vec3"));
62+
}
63+
DataValue::Quat(quat) => {
64+
response |= ui.add(QuatWidget::new_salted(quat, "quat"));
65+
}
66+
DataValue::EntityPath(entity_path) => {
67+
response |= ui.add(EntityPathWidget::new_salted(entity_path, "entity path"));
68+
}
69+
DataValue::BoneMask(bone_mask) => {
70+
response |= ui.add(BoneMaskWidget::new_salted(bone_mask, "bone mask"));
71+
}
72+
DataValue::Pose(_) => {
73+
response |= ui.label("Pose value editing not supported");
74+
}
75+
DataValue::EventQueue(_) => {
76+
response |= ui.label("Event queue editing not supported");
77+
}
78+
DataValue::RagdollConfig(ragdoll_config) => {
79+
response |= ui.add(RagdollConfigWidget::new_salted(
80+
ragdoll_config,
81+
"ragdoll config",
82+
));
83+
}
84+
}
85+
86+
response
87+
})
88+
.inner
89+
}
90+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use bevy_animation_graph::core::animation_clip::EntityPath;
2+
3+
pub struct EntityPathWidget<'a> {
4+
pub entity_path: &'a mut EntityPath,
5+
pub id_hash: egui::Id,
6+
}
7+
8+
impl<'a> EntityPathWidget<'a> {
9+
pub fn new_salted(entity_path: &'a mut EntityPath, salt: impl std::hash::Hash) -> Self {
10+
Self {
11+
entity_path,
12+
id_hash: egui::Id::new(salt),
13+
}
14+
}
15+
}
16+
17+
impl<'a> egui::Widget for EntityPathWidget<'a> {
18+
fn ui(self, ui: &mut egui::Ui) -> egui::Response {
19+
ui.push_id(self.id_hash, |ui| {
20+
let mut data = self.entity_path.to_slashed_string();
21+
22+
let response = ui.text_edit_singleline(&mut data);
23+
if response.changed() {
24+
*self.entity_path = EntityPath::from_slashed_string(data);
25+
}
26+
27+
response
28+
})
29+
.inner
30+
}
31+
}

0 commit comments

Comments
 (0)