Group brush CSG history edits
This commit is contained in:
parent
1b9fbebda1
commit
3f85d25cc7
@ -119,6 +119,14 @@ pub enum EditorCommand {
|
||||
old_brush: Option<BrushDesc>,
|
||||
new_brush: BrushDesc,
|
||||
},
|
||||
ApplyBrushCsg {
|
||||
primary: Entity,
|
||||
old_transform: Transform,
|
||||
new_transform: Transform,
|
||||
old_brush: Option<BrushDesc>,
|
||||
new_brush: BrushDesc,
|
||||
deleted: Vec<(EditorEntitySnapshot, Option<Entity>)>,
|
||||
},
|
||||
SetStaticMeshRenderer {
|
||||
entity: Entity,
|
||||
old: Option<StaticMeshRenderer>,
|
||||
@ -185,6 +193,7 @@ impl EditorCommand {
|
||||
EditorCommand::SetPrimitive { .. } => "Set Primitive",
|
||||
EditorCommand::SetBrush { .. } => "Set Brush",
|
||||
EditorCommand::SetBrushTransform { .. } => "Clip Brush",
|
||||
EditorCommand::ApplyBrushCsg { .. } => "Brush CSG",
|
||||
EditorCommand::SetStaticMeshRenderer { .. } => "Set Static Mesh Renderer",
|
||||
EditorCommand::SetPostProcessVolume { .. } => "Set Post Process Volume",
|
||||
EditorCommand::SetTransformGroup { .. } => "Move Selection",
|
||||
|
||||
@ -529,6 +529,52 @@ pub fn set_brush_transform_with_history(
|
||||
);
|
||||
}
|
||||
|
||||
pub fn apply_brush_csg_with_history(
|
||||
world: &mut World,
|
||||
primary: Entity,
|
||||
new_transform: Transform,
|
||||
new_brush: BrushDesc,
|
||||
delete_entities: &[Entity],
|
||||
) {
|
||||
if !is_level_object(world, primary) {
|
||||
return;
|
||||
}
|
||||
let old_transform = world.get::<Transform>(primary).copied().unwrap_or_default();
|
||||
let old_brush = world.get::<BrushDesc>(primary).cloned();
|
||||
let deleted: Vec<(EditorEntitySnapshot, Option<Entity>)> = delete_entities
|
||||
.iter()
|
||||
.copied()
|
||||
.filter_map(|entity| {
|
||||
snapshot_entity(world, entity).map(|snapshot| (snapshot, Some(entity)))
|
||||
})
|
||||
.collect();
|
||||
if old_transform == new_transform
|
||||
&& old_brush.as_ref() == Some(&new_brush)
|
||||
&& deleted.is_empty()
|
||||
{
|
||||
return;
|
||||
}
|
||||
if let Ok(mut entity_mut) = world.get_entity_mut(primary) {
|
||||
entity_mut.insert(new_transform);
|
||||
entity_mut.insert(new_brush.clone());
|
||||
}
|
||||
for (_, entity) in &deleted {
|
||||
despawn_entity(world, *entity);
|
||||
}
|
||||
push_history(
|
||||
world,
|
||||
EditorCommand::ApplyBrushCsg {
|
||||
primary,
|
||||
old_transform,
|
||||
new_transform,
|
||||
old_brush,
|
||||
new_brush,
|
||||
deleted,
|
||||
},
|
||||
);
|
||||
select_one(world, primary);
|
||||
}
|
||||
|
||||
pub fn set_static_mesh_renderer_with_history(
|
||||
world: &mut World,
|
||||
entity: Entity,
|
||||
@ -875,6 +921,25 @@ fn undo_command(world: &mut World, command: &mut EditorCommand) {
|
||||
}
|
||||
apply_brush(world, *entity, old_brush);
|
||||
}
|
||||
EditorCommand::ApplyBrushCsg {
|
||||
primary,
|
||||
old_transform,
|
||||
old_brush,
|
||||
deleted,
|
||||
..
|
||||
} => {
|
||||
if let Some(mut transform) = world.get_mut::<Transform>(*primary) {
|
||||
*transform = *old_transform;
|
||||
}
|
||||
apply_brush(world, *primary, old_brush);
|
||||
let mut restored = vec![*primary];
|
||||
for (snapshot, entity) in deleted.iter_mut() {
|
||||
let spawned = spawn_snapshot(world, snapshot);
|
||||
*entity = Some(spawned);
|
||||
restored.push(spawned);
|
||||
}
|
||||
select_many(world, &restored);
|
||||
}
|
||||
EditorCommand::SetStaticMeshRenderer { entity, old, .. } => {
|
||||
apply_static_mesh_renderer(world, *entity, old);
|
||||
}
|
||||
@ -1014,6 +1079,22 @@ fn redo_command(world: &mut World, command: &mut EditorCommand) {
|
||||
entity_mut.insert(new_brush.clone());
|
||||
}
|
||||
}
|
||||
EditorCommand::ApplyBrushCsg {
|
||||
primary,
|
||||
new_transform,
|
||||
new_brush,
|
||||
deleted,
|
||||
..
|
||||
} => {
|
||||
if let Ok(mut entity_mut) = world.get_entity_mut(*primary) {
|
||||
entity_mut.insert(*new_transform);
|
||||
entity_mut.insert(new_brush.clone());
|
||||
}
|
||||
for (_, entity) in deleted.iter_mut() {
|
||||
despawn_entity(world, entity.take());
|
||||
}
|
||||
select_one(world, *primary);
|
||||
}
|
||||
EditorCommand::SetStaticMeshRenderer { entity, new, .. } => {
|
||||
if let Ok(mut entity_mut) = world.get_entity_mut(*entity) {
|
||||
entity_mut.insert(new.clone());
|
||||
|
||||
@ -7,9 +7,7 @@ use shared::{
|
||||
BrushDesc, LevelObject,
|
||||
};
|
||||
|
||||
use crate::history::{
|
||||
delete_entities_with_history, set_brush_with_history, set_transform_with_history,
|
||||
};
|
||||
use crate::history::apply_brush_csg_with_history;
|
||||
use crate::scene_io::SceneIo;
|
||||
use crate::ui::UiState;
|
||||
|
||||
@ -241,17 +239,18 @@ fn commit_csg_preview(world: &mut World, pending: PendingBrushCsg) {
|
||||
return;
|
||||
}
|
||||
let new_brush = BrushDesc::cuboid(pending.result.size());
|
||||
apply_bounds_result(world, primary, pending.result, new_brush);
|
||||
if matches!(pending.op, BrushCsgOp::Merge | BrushCsgOp::Intersect) {
|
||||
let to_delete: Vec<_> = pending
|
||||
let to_delete: Vec<_> = if matches!(pending.op, BrushCsgOp::Merge | BrushCsgOp::Intersect) {
|
||||
pending
|
||||
.selected
|
||||
.iter()
|
||||
.skip(1)
|
||||
.copied()
|
||||
.filter(|entity| world.get::<BrushDesc>(*entity).is_some())
|
||||
.collect();
|
||||
delete_entities_with_history(world, &to_delete);
|
||||
}
|
||||
.collect()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
apply_bounds_result(world, primary, pending.result, new_brush, &to_delete);
|
||||
set_status(
|
||||
world,
|
||||
match pending.op {
|
||||
@ -318,6 +317,7 @@ fn apply_bounds_result(
|
||||
entity: Entity,
|
||||
bounds: BrushBounds,
|
||||
new_brush: BrushDesc,
|
||||
delete_entities: &[Entity],
|
||||
) {
|
||||
let center = bounds.center();
|
||||
let old_transform = world.get::<Transform>(entity).copied().unwrap_or_default();
|
||||
@ -325,8 +325,7 @@ fn apply_bounds_result(
|
||||
new_transform.translation = center;
|
||||
new_transform.rotation = Quat::IDENTITY;
|
||||
new_transform.scale = Vec3::ONE;
|
||||
set_transform_with_history(world, entity, old_transform, new_transform);
|
||||
set_brush_with_history(world, entity, new_brush);
|
||||
apply_brush_csg_with_history(world, entity, new_transform, new_brush, delete_entities);
|
||||
}
|
||||
|
||||
fn brush_world_bounds(world: &World, entity: Entity) -> Option<BrushBounds> {
|
||||
@ -398,6 +397,7 @@ fn set_status(world: &mut World, status: impl Into<String>) {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::history::EditorCommand;
|
||||
|
||||
fn bounds(min: Vec3, max: Vec3) -> BrushBounds {
|
||||
BrushBounds { min, max }
|
||||
@ -418,4 +418,18 @@ mod tests {
|
||||
assert_eq!(result.min, Vec3::new(1.0, 0.0, 0.0));
|
||||
assert_eq!(result.max, source.max);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn csg_history_command_is_grouped() {
|
||||
let command = EditorCommand::ApplyBrushCsg {
|
||||
primary: Entity::PLACEHOLDER,
|
||||
old_transform: Transform::default(),
|
||||
new_transform: Transform::from_translation(Vec3::X),
|
||||
old_brush: Some(BrushDesc::default()),
|
||||
new_brush: BrushDesc::default(),
|
||||
deleted: Vec::new(),
|
||||
};
|
||||
|
||||
assert_eq!(command.label(), "Brush CSG");
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user