1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
// 3D colour-grading lookup-table schema.
use crate::{AssetId, PayloadLocator};
use alloc::string::String;
/// A 3D colour-grading lookup table applied as a final post-process step. The
/// build bakes the source into a colour cube; the graded result is blended over
/// the image by [PostProcessConfig](#postprocessconfig)'s `lut_strength`.
///
/// A world declares at most one `ColorLut`; the first wins. When none is
/// present, colour grading is skipped regardless of `lut_strength`.
///
/// Two source formats are accepted, picked by file extension:
/// - `.cube` Adobe Cube LUT (plain-text interchange format).
/// - `.png` A horizontal slice strip: `(n*n)` wide by `n` tall.
///
/// ```rust
/// # use concinnity_asset::ColorLut;
/// ColorLut {
/// source: "luts/cinematic_warm.cube".into(),
/// ..Default::default()
/// };
/// ```
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(default)]
#[derive(Default)]
pub struct ColorLut {
/// Asset identity; injected via `inject_name`. Not part of `args`.
#[serde(skip)]
pub asset_id: AssetId,
/// Path to the source `.cube` or `.png` LUT file.
pub source: String,
/// Injected at load time from the compiled blob payload.
#[serde(skip)]
pub locator: Option<PayloadLocator>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_blank_lut_names_no_source() {
let l = ColorLut::default();
assert!(l.source.is_empty());
assert_eq!(l.asset_id, AssetId::default());
assert!(l.locator.is_none());
}
#[test]
fn the_source_path_is_the_only_authored_field() {
let l: ColorLut = serde_json::from_str(r#"{"source":"grade/warm.cube"}"#).unwrap();
assert_eq!(l.source, "grade/warm.cube");
assert_eq!(
serde_json::to_string(&l).unwrap(),
r#"{"source":"grade/warm.cube"}"#
);
let bytes = postcard::to_allocvec(&l).unwrap();
let back: ColorLut = postcard::from_bytes(&bytes).unwrap();
assert_eq!(back.source, "grade/warm.cube");
assert!(back.locator.is_none());
}
}