Show a mask as soon as it is made
Benchmarks / CPU and I/O (per commit) (push) Successful in 3m52s
Benchmarks / Frame budget (on demand) (push) Skipped
Build and test / Desktop (Linux) (push) Failing after 39m53s
Build and test / Layer separation (push) Successful in 1m0s
🐳 Android image / Build and push (push) Successful in 4s
Build and test / android-image (push) Successful in 4s
Traceability / Requirement traces (push) Successful in 46s
Build and test / Android (aarch64) (push) Successful in 25m19s
Benchmarks / CPU and I/O (per commit) (push) Successful in 3m52s
Benchmarks / Frame budget (on demand) (push) Skipped
Build and test / Desktop (Linux) (push) Failing after 39m53s
Build and test / Layer separation (push) Successful in 1m0s
🐳 Android image / Build and push (push) Successful in 4s
Build and test / android-image (push) Successful in 4s
Traceability / Requirement traces (push) Successful in 46s
Build and test / Android (aarch64) (push) Successful in 25m19s
Choosing a category is asking what it selected, and for a subject or a category that question had no other answer on screen: the model's outline is not derivable from anything visible, a fresh layer carries no adjustment to judge it by, and the list it was chosen from says "architecture 23%" without saying which 23%. The control that draws the mask existed but had to be found and pressed, a panel's height away from the list the choice was made in. So a new layer arrives with its mask showing, from the resting position only. Somebody who has chosen the alpha or the outline keeps it, and nothing re-arms in the background — every caller is a press that asked for a new mask. That makes the canvas depend on how a layer arrived, which is correct and worth stating: a session that has just made a mask draws a frame that a session which read the same mask out of a sidecar does not. Viewing state is not edit state and does not travel in a file, and `a_stored_mask_renders_exactly_what_the_model_rendered` now says so at both ends.
This commit is contained in:
@@ -2523,6 +2523,28 @@ impl DevelopSession {
|
||||
.and_then(|i| RevealStyle::ALL.get(i).copied());
|
||||
}
|
||||
|
||||
/// TRACES: FR-DEV-19c
|
||||
/// Show the mask of a layer that has just been made.
|
||||
///
|
||||
/// **Making a mask is asking what it selected**, and for a subject or a
|
||||
/// category that question has no other answer: the model's outline is not
|
||||
/// derivable from anything on screen, the layer carries no adjustment yet,
|
||||
/// and the list it was chosen from says "architecture 23%" and nothing
|
||||
/// about *which* 23%. So the mask appears with the layer rather than
|
||||
/// waiting to be asked for a second time.
|
||||
///
|
||||
/// Only from the resting position, and only on an explicit action — the
|
||||
/// same rule arming a brush follows. Somebody who has switched to the
|
||||
/// alpha or the outline keeps it, and this never re-arms in the background;
|
||||
/// the trap `Masking.overlay-hidden` documents is an automatic reveal that
|
||||
/// undoes a switch a photographer turned off, and every caller of this is
|
||||
/// a press that asked for a new mask.
|
||||
fn show_new_mask(&mut self) {
|
||||
if self.reveal_style.is_none() {
|
||||
self.reveal_style = Some(dr_pipeline::mask::RevealStyle::Tint);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// The region overlay
|
||||
// ----------------------------------------------------------------------
|
||||
@@ -3356,6 +3378,7 @@ impl DevelopSession {
|
||||
return None;
|
||||
}
|
||||
self.active_masks = vec![id.clone()];
|
||||
self.show_new_mask();
|
||||
self.history
|
||||
.record(&self.graph, Edit::Action(labels::step::MASK_ADDED));
|
||||
Some(id)
|
||||
@@ -3399,6 +3422,7 @@ impl DevelopSession {
|
||||
return None;
|
||||
}
|
||||
self.active_masks = vec![id.clone()];
|
||||
self.show_new_mask();
|
||||
self.history
|
||||
.record(&self.graph, Edit::Action(labels::step::MASK_ADDED));
|
||||
Some(id)
|
||||
@@ -3429,6 +3453,7 @@ impl DevelopSession {
|
||||
return None;
|
||||
}
|
||||
self.active_masks = vec![id.clone()];
|
||||
self.show_new_mask();
|
||||
self.history
|
||||
.record(&self.graph, Edit::Action(labels::step::MASK_ADDED));
|
||||
Some(id)
|
||||
@@ -3460,6 +3485,7 @@ impl DevelopSession {
|
||||
}
|
||||
self.active_masks = vec![id.clone()];
|
||||
self.active_part = 0;
|
||||
self.show_new_mask();
|
||||
self.history
|
||||
.record(&self.graph, Edit::Action(labels::step::MASK_ADDED));
|
||||
Some(id)
|
||||
@@ -3486,6 +3512,7 @@ impl DevelopSession {
|
||||
return None;
|
||||
}
|
||||
self.active_masks = vec![id.clone()];
|
||||
self.show_new_mask();
|
||||
self.history
|
||||
.record(&self.graph, Edit::Action(labels::step::MASK_ADDED));
|
||||
Some(id)
|
||||
@@ -6543,6 +6570,16 @@ mod tests {
|
||||
|
||||
let mut live = session_with_a_left_half_subject(&ctx);
|
||||
let id = live.add_subject_mask(0).expect("a subject layer");
|
||||
// TRACES: FR-DEV-19c
|
||||
// Making a mask shows it (`show_new_mask`), and this test is about the
|
||||
// pixels the *edit* produces. Put away here rather than left on, and
|
||||
// the asymmetry is the point rather than an inconvenience: the reveal
|
||||
// is how somebody is looking at a photograph, so a session that has
|
||||
// just made a layer legitimately draws a frame that a session which
|
||||
// read the same layer out of a file does not. Both of those are
|
||||
// correct, and only one of them is what a stored raster has to
|
||||
// reproduce.
|
||||
live.set_mask_view(0);
|
||||
live.graph
|
||||
.masks_mut()
|
||||
.get_mut(&id)
|
||||
@@ -6569,6 +6606,16 @@ mod tests {
|
||||
"the point: nothing has run a model in this session"
|
||||
);
|
||||
reopened.apply_version(parsed.default_version().expect("a version"));
|
||||
// TRACES: FR-DEV-19c
|
||||
// And a sidecar carries no viewing state: a photograph reopened is not
|
||||
// reopened with its masks tinted red. Checked here because this is the
|
||||
// one test that puts an edit through a file and renders both ends, so
|
||||
// it is where the property would first go wrong.
|
||||
assert_eq!(
|
||||
reopened.mask_view(),
|
||||
0,
|
||||
"restoring an edit must not turn an overlay on"
|
||||
);
|
||||
let from_the_file = read_back(&ctx, &reopened.render(64, 64).expect("render"));
|
||||
|
||||
assert_eq!(
|
||||
|
||||
Reference in New Issue
Block a user