Make the view transform an operation the photographer can set
FR-DEV-3j gives the view transform two controls, contrast and the white point in stops above middle grey, persisted and held per mask layer like any other setting. A scene-referred pipeline whose white point cannot be moved hands the photographer a shoulder they cannot place. `view_transform` is a hand-written node in `Stage::View`, a new stage the composer emits last and emits whatever the node's state: a neutral operation is otherwise left out of the shader, but a photograph with no view transform is a scan. "Active" keeps meaning "moved from the defaults", so an untouched photograph writes nothing for it and `every_node_starts_neutral` still holds. A caller whose chain holds no view operation gets a default one. The composer's loop becomes an ordered list of steps — camera nodes, the matrix, scene nodes, layer-only nodes, the view — so each is emitted in exactly one place. The base curve could not be a node because it belonged to the camera; the ops README records why that argument went with it (D19). The panel shows it in the Light group as "Tone Mapping". Tests that counted the blocks of a neutral graph now count one, the view transform, and the two chain-wide tests that load a film expect the view transform to be absent, since a stock replaces it.
This commit is contained in:
@@ -1122,13 +1122,21 @@ mod tests {
|
||||
fn a_fresh_graph_is_neutral() {
|
||||
// Opening an unedited image must produce the image, not an
|
||||
// interpretation of it.
|
||||
//
|
||||
// One block, and it is the view transform: a view operation is
|
||||
// composed at its defaults, because a photograph with no view
|
||||
// transform is a scan rather than a picture (FR-DEV-3j). It is still
|
||||
// neutral in the sense that matters here — nothing moved, nothing is
|
||||
// written — and every adjustment is absent.
|
||||
let g = EditGraph::default_chain();
|
||||
assert!(g.is_neutral());
|
||||
let source = g.compose().source;
|
||||
assert_eq!(
|
||||
g.compose().source.matches("---- ").count(),
|
||||
0,
|
||||
"a neutral graph must generate no operation blocks"
|
||||
source.matches("---- ").count(),
|
||||
1,
|
||||
"a neutral graph must generate no adjustment blocks"
|
||||
);
|
||||
assert!(source.contains("---- view_transform ----"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1207,13 +1215,15 @@ mod tests {
|
||||
#[test]
|
||||
fn only_active_operations_reach_the_shader() {
|
||||
// The composition property, end to end: two adjustments out of seven
|
||||
// available must generate a shader doing exactly two things.
|
||||
// available must generate a shader doing exactly two things — and
|
||||
// the view transform, which every render has (FR-DEV-3j).
|
||||
let mut g = EditGraph::default_chain();
|
||||
g.set_param(exposure::ID, exposure::EXPOSURE, 1.0);
|
||||
g.set_param(white_balance::ID, white_balance::TINT, 25.0);
|
||||
|
||||
let shader = g.compose();
|
||||
assert_eq!(shader.source.matches("---- ").count(), 2);
|
||||
assert_eq!(shader.source.matches("---- ").count(), 3);
|
||||
assert!(shader.source.contains("---- view_transform ----"));
|
||||
assert!(shader.source.contains("---- exposure ----"));
|
||||
assert!(shader.source.contains("---- white_balance ----"));
|
||||
assert!(!shader.source.contains("---- saturation ----"));
|
||||
|
||||
Reference in New Issue
Block a user