tawasuyu/llimphi
Sovereign retained-mode GPU UI framework in Rust (wgpu+vello+taffy+parley), Elm loop, 40+ widgets.
1// Copyright 2024 the Velato Authors
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4use super::converters::{conv_blend_mode, conv_scalar, conv_shape_geometry, conv_transform};
5use super::defaults::FLOAT_VALUE_ONE_HUNDRED;
6use crate::runtime::model::Layer;
7use crate::schema::helpers::int_boolean::BoolInt;
8use crate::{runtime, schema};
9use peniko::{self, BlendMode, Compose, Mix};
10
11pub struct LayerSetupParams {
12 pub layer_index: usize,
13 pub matte_mode: Option<BlendMode>,
14 pub matte_layer_index: Option<usize>,
15}
16
17pub fn setup_precomp_layer(
18 source: &schema::layers::precomposition::PrecompositionLayer,
19 target: &mut Layer,
20) -> LayerSetupParams {
21 target.name = source
22 .visual_layer
23 .layer
24 .visual_object
25 .name
26 .clone()
27 .unwrap_or_default();
28 target.parent = source.visual_layer.layer.parent_index;
29 let (transform, opacity) = conv_transform(&source.visual_layer.transform);
30 target.transform = transform;
31 target.opacity = opacity;
32 target.width = source.width;
33 target.height = source.height;
34 target.is_mask = source
35 .visual_layer
36 .matte_target
37 .as_ref()
38 .is_some_and(|td| *td == BoolInt::True);
39
40 let matte_mode = source
41 .visual_layer
42 .matte_mode
43 .as_ref()
44 .map(|mode| match mode {
45 schema::constants::matte_mode::MatteMode::Normal => Mix::Normal.into(),
46 schema::constants::matte_mode::MatteMode::Alpha
47 | schema::constants::matte_mode::MatteMode::Luma => Compose::SrcIn.into(),
48 schema::constants::matte_mode::MatteMode::InvertedAlpha
49 | schema::constants::matte_mode::MatteMode::InvertedLuma => Compose::SrcOut.into(),
50 });
51
52 let matte_layer_index = source
53 .visual_layer
54 .matte_layer_index
55 .map(|idx| idx as usize);
56
57 target.blend_mode = conv_blend_mode(
58 source
59 .visual_layer
60 .blend_mode
61 .as_ref()
62 .unwrap_or(&crate::schema::constants::blend_mode::BlendMode::Normal),
63 );
64 if target.blend_mode == Some(peniko::Mix::Normal.into()) {
65 target.blend_mode = None;
66 }
67 target.stretch = source.visual_layer.layer.time_stretch.unwrap_or(1.0);
68 target.frames = source.visual_layer.layer.in_point..source.visual_layer.layer.out_point;
69 target.start_frame = source.visual_layer.layer.start_time.unwrap_or(0.0);
70
71 for mask_source in source
72 .visual_layer
73 .masks_properties
74 .as_ref()
75 .unwrap_or(&Vec::default())
76 {
77 if let Some(shape) = &mask_source.shape
78 && let Some(geometry) = conv_shape_geometry(shape)
79 {
80 let mode = peniko::BlendMode::default();
81 let opacity = conv_scalar(
82 mask_source
83 .opacity
84 .as_ref()
85 .unwrap_or(&FLOAT_VALUE_ONE_HUNDRED),
86 );
87 target.masks.push(runtime::model::Mask {
88 mode,
89 geometry,
90 opacity,
91 });
92 }
93 }
94
95 LayerSetupParams {
96 layer_index: source.visual_layer.layer.index.unwrap_or(0),
97 matte_mode,
98 matte_layer_index,
99 }
100}
101
102pub fn setup_shape_layer(
103 source: &schema::layers::shape::ShapeLayer,
104 target: &mut Layer,
105) -> LayerSetupParams {
106 target.name = source
107 .visual_layer
108 .layer
109 .visual_object
110 .name
111 .clone()
112 .unwrap_or_default();
113 target.parent = source.visual_layer.layer.parent_index;
114 let (transform, opacity) = conv_transform(&source.visual_layer.transform);
115 target.transform = transform;
116 target.opacity = opacity;
117 target.is_mask = source
118 .visual_layer
119 .matte_target
120 .as_ref()
121 .is_some_and(|td| *td == BoolInt::True);
122
123 let matte_mode = source
124 .visual_layer
125 .matte_mode
126 .as_ref()
127 .map(|mode| match mode {
128 schema::constants::matte_mode::MatteMode::Normal => Mix::Normal.into(),
129 schema::constants::matte_mode::MatteMode::Alpha
130 | schema::constants::matte_mode::MatteMode::Luma => Compose::SrcIn.into(),
131 schema::constants::matte_mode::MatteMode::InvertedAlpha
132 | schema::constants::matte_mode::MatteMode::InvertedLuma => Compose::SrcOut.into(),
133 });
134
135 let matte_layer_index = source
136 .visual_layer
137 .matte_layer_index
138 .map(|idx| idx as usize);
139
140 target.blend_mode = conv_blend_mode(
141 source
142 .visual_layer
143 .blend_mode
144 .as_ref()
145 .unwrap_or(&crate::schema::constants::blend_mode::BlendMode::Normal),
146 );
147 if target.blend_mode == Some(peniko::Mix::Normal.into()) {
148 target.blend_mode = None;
149 }
150 target.stretch = source.visual_layer.layer.time_stretch.unwrap_or(1.0);
151 target.frames = source.visual_layer.layer.in_point..source.visual_layer.layer.out_point;
152 target.start_frame = source.visual_layer.layer.start_time.unwrap_or(0.0);
153
154 for mask_source in source
155 .visual_layer
156 .masks_properties
157 .as_ref()
158 .unwrap_or(&Vec::default())
159 {
160 if let Some(shape) = &mask_source.shape
161 && let Some(geometry) = conv_shape_geometry(shape)
162 {
163 let mode = peniko::BlendMode::default();
164 let opacity = conv_scalar(
165 mask_source
166 .opacity
167 .as_ref()
168 .unwrap_or(&FLOAT_VALUE_ONE_HUNDRED),
169 );
170 target.masks.push(runtime::model::Mask {
171 mode,
172 geometry,
173 opacity,
174 });
175 }
176 }
177
178 LayerSetupParams {
179 layer_index: source.visual_layer.layer.index.unwrap_or(0),
180 matte_mode,
181 matte_layer_index,
182 }
183}
184
185pub fn setup_layer_base(
186 source: &schema::layers::visual::VisualLayer,
187 target: &mut Layer,
188) -> LayerSetupParams {
189 target.name = source.layer.visual_object.name.clone().unwrap_or_default();
190 target.parent = source.layer.parent_index;
191 let (transform, opacity) = conv_transform(&source.transform);
192 target.transform = transform;
193 target.opacity = opacity;
194 target.is_mask = source
195 .matte_target
196 .as_ref()
197 .is_some_and(|td| *td == BoolInt::True);
198
199 let matte_mode = source.matte_mode.as_ref().map(|mode| match mode {
200 schema::constants::matte_mode::MatteMode::Normal => Mix::Normal.into(),
201 schema::constants::matte_mode::MatteMode::Alpha
202 | schema::constants::matte_mode::MatteMode::Luma => Compose::SrcIn.into(),
203 schema::constants::matte_mode::MatteMode::InvertedAlpha
204 | schema::constants::matte_mode::MatteMode::InvertedLuma => Compose::SrcOut.into(),
205 });
206
207 let matte_layer_index = source.matte_layer_index.map(|idx| idx as usize);
208
209 target.blend_mode = conv_blend_mode(
210 source
211 .blend_mode
212 .as_ref()
213 .unwrap_or(&crate::schema::constants::blend_mode::BlendMode::Normal),
214 );
215 // TODO: Why do we do this next part?
216 if target.blend_mode == Some(peniko::Mix::Normal.into()) {
217 target.blend_mode = None;
218 }
219 target.stretch = source.layer.time_stretch.unwrap_or(1.0);
220 target.frames = source.layer.in_point..source.layer.out_point;
221 target.start_frame = source.layer.start_time.unwrap_or(0.0);
222
223 for mask_source in source.masks_properties.as_ref().unwrap_or(&Vec::default()) {
224 if let Some(shape) = &mask_source.shape
225 && let Some(geometry) = conv_shape_geometry(shape)
226 {
227 let mode = peniko::BlendMode::default();
228 let opacity = conv_scalar(
229 mask_source
230 .opacity
231 .as_ref()
232 .unwrap_or(&FLOAT_VALUE_ONE_HUNDRED),
233 );
234 target.masks.push(runtime::model::Mask {
235 mode,
236 geometry,
237 opacity,
238 });
239 }
240 }
241
242 LayerSetupParams {
243 layer_index: source.layer.index.unwrap_or(0),
244 matte_mode,
245 matte_layer_index,
246 }
247}