Skip to content

Commit 7701ca5

Browse files
committed
Decouple map brush tools from editing state
1 parent e6d33a2 commit 7701ca5

23 files changed

Lines changed: 477 additions & 277 deletions

File tree

‎native/src/sbc/chonsole/events.rs‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -225,17 +225,17 @@ struct ModState {
225225

226226
impl ModState {
227227
fn read(interface: &NativeInterfaceRef, tracked: TrackedModifiers) -> Self {
228-
let mod_state = interface.input().get_mod_key_state().unwrap_or(0);
228+
let (_, ctrl, _, shift) = interface
229+
.input()
230+
.get_mod_key_state()
231+
.unwrap_or((false, false, false, false));
229232
ModState {
230-
shift: tracked.shift || mod_state & NATIVE_MOD_SHIFT != 0,
231-
ctrl: tracked.ctrl || mod_state & NATIVE_MOD_CTRL != 0,
233+
shift: tracked.shift || shift,
234+
ctrl: tracked.ctrl || ctrl,
232235
}
233236
}
234237
}
235238

236-
const NATIVE_MOD_SHIFT: u32 = 1 << 0;
237-
const NATIVE_MOD_CTRL: u32 = 1 << 1;
238-
239239
#[derive(Copy, Clone, Default)]
240240
struct TrackedModifiers {
241241
shift: bool,

‎native/src/sbc/devconsole/manager.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ impl DevConsoleManager {
293293
self.interface
294294
.input()
295295
.get_mod_key_state()
296-
.is_ok_and(|bits| bits & (1 << 1) != 0)
296+
.is_ok_and(|(_, ctrl, _, _)| ctrl)
297297
}
298298

299299
fn copy_selection(&self) {

‎native/src/sbc/grass/brushes.rs‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use std::collections::HashSet;
2+
3+
use crate::sbc::command_system::command::Command;
4+
use crate::sbc::grass::commands::terrain_grass_command::{Opts, TerrainGrassCommand};
5+
use crate::sbc::states::state::StateContext;
6+
use crate::sbc::states::{BrushButton, BrushSettings, BrushStamp, MapBrush};
7+
8+
pub(crate) static GRASS: Grass = Grass;
9+
pub(crate) struct Grass;
10+
11+
impl MapBrush for Grass {
12+
fn name(&self) -> &'static str {
13+
"grass"
14+
}
15+
fn initial_delay(&self) -> f32 {
16+
0.0
17+
}
18+
19+
fn prepare(
20+
&self,
21+
brush: &BrushSettings,
22+
uploaded: &mut HashSet<String>,
23+
ctx: &mut StateContext,
24+
) -> bool {
25+
crate::sbc::heightmap::brushes::prepare_pattern(brush, uploaded, ctx)
26+
}
27+
28+
fn command(
29+
&self,
30+
brush: &BrushSettings,
31+
stamp: BrushStamp,
32+
button: BrushButton,
33+
) -> Box<dyn Command> {
34+
Box::new(TerrainGrassCommand::new(Opts {
35+
rotation: stamp.rotation,
36+
x: stamp.x + stamp.size / 2.0,
37+
z: stamp.z + stamp.size / 2.0,
38+
shape_name: brush.pattern_texture.clone().unwrap_or_default(),
39+
amount: if button.is_secondary() { 0.0 } else { 1.0 },
40+
size: stamp.size,
41+
}))
42+
}
43+
}

‎native/src/sbc/grass/mod.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
pub(crate) mod brushes;
12
pub(crate) mod commands;
23
pub(crate) mod jobs;
34
pub(crate) mod ops;

‎native/src/sbc/grass/ui/layout.rs‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
use crate::sbc::panels::brush::BrushAction;
22
use crate::sbc::panels::runtime::Item;
3-
use crate::sbc::states::BrushKind;
43

54
use super::model::GrassField;
65

76
pub(crate) const ACTIONS: &[BrushAction] = &[BrushAction {
87
caption: "Add",
98
image: "LuaUI/images/scenedit/grass-add.png",
10-
kind: BrushKind::Grass,
9+
tool: &crate::sbc::grass::brushes::GRASS,
1110
paint_mode: "",
1211
}];
1312

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
use std::collections::HashSet;
2+
3+
use crate::sbc::command_system::command::Command;
4+
use crate::sbc::heightmap::commands::set_heightmap_brush_command::SetHeightmapBrushCommand;
5+
use crate::sbc::heightmap::commands::terrain_level_command::{
6+
Opts as LevelOpts, TerrainLevelCommand,
7+
};
8+
use crate::sbc::heightmap::commands::terrain_shape_modify_command::{
9+
Opts as ShapeOpts, TerrainShapeModifyCommand,
10+
};
11+
use crate::sbc::heightmap::commands::terrain_smooth_command::{
12+
Opts as SmoothOpts, TerrainSmoothCommand,
13+
};
14+
use crate::sbc::states::shapes::{brush_opts, load_shape};
15+
use crate::sbc::states::state::StateContext;
16+
use crate::sbc::states::{BrushButton, BrushSettings, BrushStamp, MapBrush};
17+
18+
pub(crate) static SHAPE_MODIFY: ShapeModify = ShapeModify;
19+
pub(crate) static LEVEL: Level = Level;
20+
pub(crate) static SMOOTH: Smooth = Smooth;
21+
22+
pub(crate) struct ShapeModify;
23+
pub(crate) struct Level;
24+
pub(crate) struct Smooth;
25+
26+
fn centre(stamp: BrushStamp) -> (f32, f32) {
27+
(stamp.x + stamp.size / 2.0, stamp.z + stamp.size / 2.0)
28+
}
29+
30+
fn signed_strength(brush: &BrushSettings, button: BrushButton) -> f32 {
31+
if button.is_secondary() {
32+
-brush.strength
33+
} else {
34+
brush.strength
35+
}
36+
}
37+
38+
pub(crate) fn prepare_pattern(
39+
brush: &BrushSettings,
40+
uploaded: &mut HashSet<String>,
41+
ctx: &mut StateContext,
42+
) -> bool {
43+
let Some(pattern) = brush.pattern_texture.as_deref() else {
44+
return false;
45+
};
46+
if uploaded.contains(pattern) {
47+
return true;
48+
}
49+
let Some(shape) = load_shape(ctx.interface, pattern) else {
50+
log::warn!("heightmap brush pattern {pattern} could not be loaded");
51+
return false;
52+
};
53+
ctx.command(Box::new(SetHeightmapBrushCommand::new(brush_opts(
54+
pattern, &shape,
55+
))));
56+
uploaded.insert(pattern.to_string());
57+
true
58+
}
59+
60+
impl MapBrush for ShapeModify {
61+
fn name(&self) -> &'static str {
62+
"terrain-shape-modify"
63+
}
64+
65+
fn prepare(
66+
&self,
67+
brush: &BrushSettings,
68+
uploaded: &mut HashSet<String>,
69+
ctx: &mut StateContext,
70+
) -> bool {
71+
prepare_pattern(brush, uploaded, ctx)
72+
}
73+
74+
fn command(
75+
&self,
76+
brush: &BrushSettings,
77+
stamp: BrushStamp,
78+
button: BrushButton,
79+
) -> Box<dyn Command> {
80+
let (x, z) = centre(stamp);
81+
Box::new(TerrainShapeModifyCommand::new(ShapeOpts {
82+
rotation: stamp.rotation,
83+
x,
84+
z,
85+
shape_name: brush.pattern_texture.clone().unwrap_or_default(),
86+
strength: signed_strength(brush, button),
87+
size: stamp.size,
88+
}))
89+
}
90+
}
91+
92+
impl MapBrush for Level {
93+
fn name(&self) -> &'static str {
94+
"terrain-level"
95+
}
96+
97+
fn prepare(
98+
&self,
99+
brush: &BrushSettings,
100+
uploaded: &mut HashSet<String>,
101+
ctx: &mut StateContext,
102+
) -> bool {
103+
prepare_pattern(brush, uploaded, ctx)
104+
}
105+
106+
fn consume_press(&self, brush: &mut BrushSettings, button: BrushButton, height: f32) -> bool {
107+
if button.is_secondary() {
108+
brush.set_height(height);
109+
true
110+
} else {
111+
false
112+
}
113+
}
114+
115+
fn command(
116+
&self,
117+
brush: &BrushSettings,
118+
stamp: BrushStamp,
119+
button: BrushButton,
120+
) -> Box<dyn Command> {
121+
let (x, z) = centre(stamp);
122+
Box::new(TerrainLevelCommand::new(LevelOpts {
123+
rotation: stamp.rotation,
124+
x,
125+
z,
126+
shape_name: brush.pattern_texture.clone().unwrap_or_default(),
127+
strength: signed_strength(brush, button),
128+
size: stamp.size,
129+
height: brush.height,
130+
apply_dir_id: brush.apply_dir.id(),
131+
}))
132+
}
133+
}
134+
135+
impl MapBrush for Smooth {
136+
fn name(&self) -> &'static str {
137+
"terrain-smooth"
138+
}
139+
140+
fn prepare(
141+
&self,
142+
brush: &BrushSettings,
143+
uploaded: &mut HashSet<String>,
144+
ctx: &mut StateContext,
145+
) -> bool {
146+
prepare_pattern(brush, uploaded, ctx)
147+
}
148+
149+
fn command(
150+
&self,
151+
brush: &BrushSettings,
152+
stamp: BrushStamp,
153+
button: BrushButton,
154+
) -> Box<dyn Command> {
155+
let (x, z) = centre(stamp);
156+
let strength = signed_strength(brush, button).abs();
157+
let sigma = (strength.sqrt().sqrt() / 2.0).clamp(0.20, 1.5);
158+
Box::new(TerrainSmoothCommand::new(SmoothOpts {
159+
rotation: stamp.rotation,
160+
x,
161+
z,
162+
shape_name: brush.pattern_texture.clone().unwrap_or_default(),
163+
strength,
164+
size: stamp.size,
165+
sigma,
166+
}))
167+
}
168+
}

