Skip to content

Commit 63e6842

Browse files
committed
Add IfVolume stencil enable state for inheritance.
1 parent df1b6e6 commit 63e6842

3 files changed

Lines changed: 94 additions & 23 deletions

File tree

src/computed.rs

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use bevy::{ecs::query::QueryItem, prelude::*, render::view::RenderLayers};
33
use crate::{
44
uniforms::{DepthMode, DrawMode},
55
InheritOutline, OutlineAlphaMask, OutlineMode, OutlinePlaneDepth, OutlineRenderLayers,
6-
OutlineStencil, OutlineVolume, TextureChannel,
6+
OutlineStencil, OutlineStencilEnabled, OutlineVolume, TextureChannel,
77
};
88

99
#[derive(Clone)]
@@ -15,7 +15,7 @@ pub(crate) struct ComputedVolume {
1515

1616
#[derive(Clone)]
1717
pub(crate) struct ComputedStencil {
18-
pub(crate) enabled: bool,
18+
pub(crate) enabled: OutlineStencilEnabled,
1919
pub(crate) offset: f32,
2020
}
2121

@@ -52,12 +52,22 @@ impl<T: Clone> Sourced<T> {
5252
inherit: Option<T>,
5353
f: impl FnOnce(&U) -> T,
5454
) -> Self {
55-
Self::set_with_fallback::<U, U>(value, None, inherit, f)
55+
Self::set_with_fallback::<U, U>(value, None, &U::default(), inherit, f)
5656
}
5757

58-
pub fn set_with_fallback<U: Default, V: Clone + Into<U>>(
58+
pub fn set_with_default<U: Clone + Default>(
59+
value: Option<Ref<U>>,
60+
default: &U,
61+
inherit: Option<T>,
62+
f: impl FnOnce(&U) -> T,
63+
) -> Self {
64+
Self::set_with_fallback::<U, U>(value, None, default, inherit, f)
65+
}
66+
67+
pub fn set_with_fallback<U, V: Clone + Into<U>>(
5968
value: Option<Ref<U>>,
6069
fallback: Option<Ref<V>>,
70+
default: &U,
6171
inherit: Option<T>,
6272
f: impl FnOnce(&U) -> T,
6373
) -> Self {
@@ -78,7 +88,7 @@ impl<T: Clone> Sourced<T> {
7888
}
7989
} else {
8090
Sourced {
81-
value: f(&U::default()),
91+
value: f(default),
8292
source: Source::Default,
8393
}
8494
}
@@ -244,11 +254,16 @@ fn update_computed_outline(
244254
colour: vol.colour.into(),
245255
},
246256
),
247-
stencil: Sourced::set(
257+
stencil: Sourced::set_with_default(
248258
stencil,
259+
&OutlineStencil::INHERIT_DEFAULT,
249260
parent_computed.map(|p| p.stencil.value.clone()),
250261
|sten| ComputedStencil {
251-
enabled: visibility.get() && sten.enabled,
262+
enabled: if visibility.get() {
263+
sten.enabled
264+
} else {
265+
OutlineStencilEnabled::Never
266+
},
252267
offset: sten.offset,
253268
},
254269
),
@@ -304,6 +319,7 @@ fn update_computed_outline(
304319
layers: Sourced::set_with_fallback(
305320
layers,
306321
fallback_layers,
322+
&default(),
307323
parent_computed.map(|p| p.layers.value.clone()),
308324
|layers| layers.0.clone(),
309325
),
@@ -354,7 +370,10 @@ mod tests {
354370
.0
355371
.as_ref()
356372
.expect("ComputedOutline should have Some value after update");
357-
assert!(internal.stencil.value.enabled);
373+
assert_eq!(
374+
internal.stencil.value.enabled,
375+
OutlineStencilEnabled::IfVolume
376+
);
358377
assert!(!internal.volume.value.enabled);
359378

360379
// Update the system again and check that nothing has changed

src/lib.rs

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -121,37 +121,69 @@ pub enum NodeOutline {
121121
EndOutlinePasses,
122122
}
123123

124+
/// Specifies when a stencil should be rendered.
125+
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
126+
#[cfg_attr(feature = "reflect", derive(Reflect))]
127+
#[cfg_attr(feature = "reflect", reflect(Default))]
128+
pub enum OutlineStencilEnabled {
129+
/// Always render a stencil
130+
#[default]
131+
Always,
132+
/// Only render a stencil if the volume is visible
133+
IfVolume,
134+
/// Never render a stencil
135+
Never,
136+
}
137+
138+
impl OutlineStencilEnabled {
139+
pub(crate) fn is_enabled(&self, volume_enabled: bool) -> bool {
140+
match self {
141+
OutlineStencilEnabled::Always => true,
142+
OutlineStencilEnabled::IfVolume => volume_enabled,
143+
OutlineStencilEnabled::Never => false,
144+
}
145+
}
146+
}
147+
124148
/// A component for stenciling meshes during outline rendering.
125149
///
126150
/// Stencils are used both to prevent entities with outlines from being
127151
/// covered by their own outline volumes and to allow entities to occlude
128152
/// any outlines behind them.
129-
#[derive(Clone, Component)]
153+
#[derive(Clone, Component, Default)]
130154
#[cfg_attr(feature = "reflect", derive(Reflect))]
131155
#[cfg_attr(feature = "reflect", reflect(Component, Default))]
132156
pub struct OutlineStencil {
133-
/// Enable rendering of the stencil
134-
pub enabled: bool,
157+
/// Controls when the stencil should be rendered
158+
pub enabled: OutlineStencilEnabled,
135159
/// Offset of the stencil in logical pixels
136160
pub offset: f32,
137161
}
138162

139-
impl Default for OutlineStencil {
140-
fn default() -> Self {
141-
OutlineStencil {
142-
enabled: true,
143-
offset: 0.0,
144-
}
145-
}
163+
impl OutlineStencil {
164+
pub(crate) const INHERIT_DEFAULT: OutlineStencil = OutlineStencil {
165+
enabled: OutlineStencilEnabled::IfVolume,
166+
offset: 0.0,
167+
};
146168
}
147169

148-
fn lerp_bool(this: bool, other: bool, scalar: f32) -> bool {
170+
fn lerp_stencil_enabled(
171+
this: OutlineStencilEnabled,
172+
other: OutlineStencilEnabled,
173+
scalar: f32,
174+
) -> OutlineStencilEnabled {
149175
if scalar <= 0.0 {
150176
this
151177
} else if scalar >= 1.0 {
152178
other
153179
} else {
154-
this | other
180+
match (this, other) {
181+
(OutlineStencilEnabled::Always, _) => OutlineStencilEnabled::Always,
182+
(_, OutlineStencilEnabled::Always) => OutlineStencilEnabled::Always,
183+
(OutlineStencilEnabled::IfVolume, _) => OutlineStencilEnabled::IfVolume,
184+
(_, OutlineStencilEnabled::IfVolume) => OutlineStencilEnabled::Never,
185+
_ => OutlineStencilEnabled::Never,
186+
}
155187
}
156188
}
157189

@@ -176,7 +208,7 @@ macro_rules! impl_lerp {
176208

177209
fn lerp_stencil(start: &OutlineStencil, end: &OutlineStencil, t: f32) -> OutlineStencil {
178210
OutlineStencil {
179-
enabled: lerp_bool(start.enabled, end.enabled, t),
211+
enabled: lerp_stencil_enabled(start.enabled, end.enabled, t),
180212
offset: start.offset.lerp(end.offset, t),
181213
}
182214
}
@@ -196,6 +228,16 @@ pub struct OutlineVolume {
196228
pub colour: Color,
197229
}
198230

231+
fn lerp_bool(this: bool, other: bool, t: f32) -> bool {
232+
if t <= 0.0 {
233+
this
234+
} else if t >= 1.0 {
235+
other
236+
} else {
237+
this || other
238+
}
239+
}
240+
199241
fn lerp_volume(start: &OutlineVolume, end: &OutlineVolume, t: f32) -> OutlineVolume {
200242
OutlineVolume {
201243
visible: lerp_bool(start.visible, end.visible, t),

src/uniforms.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,13 @@ pub(crate) fn set_outline_visibility(
9999
) {
100100
for (entity, mut visibility, computed) in query.iter_mut() {
101101
if let ComputedOutline(Some(computed)) = computed {
102-
if computed.volume.value.enabled || computed.stencil.value.enabled {
102+
if computed.volume.value.enabled
103+
|| computed
104+
.stencil
105+
.value
106+
.enabled
107+
.is_enabled(computed.volume.value.enabled)
108+
{
103109
visibility.set();
104110
previous_visible.remove(&entity);
105111
}
@@ -130,7 +136,11 @@ pub(crate) fn extract_outlines(
130136
continue;
131137
};
132138
let extracted_outline = ExtractedOutline {
133-
stencil: computed.stencil.value.enabled,
139+
stencil: computed
140+
.stencil
141+
.value
142+
.enabled
143+
.is_enabled(computed.volume.value.enabled),
134144
volume: computed.volume.value.enabled,
135145
depth_mode: computed.mode.value.depth_mode,
136146
draw_mode: computed.mode.value.draw_mode,

0 commit comments

Comments
 (0)