1use argh::FromArgs;
7use bevy::{
8 color::palettes::css::*,
9 diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
10 math::ops::sin,
11 prelude::*,
12 ui::{
13 BackgroundGradient, ColorStop, Display, Gradient, InterpolationColorSpace, LinearGradient,
14 RepeatedGridTrack,
15 },
16 window::{PresentMode, WindowResolution},
17 winit::{UpdateMode, WinitSettings},
18};
19
20const COLS: usize = 30;
21
22#[derive(FromArgs, Resource, Debug)]
23struct Args {
25 #[argh(option, default = "900")]
27 gradient_count: usize,
28
29 #[argh(switch)]
31 animate: bool,
32
33 #[argh(switch)]
35 srgb: bool,
36
37 #[argh(switch)]
39 hsl: bool,
40}
41
42fn main() {
43 let args: Args = argh::from_env();
44 let total_gradients = args.gradient_count;
45
46 println!("Gradient stress test with {total_gradients} gradients");
47 println!(
48 "Color space: {}",
49 if args.srgb {
50 "sRGB"
51 } else if args.hsl {
52 "HSL"
53 } else {
54 "OkLab (default)"
55 }
56 );
57
58 App::new()
59 .add_plugins((
60 LogDiagnosticsPlugin::default(),
61 FrameTimeDiagnosticsPlugin::default(),
62 DefaultPlugins.set(WindowPlugin {
63 primary_window: Some(Window {
64 title: "Gradient Stress Test".to_string(),
65 resolution: WindowResolution::new(1920, 1080).with_scale_factor_override(1.0),
66 present_mode: PresentMode::AutoNoVsync,
67 ..default()
68 }),
69 ..default()
70 }),
71 ))
72 .insert_resource(WinitSettings {
73 focused_mode: UpdateMode::Continuous,
74 unfocused_mode: UpdateMode::Continuous,
75 })
76 .insert_resource(args)
77 .insert_resource(WinitSettings::continuous())
78 .add_systems(Startup, setup)
79 .add_systems(Update, animate_gradients)
80 .run();
81}
82
83fn setup(mut commands: Commands, args: Res<Args>) {
84 commands.spawn(Camera2d);
85
86 let rows_to_spawn = args.gradient_count.div_ceil(COLS);
87
88 commands
90 .spawn(Node {
91 width: percent(100),
92 height: percent(100),
93 display: Display::Grid,
94 grid_template_columns: RepeatedGridTrack::flex(COLS as u16, 1.0),
95 grid_template_rows: RepeatedGridTrack::flex(rows_to_spawn as u16, 1.0),
96 ..default()
97 })
98 .with_children(|parent| {
99 for i in 0..args.gradient_count {
100 let angle = (i as f32 * 10.0) % 360.0;
101
102 let mut gradient = LinearGradient::new(
103 angle,
104 vec![
105 ColorStop::new(RED, percent(0)),
106 ColorStop::new(BLUE, percent(100)),
107 ColorStop::new(GREEN, percent(20)),
108 ColorStop::new(YELLOW, percent(40)),
109 ColorStop::new(ORANGE, percent(60)),
110 ColorStop::new(LIME, percent(80)),
111 ColorStop::new(DARK_CYAN, percent(90)),
112 ],
113 );
114
115 gradient.color_space = if args.srgb {
116 InterpolationColorSpace::Srgba
117 } else if args.hsl {
118 InterpolationColorSpace::Hsla
119 } else {
120 InterpolationColorSpace::Oklaba
121 };
122
123 parent.spawn((
124 Node {
125 width: percent(100),
126 height: percent(100),
127 ..default()
128 },
129 BackgroundGradient(vec![Gradient::Linear(gradient)]),
130 GradientNode { index: i },
131 ));
132 }
133 });
134}
135
136#[derive(Component)]
137struct GradientNode {
138 index: usize,
139}
140
141fn animate_gradients(
142 mut gradients: Query<(&mut BackgroundGradient, &GradientNode)>,
143 args: Res<Args>,
144 time: Res<Time>,
145) {
146 if !args.animate {
147 return;
148 }
149
150 let t = time.elapsed_secs();
151
152 for (mut bg_gradient, node) in &mut gradients {
153 let offset = node.index as f32 * 0.01;
154 let hue_shift = sin(t + offset) * 0.5 + 0.5;
155
156 if let Some(Gradient::Linear(gradient)) = bg_gradient.0.get_mut(0) {
157 let color1 = Color::hsl(hue_shift * 360.0, 1.0, 0.5);
158 let color2 = Color::hsl((hue_shift + 0.3) * 360.0 % 360.0, 1.0, 0.5);
159
160 gradient.stops = vec![
161 ColorStop::new(color1, percent(0)),
162 ColorStop::new(color2, percent(100)),
163 ColorStop::new(
164 Color::hsl((hue_shift + 0.1) * 360.0 % 360.0, 1.0, 0.5),
165 percent(20),
166 ),
167 ColorStop::new(
168 Color::hsl((hue_shift + 0.15) * 360.0 % 360.0, 1.0, 0.5),
169 percent(40),
170 ),
171 ColorStop::new(
172 Color::hsl((hue_shift + 0.2) * 360.0 % 360.0, 1.0, 0.5),
173 percent(60),
174 ),
175 ColorStop::new(
176 Color::hsl((hue_shift + 0.25) * 360.0 % 360.0, 1.0, 0.5),
177 percent(80),
178 ),
179 ColorStop::new(
180 Color::hsl((hue_shift + 0.28) * 360.0 % 360.0, 1.0, 0.5),
181 percent(90),
182 ),
183 ];
184 }
185 }
186}