‎native/src/sbc/heightmap/mod.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
pub(crate) mod brushes;
12
pub(crate) mod commands;
23
pub(crate) mod jobs;
34
pub(crate) mod model;

‎native/src/sbc/heightmap/ui/layout.rs‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use crate::sbc::panels::brush::BrushAction;
22
use crate::sbc::panels::runtime::Item;
3-
use crate::sbc::states::BrushKind;
43

54
use super::model::TerrainField;
65

@@ -9,19 +8,19 @@ pub(crate) const ACTIONS: &[BrushAction] = &[
98
BrushAction {
109
caption: "Add",
1110
image: "LuaUI/images/scenedit/up-card.png",
12-
kind: BrushKind::ShapeModify,
11+
tool: &crate::sbc::heightmap::brushes::SHAPE_MODIFY,
1312
paint_mode: "",
1413
},
1514
BrushAction {
1615
caption: "Set",
1716
image: "LuaUI/images/scenedit/terrain-set.png",
18-
kind: BrushKind::Level,
17+
tool: &crate::sbc::heightmap::brushes::LEVEL,
1918
paint_mode: "",
2019
},
2120
BrushAction {
2221
caption: "Smooth",
2322
image: "LuaUI/images/scenedit/terrain-smooth.png",
24-
kind: BrushKind::Smooth,
23+
tool: &crate::sbc::heightmap::brushes::SMOOTH,
2524
paint_mode: "",
2625
},
2726
];

