1use crate::bloom::Bloom;
2use crate::chain::{Chain, Pass};
3use crate::color::REC709;
4use crate::comic::ModernComic;
5use crate::fx::{
6 self, Bw, Cel, Comic, Duotone, GradientMap, Halation, Halftone, Neon, Noir, OneBit, Outline,
7 PaperGrain, Pixelate, Scanlines, TiltShift, Watercolor,
8};
9use crate::grade::{Grain, Vignette};
10use crate::tone::Tone;
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13pub enum Style {
14 Cel,
15 Bw,
16 Noir,
17 Vignette,
18 Neon,
19 RubberHose,
20 Sepia,
21 Film,
22 Crt,
23 OneBit,
24 Halftone,
25 Comic,
26 ModernComic,
27 Watercolor,
28 PaperGrain,
29 Pixel,
30 Duotone,
31 GradientMap,
32 Posterize,
33 Kuwahara,
34 TiltShift,
35}
36
37impl Style {
38 pub const ALL: [Self; 21] = [
39 Self::Cel,
40 Self::Bw,
41 Self::Noir,
42 Self::Vignette,
43 Self::Neon,
44 Self::RubberHose,
45 Self::Sepia,
46 Self::Film,
47 Self::Crt,
48 Self::OneBit,
49 Self::Halftone,
50 Self::Comic,
51 Self::ModernComic,
52 Self::Watercolor,
53 Self::PaperGrain,
54 Self::Pixel,
55 Self::Duotone,
56 Self::GradientMap,
57 Self::Posterize,
58 Self::Kuwahara,
59 Self::TiltShift,
60 ];
61
62 pub fn name(self) -> &'static str {
63 match self {
64 Self::Cel => "cel",
65 Self::Bw => "bw",
66 Self::Noir => "noir",
67 Self::Vignette => "vignette",
68 Self::Neon => "neon",
69 Self::RubberHose => "rubber_hose",
70 Self::Sepia => "sepia",
71 Self::Film => "film",
72 Self::Crt => "crt",
73 Self::OneBit => "one_bit",
74 Self::Halftone => "halftone",
75 Self::Comic => "comic",
76 Self::ModernComic => "modern_comic",
77 Self::Watercolor => "watercolor",
78 Self::PaperGrain => "paper_grain",
79 Self::Pixel => "pixel",
80 Self::Duotone => "duotone",
81 Self::GradientMap => "gradient_map",
82 Self::Posterize => "posterize",
83 Self::Kuwahara => "kuwahara",
84 Self::TiltShift => "tilt_shift",
85 }
86 }
87
88 pub fn parse(name: &str) -> Option<Self> {
89 Self::ALL.into_iter().find(|style| style.name() == name)
90 }
91
92 pub fn chain(self) -> Chain {
93 Chain {
94 passes: self.passes(),
95 seed: 0,
96 frame: 0,
97 }
98 }
99
100 fn passes(self) -> Vec<Pass> {
101 match self {
102 Self::Cel => vec![
103 Pass::Exposure(1.5),
104 Pass::Cel(Cel {
105 bands: 3,
106 shadow: 0.62,
107 threshold: 0.45,
108 softness: 0.045,
109 spec: 0.35,
110 spec_roughness: 0.25,
111 spec_threshold: 0.72,
112 light: [0.3, 0.75, 0.6],
113 }),
114 Pass::Cavity(fx::Cavity {
115 strength: 0.35,
116 distance: 2.0,
117 }),
118 Pass::Rim(fx::Rim {
119 strength: 0.3,
120 width: 0.18,
121 color: [0.62, 0.82, 1.0],
122 }),
123 Pass::Outline(Outline {
124 enabled: true,
125 thickness: 1.25,
126 color: [0.02, 0.015, 0.02],
127 local_color: true,
128 alpha: 0.92,
129 crease_angle: 35.0,
130 depth_gap: 0.003,
131 }),
132 ],
133 Self::Bw => vec![Pass::Bw(Bw { weights: REC709 })],
134 Self::Noir => vec![
135 Pass::Noir(Noir {
136 contrast: 1.9,
137 crush: 0.18,
138 keep: None,
139 keep_range: 0.45,
140 }),
141 Pass::Grain(Grain {
142 strength: 0.07,
143 response: 0.45,
144 clamp: false,
145 }),
146 Pass::Vignette(Vignette::power(0.62, 2.4, 0.8, 1.28)),
147 ],
148 Self::Vignette => vec![Pass::Vignette(Vignette::power(0.55, 2.4, 0.8, 1.28))],
149 Self::Neon => vec![
150 Pass::Neon(Neon {
151 saturation: 1.8,
152 strength: 1.35,
153 radius: 3,
154 }),
155 Pass::Bloom(Bloom {
156 linear_taps: false,
157 ..Bloom::pyramid(0.85, 0.55, 0.4, 0.3, 0.2, 5, 10.0, 4)
158 }),
159 ],
160 Self::RubberHose => vec![Pass::RubberHose],
161 Self::Sepia => vec![Pass::Sepia(1.0)],
162 Self::Film => vec![
163 Pass::Distortion(0.045),
164 Pass::Aberration(0.85),
165 Pass::Halation(Halation {
166 strength: 0.4,
167 threshold: 0.65,
168 radius: 6,
169 }),
170 Pass::Tone(Tone::aces()),
171 Pass::Sepia(0.18),
172 Pass::Grain(Grain {
173 strength: 0.03,
174 response: 0.5,
175 clamp: true,
176 }),
177 Pass::Vignette(Vignette::smoothstep(0.3, 0.72, 0.28, 0.8)),
178 ],
179 Self::Crt => vec![
180 Pass::Curvature(0.12),
181 Pass::Aberration(0.65),
182 Pass::Bloom(Bloom::pyramid(0.2, 0.9, 0.7, 0.6, 0.15, 12, 50.0, 2)),
183 Pass::Scanlines(Scanlines {
184 strength: 0.38,
185 period: 2,
186 }),
187 Pass::Aperture(0.45),
188 Pass::Vignette(Vignette::power(0.4, 2.4, 0.8, 1.28)),
189 ],
190 Self::OneBit => vec![Pass::OneBit(OneBit {
191 kind: fx::NoiseKind::Blue,
192 })],
193 Self::Halftone => vec![Pass::Halftone(Halftone {
194 cell: 6.0,
195 angle: 15.0,
196 ink: [0.02, 0.02, 0.03],
197 })],
198 Self::Comic => vec![Pass::Comic(Comic {
199 levels: 5,
200 ink: 0.9,
201 })],
202 Self::ModernComic => vec![Pass::ModernComic(ModernComic::default())],
203 Self::Watercolor => vec![Pass::Watercolor(Watercolor {
204 darkening: 0.65,
205 grain: 0.22,
206 scale: 6.0,
207 })],
208 Self::PaperGrain => vec![Pass::PaperGrain(PaperGrain {
209 strength: 0.28,
210 scale: 5.0,
211 })],
212 Self::Pixel => vec![Pass::Pixel(Pixelate {
213 size: 4,
214 levels: 0,
215 palette: true,
216 })],
217 Self::Duotone => vec![Pass::Duotone(Duotone {
218 shadow: [0.05, 0.08, 0.18],
219 highlight: [0.96, 0.82, 0.55],
220 })],
221 Self::GradientMap => vec![Pass::GradientMap(GradientMap {
222 stops: [
223 [0.04, 0.02, 0.05, 0.0],
224 [0.42, 0.16, 0.10, 0.35],
225 [0.86, 0.52, 0.28, 0.7],
226 [0.96, 0.90, 0.78, 1.0],
227 ],
228 count: 4,
229 })],
230 Self::Posterize => vec![Pass::Posterize(5.0)],
231 Self::Kuwahara => vec![Pass::Kuwahara(2)],
232 Self::TiltShift => vec![Pass::TiltShift(TiltShift {
233 focus: 0.5,
234 range: 0.22,
235 radius: 5.0,
236 })],
237 }
238 }
239}
240
241pub fn names() -> &'static [&'static str] {
242 &[
243 "cel",
244 "bw",
245 "noir",
246 "vignette",
247 "neon",
248 "rubber_hose",
249 "sepia",
250 "film",
251 "crt",
252 "one_bit",
253 "halftone",
254 "comic",
255 "modern_comic",
256 "watercolor",
257 "paper_grain",
258 "pixel",
259 "duotone",
260 "gradient_map",
261 "posterize",
262 "kuwahara",
263 "tilt_shift",
264 ]
265}