Skip to main content

vk_graph_fx/
transition.rs

1// Adapted from https://github.com/gl-transitions/gl-transitions
2// NOTE: Some are rough or broken and need a bit of care - others should be optimized for production
3// use
4
5use {
6    log::trace,
7    std::collections::HashMap,
8    vk_graph::{
9        Graph,
10        driver::{
11            ash::vk,
12            compute::{ComputePipeline, ComputePipelineInfo},
13            device::Device,
14            image::ImageInfo,
15            shader::Shader,
16            sync::AccessType,
17        },
18        node::{AnyImageNode, ImageLeaseNode},
19        pool::{Pool as _, hash::HashPool},
20    },
21    vk_shader_macros::include_glsl,
22};
23
24#[allow(missing_docs)]
25#[derive(Clone, Copy, Debug)]
26pub enum Transition {
27    Angular {
28        starting_angle: f32,
29    },
30    Bounce {
31        shadow_height: f32,
32        bounces: f32,
33        shadow_colour: [f32; 4],
34    },
35    BowTieHorizontal,
36    BowTieVertical,
37    BowTieWithParameter {
38        adjust: f32,
39        reverse: bool,
40    },
41    Burn {
42        color: [f32; 3],
43    },
44    ButterflyWaveScrawler {
45        amplitude: f32,
46        waves: f32,
47        color_separation: f32,
48    },
49    CannabisLeaf,
50    Circle {
51        center: [f32; 2],
52        background_color: [f32; 3],
53    },
54    CircleCrop {
55        background_color: [f32; 4],
56    },
57    CircleOpen {
58        smoothness: f32,
59        opening: bool,
60    },
61    ColorDistance {
62        power: f32,
63    },
64    ColorPhase {
65        from_step: [f32; 4],
66        to_step: [f32; 4],
67    },
68    CoordFromIn,
69    CrazyParametricFun {
70        a: f32,
71        b: f32,
72        amplitude: f32,
73        smoothness: f32,
74    },
75    Crosshatch {
76        center: [f32; 2],
77        threshold: f32,
78        fade_edge: f32,
79    },
80    CrossWarp,
81    CrossZoom {
82        strength: f32,
83    },
84    Cube {
85        perspective: f32,
86        unzoom: f32,
87        reflection: f32,
88        floating: f32,
89    },
90    Directional {
91        direction: [f32; 2],
92    },
93    DirectionalEasing {
94        direction: [f32; 2],
95    },
96    DirectionalWarp {
97        direction: [f32; 2],
98    },
99    DirectionalWipe {
100        smoothness: f32,
101        direction: [f32; 2],
102    },
103    Displacement {
104        displacement_map: AnyImageNode,
105        strength: f32,
106    },
107    DoomScreen {
108        /// Number of total bars/columns
109        bars: i32,
110
111        /// Multiplier for speed ratio. 0 = no variation when going down, higher = some elements go
112        /// much faster
113        amplitude: f32,
114
115        /// Further variations in speed. 0 = no noise, 1 = super noisy (ignore frequency)
116        noise: f32,
117
118        /// Speed variation horizontally. the bigger the value, the shorter the waves
119        frequency: f32,
120
121        /// How much the bars seem to "run" from the middle of the screen first (sticking to the
122        /// sides). 0 = no drip, 1 = curved drip
123        drip_scale: f32,
124    },
125    Doorway {
126        reflection: f32,
127        perspective: f32,
128        depth: f32,
129    },
130    Dreamy,
131    DreamyZoom {
132        /// In degrees
133        rotation: f32,
134
135        /// Multiplier
136        scale: f32,
137    },
138    FadeColor {
139        /// if 0.0, there is no black phase, if 0.9, the black phase is very important
140        color_phase: f32,
141
142        color: [f32; 3],
143    },
144    Fade,
145    FadeGrayscale {
146        /// If `0.0`, the image turns grayscale directly; if `0.9`, the grayscale transition phase
147        /// is very important.
148        intensity: f32,
149    },
150    FilmBurn {
151        seed: f32,
152    },
153    Flyeye {
154        size: f32,
155        zoom: f32,
156        color_separation: f32,
157    },
158    GlitchDisplace,
159    GlitchMemories,
160    GridFlip {
161        pause: f32,
162        size: [i32; 2],
163        background_color: [f32; 4],
164        divider_width: f32,
165        randomness: f32,
166    },
167    Heart,
168    Hexagonalize {
169        steps: i32,
170        horizontal_hexagons: f32,
171    },
172    InvertedPageCurl,
173    Kaleidoscope {
174        speed: f32,
175        angle: f32,
176        power: f32,
177    },
178    LeftRight,
179    LinearBlur {
180        intensity: f32,
181    },
182    Luma {
183        luma_map: AnyImageNode,
184    },
185    LuminanceMelt {
186        /// Direction of movement: `false` for up, `true` for down.
187        direction: bool,
188
189        /// Luminance threshold.
190        threshold: f32,
191
192        /// Whether movement takes effect above or below the luminance threshold.
193        above: bool,
194    },
195    Morph {
196        strength: f32,
197    },
198    Mosaic {
199        end: [i32; 2],
200    },
201    Multiply,
202    Overexposure {
203        strength: f32,
204    },
205    Perlin {
206        scale: f32,
207        smoothness: f32,
208        seed: f32,
209    },
210    Pinwheel {
211        speed: f32,
212    },
213    Pixelize {
214        /// Zero disables stepping
215        steps: i32,
216
217        /// Minimum number of squares (when the effect is at its higher level)
218        squares_min: [i32; 2],
219    },
220    PolarFunction {
221        segments: i32,
222    },
223    PolkaDotsCurtain {
224        dots: f32,
225        center: [f32; 2],
226    },
227    PowerKaleido {
228        scale: f32,
229        z: f32,
230        speed: f32,
231    },
232    Radial {
233        smoothness: f32,
234    },
235    RandomNoisex,
236    RandomSquares {
237        smoothness: f32,
238        size: [i32; 2],
239    },
240    Ripple {
241        amplitude: f32,
242        speed: f32,
243    },
244    Rotate,
245    RotateScale {
246        rotations: f32,
247        center: [f32; 2],
248        background_color: [f32; 4],
249        scale: f32,
250    },
251    ScaleIn,
252    SimpleZoom {
253        zoom_quickness: f32,
254    },
255    SquaresWire {
256        smoothness: f32,
257        squares: [i32; 2],
258        direction: [f32; 2],
259    },
260    Squeeze {
261        color_separation: f32,
262    },
263    StereoViewer {
264        /// How much to zoom (out) for the effect ~ 0.5 - 1.0
265        zoom: f32,
266
267        /// Corner radius as a fraction of the image height
268        corner_radius: f32,
269    },
270    Swap {
271        reflection: f32,
272        perspective: f32,
273        depth: f32,
274    },
275    Swirl,
276    TangentMotionBlur,
277    TopBottom,
278    TvStatic {
279        offset: f32,
280    },
281    UndulatingBurnOut {
282        smoothness: f32,
283        center: [f32; 2],
284        color: [f32; 3],
285    },
286    WaterDrop {
287        amplitude: f32,
288        speed: f32,
289    },
290    Wind {
291        size: f32,
292    },
293    WindowBlinds,
294    WindowSlice {
295        count: f32,
296        smoothness: f32,
297    },
298    WipeDown,
299    WipeLeft,
300    WipeRight,
301    WipeUp,
302    ZoomInCircles,
303    ZoomLeftWipe {
304        zoom_quickness: f32,
305    },
306    ZoomRightWipe {
307        zoom_quickness: f32,
308    },
309}
310
311impl Transition {
312    fn ty(&self) -> TransitionType {
313        match self {
314            Self::Angular { .. } => TransitionType::Angular,
315            Self::Bounce { .. } => TransitionType::Bounce,
316            Self::BowTieHorizontal => TransitionType::BowTieHorizontal,
317            Self::BowTieVertical => TransitionType::BowTieVertical,
318            Self::BowTieWithParameter { .. } => TransitionType::BowTieWithParameter,
319            Self::Burn { .. } => TransitionType::Burn,
320            Self::ButterflyWaveScrawler { .. } => TransitionType::ButterflyWaveScrawler,
321            Self::CannabisLeaf { .. } => TransitionType::CannabisLeaf,
322            Self::Circle { .. } => TransitionType::Circle,
323            Self::CircleCrop { .. } => TransitionType::CircleCrop,
324            Self::CircleOpen { .. } => TransitionType::CircleOpen,
325            Self::ColorDistance { .. } => TransitionType::ColorDistance,
326            Self::ColorPhase { .. } => TransitionType::ColorPhase,
327            Self::CoordFromIn => TransitionType::CoordFromIn,
328            Self::CrazyParametricFun { .. } => TransitionType::CrazyParametricFun,
329            Self::Crosshatch { .. } => TransitionType::Crosshatch,
330            Self::CrossWarp => TransitionType::CrossWarp,
331            Self::CrossZoom { .. } => TransitionType::CrossZoom,
332            Self::Cube { .. } => TransitionType::Cube,
333            Self::Directional { .. } => TransitionType::Directional,
334            Self::DirectionalEasing { .. } => TransitionType::DirectionalEasing,
335            Self::DirectionalWarp { .. } => TransitionType::DirectionalWarp,
336            Self::DirectionalWipe { .. } => TransitionType::DirectionalWipe,
337            Self::Displacement { .. } => TransitionType::Displacement,
338            Self::DoomScreen { .. } => TransitionType::DoomScreen,
339            Self::Doorway { .. } => TransitionType::Doorway,
340            Self::Dreamy => TransitionType::Dreamy,
341            Self::DreamyZoom { .. } => TransitionType::DreamyZoom,
342            Self::FadeColor { .. } => TransitionType::FadeColor,
343            Self::Fade => TransitionType::Fade,
344            Self::FadeGrayscale { .. } => TransitionType::FadeGrayscale,
345            Self::FilmBurn { .. } => TransitionType::FilmBurn,
346            Self::Flyeye { .. } => TransitionType::Flyeye,
347            Self::GlitchDisplace => TransitionType::GlitchDisplace,
348            Self::GlitchMemories => TransitionType::GlitchMemories,
349            Self::GridFlip { .. } => TransitionType::GridFlip,
350            Self::Heart => TransitionType::Heart,
351            Self::Hexagonalize { .. } => TransitionType::Hexagonalize,
352            Self::InvertedPageCurl => TransitionType::InvertedPageCurl,
353            Self::Kaleidoscope { .. } => TransitionType::Kaleidoscope,
354            Self::LeftRight => TransitionType::LeftRight,
355            Self::LinearBlur { .. } => TransitionType::LinearBlur,
356            Self::Luma { .. } => TransitionType::Luma,
357            Self::LuminanceMelt { .. } => TransitionType::LuminanceMelt,
358            Self::Morph { .. } => TransitionType::Morph,
359            Self::Mosaic { .. } => TransitionType::Mosaic,
360            Self::Multiply => TransitionType::Multiply,
361            Self::Overexposure { .. } => TransitionType::Overexposure,
362            Self::Perlin { .. } => TransitionType::Perlin,
363            Self::Pinwheel { .. } => TransitionType::Pinwheel,
364            Self::Pixelize { .. } => TransitionType::Pixelize,
365            Self::PolarFunction { .. } => TransitionType::PolarFunction,
366            Self::PolkaDotsCurtain { .. } => TransitionType::PolkaDotsCurtain,
367            Self::PowerKaleido { .. } => TransitionType::PowerKaleido,
368            Self::Radial { .. } => TransitionType::Radial,
369            Self::RandomNoisex => TransitionType::RandomNoisex,
370            Self::RandomSquares { .. } => TransitionType::RandomSquares,
371            Self::Ripple { .. } => TransitionType::Ripple,
372            Self::Rotate => TransitionType::Rotate,
373            Self::RotateScale { .. } => TransitionType::RotateScale,
374            Self::ScaleIn => TransitionType::ScaleIn,
375            Self::SimpleZoom { .. } => TransitionType::SimpleZoom,
376            Self::SquaresWire { .. } => TransitionType::SquaresWire,
377            Self::Squeeze { .. } => TransitionType::Squeeze,
378            Self::StereoViewer { .. } => TransitionType::StereoViewer,
379            Self::Swap { .. } => TransitionType::Swap,
380            Self::Swirl => TransitionType::Swirl,
381            Self::TangentMotionBlur => TransitionType::TangentMotionBlur,
382            Self::TopBottom => TransitionType::TopBottom,
383            Self::TvStatic { .. } => TransitionType::TvStatic,
384            Self::UndulatingBurnOut { .. } => TransitionType::UndulatingBurnOut,
385            Self::WaterDrop { .. } => TransitionType::WaterDrop,
386            Self::Wind { .. } => TransitionType::Wind,
387            Self::WindowBlinds => TransitionType::WindowBlinds,
388            Self::WindowSlice { .. } => TransitionType::WindowSlice,
389            Self::WipeDown => TransitionType::WipeDown,
390            Self::WipeLeft => TransitionType::WipeLeft,
391            Self::WipeRight => TransitionType::WipeRight,
392            Self::WipeUp => TransitionType::WipeUp,
393            Self::ZoomInCircles => TransitionType::ZoomInCircles,
394            Self::ZoomLeftWipe { .. } => TransitionType::ZoomLeftWipe,
395            Self::ZoomRightWipe { .. } => TransitionType::ZoomRightWipe,
396        }
397    }
398}
399
400/// Cache and lazily create transition compute pipelines on demand.
401pub struct TransitionPipeline {
402    cache: HashPool,
403    pipelines: HashMap<TransitionType, ComputePipeline>,
404}
405
406impl TransitionPipeline {
407    /// Creates an empty transition pipeline cache for the given device.
408    pub fn new(device: &Device) -> Self {
409        let cache = HashPool::new(device);
410        let pipelines = Default::default();
411
412        Self { cache, pipelines }
413    }
414
415    /// Applies a transition between two images and returns a pooled destination image.
416    pub fn apply(
417        &mut self,
418        graph: &mut Graph,
419        a_image: impl Into<AnyImageNode>,
420        b_image: impl Into<AnyImageNode>,
421        transition: Transition,
422        progress: f32,
423    ) -> ImageLeaseNode {
424        let a_image = a_image.into();
425        let b_image = b_image.into();
426
427        let a_info = graph.resource(a_image).info;
428        let b_info = graph.resource(b_image).info;
429
430        let dest_info = ImageInfo::image_2d(
431            a_info.width.max(b_info.width),
432            a_info.height.max(b_info.height),
433            vk::Format::R8G8B8A8_UNORM,
434            vk::ImageUsageFlags::SAMPLED
435                | vk::ImageUsageFlags::STORAGE
436                | vk::ImageUsageFlags::TRANSFER_DST
437                | vk::ImageUsageFlags::TRANSFER_SRC,
438        );
439        let dest_image = graph.bind_resource(
440            self.cache
441                .resource(dest_info)
442                .expect("missing transition image"),
443        );
444
445        self.apply_to(graph, a_image, b_image, dest_image, transition, progress);
446
447        dest_image
448    }
449
450    /// Applies a transition between two images into an existing destination image.
451    pub fn apply_to(
452        &mut self,
453        graph: &mut Graph,
454        a_image: impl Into<AnyImageNode>,
455        b_image: impl Into<AnyImageNode>,
456        dest_image: impl Into<AnyImageNode>,
457        transition: Transition,
458        progress: f32,
459    ) {
460        let a_image = a_image.into();
461        let b_image = b_image.into();
462        let dest_image = dest_image.into();
463        let progress = progress.clamp(0.0, 1.0);
464
465        let dest_info = graph.resource(dest_image).info;
466
467        // Lazy-initialize the compute pipeline for this transition
468        let transition_ty = transition.ty();
469        let pipeline = self.pipeline(transition_ty);
470
471        let mut push_consts = Vec::with_capacity(128);
472        push_consts.extend_from_slice(&progress.to_ne_bytes());
473
474        extend_push_constants(transition, &mut push_consts);
475
476        graph
477            .begin_cmd()
478            .debug_name(format!("transition {transition_ty:?}"))
479            .bind_pipeline(pipeline)
480            .shader_resource_access(0, a_image, AccessType::ComputeShaderReadOther)
481            .shader_resource_access(1, b_image, AccessType::ComputeShaderReadOther)
482            .shader_resource_access(2, dest_image, AccessType::ComputeShaderWrite)
483            .record_cmd(move |cmd| {
484                cmd.push_constants(0, &push_consts)
485                    .dispatch(dest_info.width, dest_info.height, 1);
486            });
487    }
488
489    fn pipeline(&mut self, transition_ty: TransitionType) -> &ComputePipeline {
490        self.pipelines.entry(transition_ty).or_insert_with(|| {
491            trace!("creating {transition_ty:?}");
492
493            ComputePipeline::create(
494                &self.cache.device,
495                ComputePipelineInfo::default(),
496                Shader::new_compute(match transition_ty {
497                    TransitionType::Angular => {
498                        include_glsl!("res/shader/transition/angular.comp").as_slice()
499                    }
500                    TransitionType::Bounce => {
501                        include_glsl!("res/shader/transition/bounce.comp").as_slice()
502                    }
503                    TransitionType::BowTieHorizontal => {
504                        include_glsl!("res/shader/transition/bow_tie_horizontal.comp").as_slice()
505                    }
506                    TransitionType::BowTieVertical => {
507                        include_glsl!("res/shader/transition/bow_tie_vertical.comp").as_slice()
508                    }
509                    TransitionType::BowTieWithParameter => {
510                        include_glsl!("res/shader/transition/bow_tie_with_parameter.comp",)
511                            .as_slice()
512                    }
513                    TransitionType::Burn => {
514                        include_glsl!("res/shader/transition/burn.comp").as_slice()
515                    }
516                    TransitionType::ButterflyWaveScrawler => {
517                        include_glsl!("res/shader/transition/butterfly_wave_scrawler.comp",)
518                            .as_slice()
519                    }
520                    TransitionType::CannabisLeaf => {
521                        include_glsl!("res/shader/transition/cannabis_leaf.comp").as_slice()
522                    }
523                    TransitionType::Circle => {
524                        include_glsl!("res/shader/transition/circle.comp").as_slice()
525                    }
526                    TransitionType::CircleCrop => {
527                        include_glsl!("res/shader/transition/circle_crop.comp").as_slice()
528                    }
529                    TransitionType::CircleOpen => {
530                        include_glsl!("res/shader/transition/circle_open.comp").as_slice()
531                    }
532                    TransitionType::ColorDistance => {
533                        include_glsl!("res/shader/transition/color_distance.comp").as_slice()
534                    }
535                    TransitionType::ColorPhase => {
536                        include_glsl!("res/shader/transition/color_phase.comp").as_slice()
537                    }
538                    TransitionType::CoordFromIn => {
539                        include_glsl!("res/shader/transition/coord_from_in.comp").as_slice()
540                    }
541                    TransitionType::CrazyParametricFun => {
542                        include_glsl!("res/shader/transition/crazy_parametric_fun.comp").as_slice()
543                    }
544                    TransitionType::Crosshatch => {
545                        include_glsl!("res/shader/transition/crosshatch.comp").as_slice()
546                    }
547                    TransitionType::CrossWarp => {
548                        include_glsl!("res/shader/transition/cross_warp.comp").as_slice()
549                    }
550                    TransitionType::CrossZoom => {
551                        include_glsl!("res/shader/transition/cross_zoom.comp").as_slice()
552                    }
553                    TransitionType::Cube => {
554                        include_glsl!("res/shader/transition/cube.comp").as_slice()
555                    }
556                    TransitionType::Directional => {
557                        include_glsl!("res/shader/transition/directional.comp").as_slice()
558                    }
559                    TransitionType::DirectionalEasing => {
560                        include_glsl!("res/shader/transition/directional_easing.comp").as_slice()
561                    }
562                    TransitionType::DirectionalWarp => {
563                        include_glsl!("res/shader/transition/directional_warp.comp").as_slice()
564                    }
565                    TransitionType::DirectionalWipe => {
566                        include_glsl!("res/shader/transition/directional_wipe.comp").as_slice()
567                    }
568                    TransitionType::Displacement => {
569                        include_glsl!("res/shader/transition/displacement.comp").as_slice()
570                    }
571                    TransitionType::DoomScreen => {
572                        include_glsl!("res/shader/transition/doom_screen.comp").as_slice()
573                    }
574                    TransitionType::Doorway => {
575                        include_glsl!("res/shader/transition/doorway.comp").as_slice()
576                    }
577                    TransitionType::Dreamy => {
578                        include_glsl!("res/shader/transition/dreamy.comp").as_slice()
579                    }
580                    TransitionType::DreamyZoom => {
581                        include_glsl!("res/shader/transition/dreamy_zoom.comp").as_slice()
582                    }
583                    TransitionType::FadeColor => {
584                        include_glsl!("res/shader/transition/fade_color.comp").as_slice()
585                    }
586                    TransitionType::Fade => {
587                        include_glsl!("res/shader/transition/fade.comp").as_slice()
588                    }
589                    TransitionType::FadeGrayscale => {
590                        include_glsl!("res/shader/transition/fade_grayscale.comp").as_slice()
591                    }
592                    TransitionType::FilmBurn => {
593                        include_glsl!("res/shader/transition/film_burn.comp").as_slice()
594                    }
595                    TransitionType::Flyeye => {
596                        include_glsl!("res/shader/transition/flyeye.comp").as_slice()
597                    }
598                    TransitionType::GlitchDisplace => {
599                        include_glsl!("res/shader/transition/glitch_displace.comp").as_slice()
600                    }
601                    TransitionType::GlitchMemories => {
602                        include_glsl!("res/shader/transition/glitch_memories.comp").as_slice()
603                    }
604                    TransitionType::GridFlip => {
605                        include_glsl!("res/shader/transition/grid_flip.comp").as_slice()
606                    }
607                    TransitionType::Heart => {
608                        include_glsl!("res/shader/transition/heart.comp").as_slice()
609                    }
610                    TransitionType::Hexagonalize => {
611                        include_glsl!("res/shader/transition/hexagonalize.comp").as_slice()
612                    }
613                    TransitionType::InvertedPageCurl => {
614                        include_glsl!("res/shader/transition/inverted_page_curl.comp").as_slice()
615                    }
616                    TransitionType::Kaleidoscope => {
617                        include_glsl!("res/shader/transition/kaleidoscope.comp").as_slice()
618                    }
619                    TransitionType::LeftRight => {
620                        include_glsl!("res/shader/transition/left_right.comp").as_slice()
621                    }
622                    TransitionType::LinearBlur => {
623                        include_glsl!("res/shader/transition/linear_blur.comp").as_slice()
624                    }
625                    TransitionType::Luma => {
626                        include_glsl!("res/shader/transition/luma.comp").as_slice()
627                    }
628                    TransitionType::LuminanceMelt => {
629                        include_glsl!("res/shader/transition/luminance_melt.comp").as_slice()
630                    }
631                    TransitionType::Morph => {
632                        include_glsl!("res/shader/transition/morph.comp").as_slice()
633                    }
634                    TransitionType::Mosaic => {
635                        include_glsl!("res/shader/transition/mosaic.comp").as_slice()
636                    }
637                    TransitionType::Multiply => {
638                        include_glsl!("res/shader/transition/multiply.comp").as_slice()
639                    }
640                    TransitionType::Overexposure => {
641                        include_glsl!("res/shader/transition/overexposure.comp").as_slice()
642                    }
643                    TransitionType::Perlin => {
644                        include_glsl!("res/shader/transition/perlin.comp").as_slice()
645                    }
646                    TransitionType::Pinwheel => {
647                        include_glsl!("res/shader/transition/pinwheel.comp").as_slice()
648                    }
649                    TransitionType::Pixelize => {
650                        include_glsl!("res/shader/transition/pixelize.comp").as_slice()
651                    }
652                    TransitionType::PolarFunction => {
653                        include_glsl!("res/shader/transition/polar_function.comp").as_slice()
654                    }
655                    TransitionType::PolkaDotsCurtain => {
656                        include_glsl!("res/shader/transition/polka_dots_curtain.comp").as_slice()
657                    }
658                    TransitionType::PowerKaleido => {
659                        include_glsl!("res/shader/transition/power_kaleido.comp").as_slice()
660                    }
661                    TransitionType::Radial => {
662                        include_glsl!("res/shader/transition/radial.comp").as_slice()
663                    }
664                    TransitionType::RandomNoisex => {
665                        include_glsl!("res/shader/transition/random_noisex.comp").as_slice()
666                    }
667                    TransitionType::RandomSquares => {
668                        include_glsl!("res/shader/transition/random_squares.comp").as_slice()
669                    }
670                    TransitionType::Ripple => {
671                        include_glsl!("res/shader/transition/ripple.comp").as_slice()
672                    }
673                    TransitionType::Rotate => {
674                        include_glsl!("res/shader/transition/rotate.comp").as_slice()
675                    }
676                    TransitionType::RotateScale => {
677                        include_glsl!("res/shader/transition/rotate_scale.comp").as_slice()
678                    }
679                    TransitionType::ScaleIn => {
680                        include_glsl!("res/shader/transition/scale_in.comp").as_slice()
681                    }
682                    TransitionType::SimpleZoom => {
683                        include_glsl!("res/shader/transition/simple_zoom.comp").as_slice()
684                    }
685                    TransitionType::SquaresWire => {
686                        include_glsl!("res/shader/transition/squares_wire.comp").as_slice()
687                    }
688                    TransitionType::Squeeze => {
689                        include_glsl!("res/shader/transition/squeeze.comp").as_slice()
690                    }
691                    TransitionType::StereoViewer => {
692                        include_glsl!("res/shader/transition/stereo_viewer.comp").as_slice()
693                    }
694                    TransitionType::Swap => {
695                        include_glsl!("res/shader/transition/swap.comp").as_slice()
696                    }
697                    TransitionType::Swirl => {
698                        include_glsl!("res/shader/transition/swirl.comp").as_slice()
699                    }
700                    TransitionType::TangentMotionBlur => {
701                        include_glsl!("res/shader/transition/tangent_motion_blur.comp").as_slice()
702                    }
703                    TransitionType::TopBottom => {
704                        include_glsl!("res/shader/transition/top_bottom.comp").as_slice()
705                    }
706                    TransitionType::TvStatic => {
707                        include_glsl!("res/shader/transition/tv_static.comp").as_slice()
708                    }
709                    TransitionType::UndulatingBurnOut => {
710                        include_glsl!("res/shader/transition/undulating_burn_out.comp").as_slice()
711                    }
712                    TransitionType::WaterDrop => {
713                        include_glsl!("res/shader/transition/water_drop.comp").as_slice()
714                    }
715                    TransitionType::Wind => {
716                        include_glsl!("res/shader/transition/wind.comp").as_slice()
717                    }
718                    TransitionType::WindowBlinds => {
719                        include_glsl!("res/shader/transition/window_blinds.comp").as_slice()
720                    }
721                    TransitionType::WindowSlice => {
722                        include_glsl!("res/shader/transition/window_slice.comp").as_slice()
723                    }
724                    TransitionType::WipeDown => {
725                        include_glsl!("res/shader/transition/wipe_down.comp").as_slice()
726                    }
727                    TransitionType::WipeLeft => {
728                        include_glsl!("res/shader/transition/wipe_left.comp").as_slice()
729                    }
730                    TransitionType::WipeRight => {
731                        include_glsl!("res/shader/transition/wipe_right.comp").as_slice()
732                    }
733                    TransitionType::WipeUp => {
734                        include_glsl!("res/shader/transition/wipe_up.comp").as_slice()
735                    }
736                    TransitionType::ZoomInCircles => {
737                        include_glsl!("res/shader/transition/zoom_in_circles.comp").as_slice()
738                    }
739                    TransitionType::ZoomLeftWipe => {
740                        include_glsl!("res/shader/transition/zoom_left_wipe.comp").as_slice()
741                    }
742                    TransitionType::ZoomRightWipe => {
743                        include_glsl!("res/shader/transition/zoom_right_wipe.comp").as_slice()
744                    }
745                }),
746            )
747            .expect("invalid transition pipeline")
748        })
749    }
750}
751
752fn extend_push_constants(transition: Transition, push_consts: &mut Vec<u8>) {
753    match transition {
754        Transition::Angular { starting_angle } => {
755            push_consts.extend_from_slice(&starting_angle.to_ne_bytes());
756        }
757        Transition::Bounce {
758            shadow_height,
759            bounces,
760            shadow_colour,
761        } => {
762            push_consts.extend_from_slice(&shadow_height.to_ne_bytes());
763            push_consts.extend_from_slice(&bounces.to_ne_bytes());
764            push_consts.extend_from_slice(&[0u8; 4]); // padding
765            push_consts.extend_from_slice(&shadow_colour[0].to_ne_bytes());
766            push_consts.extend_from_slice(&shadow_colour[1].to_ne_bytes());
767            push_consts.extend_from_slice(&shadow_colour[2].to_ne_bytes());
768            push_consts.extend_from_slice(&shadow_colour[3].to_ne_bytes());
769        }
770        Transition::BowTieWithParameter { adjust, reverse } => {
771            push_consts.extend_from_slice(&adjust.to_ne_bytes());
772            push_consts.extend_from_slice(&(reverse as u32).to_ne_bytes());
773        }
774        Transition::Burn { color } => {
775            push_consts.extend_from_slice(&[0u8; 12]); // padding
776            push_consts.extend_from_slice(&color[0].to_ne_bytes());
777            push_consts.extend_from_slice(&color[1].to_ne_bytes());
778            push_consts.extend_from_slice(&color[2].to_ne_bytes());
779        }
780        Transition::ButterflyWaveScrawler {
781            amplitude,
782            waves,
783            color_separation,
784        } => {
785            push_consts.extend_from_slice(&amplitude.to_ne_bytes());
786            push_consts.extend_from_slice(&waves.to_ne_bytes());
787            push_consts.extend_from_slice(&color_separation.to_ne_bytes());
788        }
789        Transition::Circle {
790            center,
791            background_color,
792        } => {
793            push_consts.extend_from_slice(&[0u8; 4]); // padding
794            push_consts.extend_from_slice(&center[0].to_ne_bytes());
795            push_consts.extend_from_slice(&center[1].to_ne_bytes());
796            push_consts.extend_from_slice(&background_color[0].to_ne_bytes());
797            push_consts.extend_from_slice(&background_color[1].to_ne_bytes());
798            push_consts.extend_from_slice(&background_color[2].to_ne_bytes());
799            push_consts.extend_from_slice(&[0u8; 4]); // padding
800        }
801        Transition::CircleCrop { background_color } => {
802            push_consts.extend_from_slice(&[0u8; 12]); // padding
803            push_consts.extend_from_slice(&background_color[0].to_ne_bytes());
804            push_consts.extend_from_slice(&background_color[1].to_ne_bytes());
805            push_consts.extend_from_slice(&background_color[2].to_ne_bytes());
806            push_consts.extend_from_slice(&background_color[3].to_ne_bytes());
807            push_consts.extend_from_slice(&[0u8; 4]); // padding
808        }
809        Transition::CircleOpen {
810            smoothness,
811            opening,
812        } => {
813            push_consts.extend_from_slice(&smoothness.to_ne_bytes());
814            push_consts.extend_from_slice(&(opening as u32).to_ne_bytes());
815        }
816        Transition::ColorDistance { power } => {
817            push_consts.extend_from_slice(&power.to_ne_bytes());
818        }
819        Transition::ColorPhase { from_step, to_step } => {
820            push_consts.extend_from_slice(&[0u8; 12]); // padding
821            push_consts.extend_from_slice(&from_step[0].to_ne_bytes());
822            push_consts.extend_from_slice(&from_step[1].to_ne_bytes());
823            push_consts.extend_from_slice(&from_step[2].to_ne_bytes());
824            push_consts.extend_from_slice(&from_step[3].to_ne_bytes());
825            push_consts.extend_from_slice(&to_step[0].to_ne_bytes());
826            push_consts.extend_from_slice(&to_step[1].to_ne_bytes());
827            push_consts.extend_from_slice(&to_step[2].to_ne_bytes());
828            push_consts.extend_from_slice(&to_step[3].to_ne_bytes());
829        }
830        Transition::CrazyParametricFun {
831            a,
832            b,
833            amplitude,
834            smoothness,
835        } => {
836            push_consts.extend_from_slice(&a.to_ne_bytes());
837            push_consts.extend_from_slice(&b.to_ne_bytes());
838            push_consts.extend_from_slice(&amplitude.to_ne_bytes());
839            push_consts.extend_from_slice(&smoothness.to_ne_bytes());
840        }
841        Transition::Crosshatch {
842            center,
843            threshold,
844            fade_edge,
845        } => {
846            push_consts.extend_from_slice(&[0u8; 4]); // padding
847            push_consts.extend_from_slice(&center[0].to_ne_bytes());
848            push_consts.extend_from_slice(&center[1].to_ne_bytes());
849            push_consts.extend_from_slice(&threshold.to_ne_bytes());
850            push_consts.extend_from_slice(&fade_edge.to_ne_bytes());
851        }
852        Transition::CrossZoom { strength } => {
853            push_consts.extend_from_slice(&strength.to_ne_bytes());
854        }
855        Transition::Cube {
856            perspective,
857            unzoom,
858            reflection,
859            floating,
860        } => {
861            push_consts.extend_from_slice(&perspective.to_ne_bytes());
862            push_consts.extend_from_slice(&unzoom.to_ne_bytes());
863            push_consts.extend_from_slice(&reflection.to_ne_bytes());
864            push_consts.extend_from_slice(&floating.to_ne_bytes());
865        }
866        Transition::Directional { direction } => {
867            push_consts.extend_from_slice(&[0u8; 4]); // padding
868            push_consts.extend_from_slice(&direction[0].to_ne_bytes());
869            push_consts.extend_from_slice(&direction[1].to_ne_bytes());
870        }
871        Transition::DirectionalEasing { direction } => {
872            push_consts.extend_from_slice(&[0u8; 4]); // padding
873            push_consts.extend_from_slice(&direction[0].to_ne_bytes());
874            push_consts.extend_from_slice(&direction[1].to_ne_bytes());
875        }
876        Transition::DirectionalWarp { direction } => {
877            push_consts.extend_from_slice(&[0u8; 4]); // padding
878            push_consts.extend_from_slice(&direction[0].to_ne_bytes());
879            push_consts.extend_from_slice(&direction[1].to_ne_bytes());
880        }
881        Transition::DirectionalWipe {
882            smoothness,
883            direction,
884        } => {
885            push_consts.extend_from_slice(&smoothness.to_ne_bytes());
886            push_consts.extend_from_slice(&direction[0].to_ne_bytes());
887            push_consts.extend_from_slice(&direction[1].to_ne_bytes());
888        }
889        Transition::Displacement { strength, .. } => {
890            push_consts.extend_from_slice(&strength.to_ne_bytes());
891        }
892        Transition::DoomScreen {
893            bars,
894            amplitude,
895            noise,
896            frequency,
897            drip_scale,
898        } => {
899            push_consts.extend_from_slice(&bars.to_ne_bytes());
900            push_consts.extend_from_slice(&amplitude.to_ne_bytes());
901            push_consts.extend_from_slice(&noise.to_ne_bytes());
902            push_consts.extend_from_slice(&frequency.to_ne_bytes());
903            push_consts.extend_from_slice(&drip_scale.to_ne_bytes());
904        }
905        Transition::Doorway {
906            reflection,
907            perspective,
908            depth,
909        } => {
910            push_consts.extend_from_slice(&reflection.to_ne_bytes());
911            push_consts.extend_from_slice(&perspective.to_ne_bytes());
912            push_consts.extend_from_slice(&depth.to_ne_bytes());
913        }
914        Transition::DreamyZoom { rotation, scale } => {
915            push_consts.extend_from_slice(&rotation.to_ne_bytes());
916            push_consts.extend_from_slice(&scale.to_ne_bytes());
917        }
918        Transition::FadeColor { color_phase, color } => {
919            push_consts.extend_from_slice(&color_phase.to_ne_bytes());
920            push_consts.extend_from_slice(&[0u8; 8]); // padding
921            push_consts.extend_from_slice(&color[0].to_ne_bytes());
922            push_consts.extend_from_slice(&color[1].to_ne_bytes());
923            push_consts.extend_from_slice(&color[2].to_ne_bytes());
924        }
925        Transition::FadeGrayscale { intensity } => {
926            push_consts.extend_from_slice(&intensity.to_ne_bytes());
927        }
928        Transition::FilmBurn { seed } => {
929            push_consts.extend_from_slice(&seed.to_ne_bytes());
930        }
931        Transition::Flyeye {
932            size,
933            zoom,
934            color_separation,
935        } => {
936            push_consts.extend_from_slice(&size.to_ne_bytes());
937            push_consts.extend_from_slice(&zoom.to_ne_bytes());
938            push_consts.extend_from_slice(&color_separation.to_ne_bytes());
939        }
940        Transition::GridFlip {
941            pause,
942            size,
943            background_color,
944            divider_width,
945            randomness,
946        } => {
947            push_consts.extend_from_slice(&pause.to_ne_bytes());
948            push_consts.extend_from_slice(&size[0].to_ne_bytes());
949            push_consts.extend_from_slice(&size[1].to_ne_bytes());
950            push_consts.extend_from_slice(&background_color[0].to_ne_bytes());
951            push_consts.extend_from_slice(&background_color[1].to_ne_bytes());
952            push_consts.extend_from_slice(&background_color[2].to_ne_bytes());
953            push_consts.extend_from_slice(&background_color[3].to_ne_bytes());
954            push_consts.extend_from_slice(&divider_width.to_ne_bytes());
955            push_consts.extend_from_slice(&randomness.to_ne_bytes());
956        }
957        Transition::Hexagonalize {
958            steps,
959            horizontal_hexagons,
960        } => {
961            push_consts.extend_from_slice(&steps.to_ne_bytes());
962            push_consts.extend_from_slice(&horizontal_hexagons.to_ne_bytes());
963        }
964        Transition::Kaleidoscope {
965            speed,
966            angle,
967            power,
968        } => {
969            push_consts.extend_from_slice(&speed.to_ne_bytes());
970            push_consts.extend_from_slice(&angle.to_ne_bytes());
971            push_consts.extend_from_slice(&power.to_ne_bytes());
972        }
973        Transition::LinearBlur { intensity } => {
974            push_consts.extend_from_slice(&intensity.to_ne_bytes());
975        }
976        Transition::LuminanceMelt {
977            direction,
978            threshold,
979            above,
980        } => {
981            push_consts.extend_from_slice(&(direction as u32).to_ne_bytes());
982            push_consts.extend_from_slice(&threshold.to_ne_bytes());
983            push_consts.extend_from_slice(&(above as u32).to_ne_bytes());
984        }
985        Transition::Morph { strength } => {
986            push_consts.extend_from_slice(&strength.to_ne_bytes());
987        }
988        Transition::Mosaic { end } => {
989            push_consts.extend_from_slice(&end[0].to_ne_bytes());
990            push_consts.extend_from_slice(&end[1].to_ne_bytes());
991        }
992        Transition::Overexposure { strength } => {
993            push_consts.extend_from_slice(&strength.to_ne_bytes());
994        }
995        Transition::Perlin {
996            scale,
997            smoothness,
998            seed,
999        } => {
1000            push_consts.extend_from_slice(&scale.to_ne_bytes());
1001            push_consts.extend_from_slice(&smoothness.to_ne_bytes());
1002            push_consts.extend_from_slice(&seed.to_ne_bytes());
1003        }
1004        Transition::Pinwheel { speed } => {
1005            push_consts.extend_from_slice(&speed.to_ne_bytes());
1006        }
1007        Transition::Pixelize { steps, squares_min } => {
1008            push_consts.extend_from_slice(&steps.to_ne_bytes());
1009            push_consts.extend_from_slice(&squares_min[0].to_ne_bytes());
1010            push_consts.extend_from_slice(&squares_min[1].to_ne_bytes());
1011        }
1012        Transition::PolarFunction { segments } => {
1013            push_consts.extend_from_slice(&segments.to_ne_bytes());
1014        }
1015        Transition::PolkaDotsCurtain { dots, center } => {
1016            push_consts.extend_from_slice(&dots.to_ne_bytes());
1017            push_consts.extend_from_slice(&center[0].to_ne_bytes());
1018            push_consts.extend_from_slice(&center[1].to_ne_bytes());
1019        }
1020        Transition::PowerKaleido { scale, z, speed } => {
1021            push_consts.extend_from_slice(&scale.to_ne_bytes());
1022            push_consts.extend_from_slice(&z.to_ne_bytes());
1023            push_consts.extend_from_slice(&speed.to_ne_bytes());
1024        }
1025        Transition::Radial { smoothness } => {
1026            push_consts.extend_from_slice(&smoothness.to_ne_bytes());
1027        }
1028        Transition::RandomSquares { smoothness, size } => {
1029            push_consts.extend_from_slice(&smoothness.to_ne_bytes());
1030            push_consts.extend_from_slice(&size[0].to_ne_bytes());
1031            push_consts.extend_from_slice(&size[1].to_ne_bytes());
1032        }
1033        Transition::Ripple { amplitude, speed } => {
1034            push_consts.extend_from_slice(&amplitude.to_ne_bytes());
1035            push_consts.extend_from_slice(&speed.to_ne_bytes());
1036        }
1037        Transition::RotateScale {
1038            rotations,
1039            center,
1040            background_color,
1041            scale,
1042        } => {
1043            push_consts.extend_from_slice(&rotations.to_ne_bytes());
1044            push_consts.extend_from_slice(&center[0].to_ne_bytes());
1045            push_consts.extend_from_slice(&center[1].to_ne_bytes());
1046            push_consts.extend_from_slice(&background_color[0].to_ne_bytes());
1047            push_consts.extend_from_slice(&background_color[1].to_ne_bytes());
1048            push_consts.extend_from_slice(&background_color[2].to_ne_bytes());
1049            push_consts.extend_from_slice(&background_color[3].to_ne_bytes());
1050            push_consts.extend_from_slice(&scale.to_ne_bytes());
1051        }
1052        Transition::SimpleZoom { zoom_quickness } => {
1053            push_consts.extend_from_slice(&zoom_quickness.to_ne_bytes());
1054        }
1055        Transition::SquaresWire {
1056            smoothness,
1057            squares,
1058            direction,
1059        } => {
1060            push_consts.extend_from_slice(&smoothness.to_ne_bytes());
1061            push_consts.extend_from_slice(&squares[0].to_ne_bytes());
1062            push_consts.extend_from_slice(&squares[1].to_ne_bytes());
1063            push_consts.extend_from_slice(&direction[0].to_ne_bytes());
1064            push_consts.extend_from_slice(&direction[1].to_ne_bytes());
1065        }
1066        Transition::Squeeze { color_separation } => {
1067            push_consts.extend_from_slice(&color_separation.to_ne_bytes());
1068        }
1069        Transition::StereoViewer {
1070            zoom,
1071            corner_radius,
1072        } => {
1073            push_consts.extend_from_slice(&zoom.to_ne_bytes());
1074            push_consts.extend_from_slice(&corner_radius.to_ne_bytes());
1075        }
1076        Transition::Swap {
1077            reflection,
1078            perspective,
1079            depth,
1080        } => {
1081            push_consts.extend_from_slice(&reflection.to_ne_bytes());
1082            push_consts.extend_from_slice(&perspective.to_ne_bytes());
1083            push_consts.extend_from_slice(&depth.to_ne_bytes());
1084        }
1085        Transition::TvStatic { offset } => {
1086            push_consts.extend_from_slice(&offset.to_ne_bytes());
1087        }
1088        Transition::UndulatingBurnOut {
1089            smoothness,
1090            center,
1091            color,
1092        } => {
1093            push_consts.extend_from_slice(&smoothness.to_ne_bytes());
1094            push_consts.extend_from_slice(&center[0].to_ne_bytes());
1095            push_consts.extend_from_slice(&center[1].to_ne_bytes());
1096            push_consts.extend_from_slice(&color[0].to_ne_bytes());
1097            push_consts.extend_from_slice(&color[1].to_ne_bytes());
1098            push_consts.extend_from_slice(&color[2].to_ne_bytes());
1099        }
1100        Transition::WaterDrop { amplitude, speed } => {
1101            push_consts.extend_from_slice(&amplitude.to_ne_bytes());
1102            push_consts.extend_from_slice(&speed.to_ne_bytes());
1103        }
1104        Transition::Wind { size } => {
1105            push_consts.extend_from_slice(&size.to_ne_bytes());
1106        }
1107        Transition::WindowSlice { count, smoothness } => {
1108            push_consts.extend_from_slice(&count.to_ne_bytes());
1109            push_consts.extend_from_slice(&smoothness.to_ne_bytes());
1110        }
1111        Transition::ZoomLeftWipe { zoom_quickness } => {
1112            push_consts.extend_from_slice(&zoom_quickness.to_ne_bytes());
1113        }
1114        Transition::ZoomRightWipe { zoom_quickness } => {
1115            push_consts.extend_from_slice(&zoom_quickness.to_ne_bytes());
1116        }
1117        Transition::BowTieHorizontal
1118        | Transition::BowTieVertical
1119        | Transition::CannabisLeaf
1120        | Transition::CoordFromIn
1121        | Transition::CrossWarp
1122        | Transition::Dreamy
1123        | Transition::Fade
1124        | Transition::GlitchDisplace
1125        | Transition::GlitchMemories
1126        | Transition::Heart
1127        | Transition::InvertedPageCurl
1128        | Transition::Luma { .. }
1129        | Transition::LeftRight
1130        | Transition::Multiply
1131        | Transition::RandomNoisex
1132        | Transition::Rotate
1133        | Transition::ScaleIn
1134        | Transition::Swirl
1135        | Transition::TangentMotionBlur
1136        | Transition::TopBottom
1137        | Transition::WindowBlinds
1138        | Transition::WipeDown
1139        | Transition::WipeLeft
1140        | Transition::WipeRight
1141        | Transition::WipeUp
1142        | Transition::ZoomInCircles => {}
1143    };
1144}
1145
1146#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1147enum TransitionType {
1148    Angular,
1149    Bounce,
1150    BowTieHorizontal,
1151    BowTieVertical,
1152    BowTieWithParameter,
1153    Burn,
1154    ButterflyWaveScrawler,
1155    CannabisLeaf,
1156    Circle,
1157    CircleCrop,
1158    CircleOpen,
1159    ColorDistance,
1160    ColorPhase,
1161    CoordFromIn,
1162    CrazyParametricFun,
1163    Crosshatch,
1164    CrossWarp,
1165    CrossZoom,
1166    Cube,
1167    Directional,
1168    DirectionalEasing,
1169    DirectionalWarp,
1170    DirectionalWipe,
1171    Displacement,
1172    DoomScreen,
1173    Doorway,
1174    Dreamy,
1175    DreamyZoom,
1176    FadeColor,
1177    Fade,
1178    FadeGrayscale,
1179    FilmBurn,
1180    Flyeye,
1181    GlitchDisplace,
1182    GlitchMemories,
1183    GridFlip,
1184    Heart,
1185    Hexagonalize,
1186    InvertedPageCurl,
1187    Kaleidoscope,
1188    LeftRight,
1189    LinearBlur,
1190    Luma,
1191    LuminanceMelt,
1192    Morph,
1193    Mosaic,
1194    Multiply,
1195    Overexposure,
1196    Perlin,
1197    Pinwheel,
1198    Pixelize,
1199    PolarFunction,
1200    PolkaDotsCurtain,
1201    PowerKaleido,
1202    Radial,
1203    RandomNoisex,
1204    RandomSquares,
1205    Ripple,
1206    Rotate,
1207    RotateScale,
1208    ScaleIn,
1209    SimpleZoom,
1210    SquaresWire,
1211    Squeeze,
1212    StereoViewer,
1213    Swap,
1214    Swirl,
1215    TangentMotionBlur,
1216    TopBottom,
1217    TvStatic,
1218    UndulatingBurnOut,
1219    WaterDrop,
1220    Wind,
1221    WindowBlinds,
1222    WindowSlice,
1223    WipeDown,
1224    WipeLeft,
1225    WipeRight,
1226    WipeUp,
1227    ZoomInCircles,
1228    ZoomLeftWipe,
1229    ZoomRightWipe,
1230}