‎native/src/sbc/metal/brushes.rs‎

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
use std::collections::HashSet;
2+
3+
use crate::sbc::command_system::command::Command;
4+
use crate::sbc::metal::commands::terrain_metal_command::{Opts, TerrainMetalCommand};
5+
use crate::sbc::states::state::StateContext;
6+
use crate::sbc::states::{BrushButton, BrushSettings, BrushStamp, MapBrush};
7+
8+
pub(crate) static METAL: Metal = Metal;
9+
pub(crate) struct Metal;
10+
11+
impl MapBrush for Metal {
12+
fn name(&self) -> &'static str {
13+
"metal"
14+
}
15+
fn initial_delay(&self) -> f32 {
16+
0.0
17+
}
18+
19+
fn prepare(
20+
&self,
21+
brush: &BrushSettings,
22+
uploaded: &mut HashSet<String>,
23+
ctx: &mut StateContext,
24+
) -> bool {
25+
crate::sbc::heightmap::brushes::prepare_pattern(brush, uploaded, ctx)
26+
}
27+
28+
fn command(
29+
&self,
30+
brush: &BrushSettings,
31+
stamp: BrushStamp,
32+
button: BrushButton,
33+
) -> Box<dyn Command> {
34+
Box::new(TerrainMetalCommand::new(Opts {
35+
rotation: stamp.rotation,
36+
x: stamp.x + stamp.size / 2.0,
37+
z: stamp.z + stamp.size / 2.0,
38+
shape_name: brush.pattern_texture.clone().unwrap_or_default(),
39+
amount: if button.is_secondary() {
40+
0.0
41+
} else {
42+
brush.amount
43+
},
44+
size: stamp.size,
45+
}))
46+
}
47+
}

‎native/src/sbc/metal/mod.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
pub(crate) mod brushes;
12
pub(crate) mod commands;
23
pub(crate) mod jobs;
34
pub(crate) mod ops;

0 commit comments

Comments
 (0)