Preconvert colors to sRGB
This commit is contained in:
parent
f1eace62f0
commit
fff060d638
11
Cargo.toml
11
Cargo.toml
@ -3068,6 +3068,17 @@ description = "Test rendering of many UI elements"
|
||||
category = "Stress Tests"
|
||||
wasm = true
|
||||
|
||||
[[example]]
|
||||
name = "many_gradients"
|
||||
path = "examples/stress_tests/many_gradients.rs"
|
||||
doc-scrape-examples = true
|
||||
|
||||
[package.metadata.example.many_gradients]
|
||||
name = "Many Gradients"
|
||||
description = "Stress test for gradient rendering performance"
|
||||
category = "Stress Tests"
|
||||
wasm = true
|
||||
|
||||
[[example]]
|
||||
name = "many_cameras_lights"
|
||||
path = "examples/stress_tests/many_cameras_lights.rs"
|
||||
|
@ -7,7 +7,7 @@ use core::{
|
||||
use super::shader_flags::BORDER_ALL;
|
||||
use crate::*;
|
||||
use bevy_asset::*;
|
||||
use bevy_color::{ColorToComponents, LinearRgba};
|
||||
use bevy_color::{ColorToComponents, Hsla, Hsva, LinearRgba, Oklaba, Oklcha, Srgba};
|
||||
use bevy_ecs::{
|
||||
prelude::Component,
|
||||
system::{
|
||||
@ -654,6 +654,36 @@ struct UiGradientVertex {
|
||||
hint: f32,
|
||||
}
|
||||
|
||||
fn convert_color_to_space(color: LinearRgba, space: InterpolationColorSpace) -> [f32; 4] {
|
||||
match space {
|
||||
InterpolationColorSpace::OkLab => {
|
||||
let oklaba: Oklaba = color.into();
|
||||
[oklaba.lightness, oklaba.a, oklaba.b, oklaba.alpha]
|
||||
}
|
||||
InterpolationColorSpace::OkLch | InterpolationColorSpace::OkLchLong => {
|
||||
let oklcha: Oklcha = color.into();
|
||||
[oklcha.lightness, oklcha.chroma, oklcha.hue.to_radians(), oklcha.alpha]
|
||||
}
|
||||
InterpolationColorSpace::Srgb => {
|
||||
let srgba: Srgba = color.into();
|
||||
[srgba.red, srgba.green, srgba.blue, srgba.alpha]
|
||||
}
|
||||
InterpolationColorSpace::LinearRgb => {
|
||||
color.to_f32_array()
|
||||
}
|
||||
InterpolationColorSpace::Hsl | InterpolationColorSpace::HslLong => {
|
||||
let hsla: Hsla = color.into();
|
||||
// Normalize hue to 0..1 range for shader
|
||||
[hsla.hue / 360.0, hsla.saturation, hsla.lightness, hsla.alpha]
|
||||
}
|
||||
InterpolationColorSpace::Hsv | InterpolationColorSpace::HsvLong => {
|
||||
let hsva: Hsva = color.into();
|
||||
// Normalize hue to 0..1 range for shader
|
||||
[hsva.hue / 360.0, hsva.saturation, hsva.value, hsva.alpha]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prepare_gradient(
|
||||
mut commands: Commands,
|
||||
render_device: Res<RenderDevice>,
|
||||
@ -804,8 +834,8 @@ pub fn prepare_gradient(
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let start_color = start_stop.0.to_f32_array();
|
||||
let end_color = end_stop.0.to_f32_array();
|
||||
let start_color = convert_color_to_space(start_stop.0, gradient.color_space);
|
||||
let end_color = convert_color_to_space(end_stop.0, gradient.color_space);
|
||||
let mut stop_flags = flags;
|
||||
if 0. < start_stop.1
|
||||
&& (stop_index == gradient.stops_range.start || segment_count == 0)
|
||||
|
@ -114,26 +114,6 @@ fn fragment(in: GradientVertexOutput) -> @location(0) vec4<f32> {
|
||||
}
|
||||
}
|
||||
|
||||
// This function converts two linear rgba colors to srgba space, mixes them, and then converts the result back to linear rgb space.
|
||||
fn mix_linear_rgba_in_srgba_space(a: vec4<f32>, b: vec4<f32>, t: f32) -> vec4<f32> {
|
||||
let a_srgb = pow(a.rgb, vec3(1. / 2.2));
|
||||
let b_srgb = pow(b.rgb, vec3(1. / 2.2));
|
||||
let mixed_srgb = mix(a_srgb, b_srgb, t);
|
||||
return vec4(pow(mixed_srgb, vec3(2.2)), mix(a.a, b.a, t));
|
||||
}
|
||||
|
||||
fn linear_rgba_to_oklaba(c: vec4<f32>) -> vec4<f32> {
|
||||
let l = pow(0.41222146 * c.x + 0.53633255 * c.y + 0.051445995 * c.z, 1. / 3.);
|
||||
let m = pow(0.2119035 * c.x + 0.6806995 * c.y + 0.10739696 * c.z, 1. / 3.);
|
||||
let s = pow(0.08830246 * c.x + 0.28171885 * c.y + 0.6299787 * c.z, 1. / 3.);
|
||||
return vec4(
|
||||
0.21045426 * l + 0.7936178 * m - 0.004072047 * s,
|
||||
1.9779985 * l - 2.4285922 * m + 0.4505937 * s,
|
||||
0.025904037 * l + 0.78277177 * m - 0.80867577 * s,
|
||||
c.a
|
||||
);
|
||||
}
|
||||
|
||||
fn oklaba_to_linear_rgba(c: vec4<f32>) -> vec4<f32> {
|
||||
let l_ = c.x + 0.39633778 * c.y + 0.21580376 * c.z;
|
||||
let m_ = c.x - 0.105561346 * c.y - 0.06385417 * c.z;
|
||||
@ -149,33 +129,6 @@ fn oklaba_to_linear_rgba(c: vec4<f32>) -> vec4<f32> {
|
||||
);
|
||||
}
|
||||
|
||||
fn mix_linear_rgba_in_oklaba_space(a: vec4<f32>, b: vec4<f32>, t: f32) -> vec4<f32> {
|
||||
return oklaba_to_linear_rgba(mix(linear_rgba_to_oklaba(a), linear_rgba_to_oklaba(b), t));
|
||||
}
|
||||
|
||||
fn linear_rgba_to_hsla(c: vec4<f32>) -> vec4<f32> {
|
||||
let max = max(max(c.r, c.g), c.b);
|
||||
let min = min(min(c.r, c.g), c.b);
|
||||
let l = (max + min) * 0.5;
|
||||
if max == min {
|
||||
return vec4(0., 0., l, c.a);
|
||||
} else {
|
||||
let delta = max - min;
|
||||
let s = delta / (1. - abs(2. * l - 1.));
|
||||
var h = 0.;
|
||||
if max == c.r {
|
||||
h = ((c.g - c.b) / delta) % 6.;
|
||||
} else if max == c.g {
|
||||
h = ((c.b - c.r) / delta) + 2.;
|
||||
} else {
|
||||
h = ((c.r - c.g) / delta) + 4.;
|
||||
}
|
||||
h = h / 6.;
|
||||
return vec4<f32>(h, s, l, c.a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn hsla_to_linear_rgba(hsl: vec4<f32>) -> vec4<f32> {
|
||||
let h = hsl.x;
|
||||
let s = hsl.y;
|
||||
@ -203,30 +156,6 @@ fn hsla_to_linear_rgba(hsl: vec4<f32>) -> vec4<f32> {
|
||||
return vec4<f32>(r + m, g + m, b + m, hsl.a);
|
||||
}
|
||||
|
||||
fn linear_rgba_to_hsva(c: vec4<f32>) -> vec4<f32> {
|
||||
let maxc = max(max(c.r, c.g), c.b);
|
||||
let minc = min(min(c.r, c.g), c.b);
|
||||
let delta = maxc - minc;
|
||||
var h: f32 = 0.0;
|
||||
var s: f32 = 0.0;
|
||||
let v: f32 = maxc;
|
||||
if delta != 0.0 {
|
||||
s = delta / maxc;
|
||||
if maxc == c.r {
|
||||
h = ((c.g - c.b) / delta) % 6.0;
|
||||
} else if maxc == c.g {
|
||||
h = ((c.b - c.r) / delta) + 2.0;
|
||||
} else {
|
||||
h = ((c.r - c.g) / delta) + 4.0;
|
||||
}
|
||||
h = h / 6.0;
|
||||
if h < 0.0 {
|
||||
h = h + 1.0;
|
||||
}
|
||||
}
|
||||
return vec4<f32>(h, s, v, c.a);
|
||||
}
|
||||
|
||||
fn hsva_to_linear_rgba(hsva: vec4<f32>) -> vec4<f32> {
|
||||
let h = hsva.x * 6.0;
|
||||
let s = hsva.y;
|
||||
@ -253,14 +182,6 @@ fn hsva_to_linear_rgba(hsva: vec4<f32>) -> vec4<f32> {
|
||||
return vec4<f32>(r + m, g + m, b + m, hsva.a);
|
||||
}
|
||||
|
||||
/// hue is left in radians and not converted to degrees
|
||||
fn linear_rgba_to_oklcha(c: vec4<f32>) -> vec4<f32> {
|
||||
let o = linear_rgba_to_oklaba(c);
|
||||
let chroma = sqrt(o.y * o.y + o.z * o.z);
|
||||
let hue = atan2(o.z, o.y);
|
||||
return vec4(o.x, chroma, rem_euclid(hue, TAU), o.a);
|
||||
}
|
||||
|
||||
fn oklcha_to_linear_rgba(c: vec4<f32>) -> vec4<f32> {
|
||||
let a = c.y * cos(c.z);
|
||||
let b = c.y * sin(c.z);
|
||||
@ -271,90 +192,6 @@ fn rem_euclid(a: f32, b: f32) -> f32 {
|
||||
return ((a % b) + b) % b;
|
||||
}
|
||||
|
||||
fn lerp_hue(a: f32, b: f32, t: f32) -> f32 {
|
||||
let diff = rem_euclid(b - a + PI, TAU) - PI;
|
||||
return rem_euclid(a + diff * t, TAU);
|
||||
}
|
||||
|
||||
fn lerp_hue_long(a: f32, b: f32, t: f32) -> f32 {
|
||||
let diff = rem_euclid(b - a + PI, TAU) - PI;
|
||||
return rem_euclid(a + (diff + select(TAU, -TAU, 0. < diff)) * t, TAU);
|
||||
}
|
||||
|
||||
fn mix_oklcha(a: vec4<f32>, b: vec4<f32>, t: f32) -> vec4<f32> {
|
||||
let ah = select(a.z, b.z, a.y == 0.);
|
||||
let bh = select(b.z, a.z, b.y == 0.);
|
||||
return vec4(
|
||||
mix(a.xy, b.xy, t),
|
||||
lerp_hue(ah, bh, t),
|
||||
mix(a.a, b.a, t)
|
||||
);
|
||||
}
|
||||
|
||||
fn mix_oklcha_long(a: vec4<f32>, b: vec4<f32>, t: f32) -> vec4<f32> {
|
||||
let ah = select(a.z, b.z, a.y == 0.);
|
||||
let bh = select(b.z, a.z, b.y == 0.);
|
||||
return vec4(
|
||||
mix(a.xy, b.xy, t),
|
||||
lerp_hue_long(ah, bh, t),
|
||||
mix(a.w, b.w, t)
|
||||
);
|
||||
}
|
||||
|
||||
fn mix_linear_rgba_in_oklcha_space(a: vec4<f32>, b: vec4<f32>, t: f32) -> vec4<f32> {
|
||||
return oklcha_to_linear_rgba(mix_oklcha(linear_rgba_to_oklcha(a), linear_rgba_to_oklcha(b), t));
|
||||
}
|
||||
|
||||
fn mix_linear_rgba_in_oklcha_space_long(a: vec4<f32>, b: vec4<f32>, t: f32) -> vec4<f32> {
|
||||
return oklcha_to_linear_rgba(mix_oklcha_long(linear_rgba_to_oklcha(a), linear_rgba_to_oklcha(b), t));
|
||||
}
|
||||
|
||||
fn mix_linear_rgba_in_hsva_space(a: vec4<f32>, b: vec4<f32>, t: f32) -> vec4<f32> {
|
||||
let ha = linear_rgba_to_hsva(a);
|
||||
let hb = linear_rgba_to_hsva(b);
|
||||
var h: f32;
|
||||
if ha.y == 0. {
|
||||
h = hb.x;
|
||||
} else if hb.y == 0. {
|
||||
h = ha.x;
|
||||
} else {
|
||||
h = lerp_hue(ha.x * TAU, hb.x * TAU, t) / TAU;
|
||||
}
|
||||
let s = mix(ha.y, hb.y, t);
|
||||
let v = mix(ha.z, hb.z, t);
|
||||
let a_alpha = mix(ha.a, hb.a, t);
|
||||
return hsva_to_linear_rgba(vec4<f32>(h, s, v, a_alpha));
|
||||
}
|
||||
|
||||
fn mix_linear_rgba_in_hsva_space_long(a: vec4<f32>, b: vec4<f32>, t: f32) -> vec4<f32> {
|
||||
let ha = linear_rgba_to_hsva(a);
|
||||
let hb = linear_rgba_to_hsva(b);
|
||||
let h = lerp_hue_long(ha.x * TAU, hb.x * TAU, t) / TAU;
|
||||
let s = mix(ha.y, hb.y, t);
|
||||
let v = mix(ha.z, hb.z, t);
|
||||
let a_alpha = mix(ha.a, hb.a, t);
|
||||
return hsva_to_linear_rgba(vec4<f32>(h, s, v, a_alpha));
|
||||
}
|
||||
|
||||
fn mix_linear_rgba_in_hsla_space(a: vec4<f32>, b: vec4<f32>, t: f32) -> vec4<f32> {
|
||||
let ha = linear_rgba_to_hsla(a);
|
||||
let hb = linear_rgba_to_hsla(b);
|
||||
let h = lerp_hue(ha.x * TAU, hb.x * TAU, t) / TAU;
|
||||
let s = mix(ha.y, hb.y, t);
|
||||
let l = mix(ha.z, hb.z, t);
|
||||
let a_alpha = mix(ha.a, hb.a, t);
|
||||
return hsla_to_linear_rgba(vec4<f32>(h, s, l, a_alpha));
|
||||
}
|
||||
|
||||
fn mix_linear_rgba_in_hsla_space_long(a: vec4<f32>, b: vec4<f32>, t: f32) -> vec4<f32> {
|
||||
let ha = linear_rgba_to_hsla(a);
|
||||
let hb = linear_rgba_to_hsla(b);
|
||||
let h = lerp_hue_long(ha.x * TAU, hb.x * TAU, t) / TAU;
|
||||
let s = mix(ha.y, hb.y, t);
|
||||
let l = mix(ha.z, hb.z, t);
|
||||
let a_alpha = mix(ha.a, hb.a, t);
|
||||
return hsla_to_linear_rgba(vec4<f32>(h, s, l, a_alpha));
|
||||
}
|
||||
|
||||
// These functions are used to calculate the distance in gradient space from the start of the gradient to the point.
|
||||
// The distance in gradient space is then used to interpolate between the start and end colors.
|
||||
@ -386,6 +223,126 @@ fn conic_distance(
|
||||
return (((angle - start) % TAU) + TAU) % TAU;
|
||||
}
|
||||
|
||||
fn mix_oklcha(a: vec4<f32>, b: vec4<f32>, t: f32) -> vec4<f32> {
|
||||
let hue_diff = b.z - a.z;
|
||||
var adjusted_hue = a.z;
|
||||
if abs(hue_diff) > PI {
|
||||
if hue_diff > 0.0 {
|
||||
adjusted_hue = a.z + (hue_diff - TAU) * t;
|
||||
} else {
|
||||
adjusted_hue = a.z + (hue_diff + TAU) * t;
|
||||
}
|
||||
} else {
|
||||
adjusted_hue = a.z + hue_diff * t;
|
||||
}
|
||||
return vec4(
|
||||
mix(a.x, b.x, t),
|
||||
mix(a.y, b.y, t),
|
||||
rem_euclid(adjusted_hue, TAU),
|
||||
mix(a.w, b.w, t)
|
||||
);
|
||||
}
|
||||
|
||||
fn mix_oklcha_long(a: vec4<f32>, b: vec4<f32>, t: f32) -> vec4<f32> {
|
||||
let hue_diff = b.z - a.z;
|
||||
var adjusted_hue = a.z;
|
||||
if abs(hue_diff) < PI {
|
||||
if hue_diff >= 0.0 {
|
||||
adjusted_hue = a.z + (hue_diff - TAU) * t;
|
||||
} else {
|
||||
adjusted_hue = a.z + (hue_diff + TAU) * t;
|
||||
}
|
||||
} else {
|
||||
adjusted_hue = a.z + hue_diff * t;
|
||||
}
|
||||
return vec4(
|
||||
mix(a.x, b.x, t),
|
||||
mix(a.y, b.y, t),
|
||||
rem_euclid(adjusted_hue, TAU),
|
||||
mix(a.w, b.w, t)
|
||||
);
|
||||
}
|
||||
|
||||
fn mix_hsla(a: vec4<f32>, b: vec4<f32>, t: f32) -> vec4<f32> {
|
||||
let hue_diff = b.x - a.x;
|
||||
var adjusted_hue = a.x;
|
||||
if abs(hue_diff) > 0.5 {
|
||||
if hue_diff > 0.0 {
|
||||
adjusted_hue = a.x + (hue_diff - 1.0) * t;
|
||||
} else {
|
||||
adjusted_hue = a.x + (hue_diff + 1.0) * t;
|
||||
}
|
||||
} else {
|
||||
adjusted_hue = a.x + hue_diff * t;
|
||||
}
|
||||
return vec4(
|
||||
fract(adjusted_hue),
|
||||
mix(a.y, b.y, t),
|
||||
mix(a.z, b.z, t),
|
||||
mix(a.w, b.w, t)
|
||||
);
|
||||
}
|
||||
|
||||
fn mix_hsla_long(a: vec4<f32>, b: vec4<f32>, t: f32) -> vec4<f32> {
|
||||
let hue_diff = b.x - a.x;
|
||||
var adjusted_hue = a.x;
|
||||
if abs(hue_diff) < 0.5 {
|
||||
if hue_diff >= 0.0 {
|
||||
adjusted_hue = a.x + (hue_diff - 1.0) * t;
|
||||
} else {
|
||||
adjusted_hue = a.x + (hue_diff + 1.0) * t;
|
||||
}
|
||||
} else {
|
||||
adjusted_hue = a.x + hue_diff * t;
|
||||
}
|
||||
return vec4(
|
||||
fract(adjusted_hue),
|
||||
mix(a.y, b.y, t),
|
||||
mix(a.z, b.z, t),
|
||||
mix(a.w, b.w, t)
|
||||
);
|
||||
}
|
||||
|
||||
fn mix_hsva(a: vec4<f32>, b: vec4<f32>, t: f32) -> vec4<f32> {
|
||||
let hue_diff = b.x - a.x;
|
||||
var adjusted_hue = a.x;
|
||||
if abs(hue_diff) > 0.5 {
|
||||
if hue_diff > 0.0 {
|
||||
adjusted_hue = a.x + (hue_diff - 1.0) * t;
|
||||
} else {
|
||||
adjusted_hue = a.x + (hue_diff + 1.0) * t;
|
||||
}
|
||||
} else {
|
||||
adjusted_hue = a.x + hue_diff * t;
|
||||
}
|
||||
return vec4(
|
||||
fract(adjusted_hue),
|
||||
mix(a.y, b.y, t),
|
||||
mix(a.z, b.z, t),
|
||||
mix(a.w, b.w, t)
|
||||
);
|
||||
}
|
||||
|
||||
fn mix_hsva_long(a: vec4<f32>, b: vec4<f32>, t: f32) -> vec4<f32> {
|
||||
let hue_diff = b.x - a.x;
|
||||
var adjusted_hue = a.x;
|
||||
if abs(hue_diff) < 0.5 {
|
||||
if hue_diff >= 0.0 {
|
||||
adjusted_hue = a.x + (hue_diff - 1.0) * t;
|
||||
} else {
|
||||
adjusted_hue = a.x + (hue_diff + 1.0) * t;
|
||||
}
|
||||
} else {
|
||||
adjusted_hue = a.x + hue_diff * t;
|
||||
}
|
||||
return vec4(
|
||||
fract(adjusted_hue),
|
||||
mix(a.y, b.y, t),
|
||||
mix(a.z, b.z, t),
|
||||
mix(a.w, b.w, t)
|
||||
);
|
||||
}
|
||||
|
||||
fn interpolate_gradient(
|
||||
distance: f32,
|
||||
start_color: vec4<f32>,
|
||||
@ -426,23 +383,23 @@ fn interpolate_gradient(
|
||||
} else {
|
||||
t = 0.5 * (1 + (t - hint) / (1.0 - hint));
|
||||
}
|
||||
|
||||
#ifdef IN_SRGB
|
||||
return mix_linear_rgba_in_srgba_space(start_color, end_color, t);
|
||||
#else ifdef IN_OKLAB
|
||||
return mix_linear_rgba_in_oklaba_space(start_color, end_color, t);
|
||||
#else ifdef IN_OKLCH
|
||||
return mix_linear_rgba_in_oklcha_space(start_color, end_color, t);
|
||||
#ifdef IN_OKLCH
|
||||
return oklcha_to_linear_rgba(mix_oklcha(start_color, end_color, t));
|
||||
#else ifdef IN_OKLCH_LONG
|
||||
return mix_linear_rgba_in_oklcha_space_long(start_color, end_color, t);
|
||||
return oklcha_to_linear_rgba(mix_oklcha_long(start_color, end_color, t));
|
||||
#else ifdef IN_HSV
|
||||
return mix_linear_rgba_in_hsva_space(start_color, end_color, t);
|
||||
return hsva_to_linear_rgba(mix_hsva(start_color, end_color, t));
|
||||
#else ifdef IN_HSV_LONG
|
||||
return mix_linear_rgba_in_hsva_space_long(start_color, end_color, t);
|
||||
return hsva_to_linear_rgba(mix_hsva_long(start_color, end_color, t));
|
||||
#else ifdef IN_HSL
|
||||
return mix_linear_rgba_in_hsla_space(start_color, end_color, t);
|
||||
return hsla_to_linear_rgba(mix_hsla(start_color, end_color, t));
|
||||
#else ifdef IN_HSL_LONG
|
||||
return mix_linear_rgba_in_hsla_space_long(start_color, end_color, t);
|
||||
return hsla_to_linear_rgba(mix_hsla_long(start_color, end_color, t));
|
||||
#else ifdef IN_OKLAB
|
||||
return oklaba_to_linear_rgba(mix(start_color, end_color, t));
|
||||
#else ifdef IN_SRGB
|
||||
let mixed_srgb = mix(start_color, end_color, t);
|
||||
return vec4(pow(mixed_srgb.rgb, vec3(2.2)), mixed_srgb.a);
|
||||
#else
|
||||
return mix(start_color, end_color, t);
|
||||
#endif
|
||||
|
145
examples/stress_tests/many_gradients.rs
Normal file
145
examples/stress_tests/many_gradients.rs
Normal file
@ -0,0 +1,145 @@
|
||||
//! Stress test demonstrating gradient performance improvements.
|
||||
//!
|
||||
//! This example creates many UI nodes with gradients to measure the performance
|
||||
//! impact of pre-converting colors to the target color space on the CPU.
|
||||
|
||||
use argh::FromArgs;
|
||||
use bevy::{
|
||||
color::palettes::css::*,
|
||||
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
|
||||
prelude::*,
|
||||
ui::{BackgroundGradient, LinearGradient, ColorStop, Gradient, RepeatedGridTrack, Display, InterpolationColorSpace},
|
||||
window::{PresentMode, WindowResolution},
|
||||
};
|
||||
|
||||
const COLS: usize = 30;
|
||||
|
||||
#[derive(FromArgs, Resource, Debug)]
|
||||
/// Gradient stress test
|
||||
struct Args {
|
||||
/// how many gradients per group (default: 900)
|
||||
#[argh(option, default = "900")]
|
||||
gradient_count: usize,
|
||||
|
||||
/// whether to animate gradients by changing colors
|
||||
#[argh(switch)]
|
||||
animate: bool,
|
||||
|
||||
/// use sRGB interpolation
|
||||
#[argh(switch)]
|
||||
srgb: bool,
|
||||
|
||||
/// use HSL interpolation
|
||||
#[argh(switch)]
|
||||
hsl: bool,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args: Args = argh::from_env();
|
||||
let total_gradients = args.gradient_count;
|
||||
|
||||
println!("Gradient stress test with {} gradients", total_gradients);
|
||||
println!("Color space: {}", if args.srgb {
|
||||
"sRGB"
|
||||
} else if args.hsl {
|
||||
"HSL"
|
||||
} else {
|
||||
"OkLab (default)"
|
||||
});
|
||||
|
||||
App::new()
|
||||
.add_plugins((
|
||||
LogDiagnosticsPlugin::default(),
|
||||
FrameTimeDiagnosticsPlugin::default(),
|
||||
DefaultPlugins.set(WindowPlugin {
|
||||
primary_window: Some(Window {
|
||||
title: "Gradient Stress Test".to_string(),
|
||||
resolution: WindowResolution::new(1920.0, 1080.0),
|
||||
present_mode: PresentMode::AutoNoVsync,
|
||||
..default()
|
||||
}),
|
||||
..default()
|
||||
}),
|
||||
))
|
||||
.insert_resource(args)
|
||||
.add_systems(Startup, setup)
|
||||
.add_systems(Update, animate_gradients)
|
||||
.run();
|
||||
}
|
||||
|
||||
fn setup(mut commands: Commands, args: Res<Args>) {
|
||||
commands.spawn(Camera2d);
|
||||
|
||||
let rows_to_spawn = (args.gradient_count + COLS - 1) / COLS;
|
||||
|
||||
// Create a grid of gradients
|
||||
commands
|
||||
.spawn(Node {
|
||||
width: Val::Percent(100.0),
|
||||
height: Val::Percent(100.0),
|
||||
display: Display::Grid,
|
||||
grid_template_columns: RepeatedGridTrack::flex(COLS as u16, 1.0),
|
||||
grid_template_rows: RepeatedGridTrack::flex(rows_to_spawn as u16, 1.0),
|
||||
..default()
|
||||
})
|
||||
.with_children(|parent| {
|
||||
for i in 0..args.gradient_count {
|
||||
let angle = (i as f32 * 10.0) % 360.0;
|
||||
|
||||
let mut gradient = LinearGradient::new(angle, vec![
|
||||
ColorStop::new(RED, Val::Percent(0.0)),
|
||||
ColorStop::new(BLUE, Val::Percent(100.0)),
|
||||
]);
|
||||
|
||||
gradient.color_space = if args.srgb {
|
||||
InterpolationColorSpace::Srgb
|
||||
} else if args.hsl {
|
||||
InterpolationColorSpace::Hsl
|
||||
} else {
|
||||
InterpolationColorSpace::OkLab
|
||||
};
|
||||
|
||||
parent.spawn((
|
||||
Node {
|
||||
width: Val::Percent(100.0),
|
||||
height: Val::Percent(100.0),
|
||||
..default()
|
||||
},
|
||||
BackgroundGradient(vec![Gradient::Linear(gradient)]),
|
||||
GradientNode { index: i },
|
||||
));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
struct GradientNode {
|
||||
index: usize,
|
||||
}
|
||||
|
||||
fn animate_gradients(
|
||||
mut gradients: Query<(&mut BackgroundGradient, &GradientNode)>,
|
||||
args: Res<Args>,
|
||||
time: Res<Time>,
|
||||
) {
|
||||
if !args.animate {
|
||||
return;
|
||||
}
|
||||
|
||||
let t = time.elapsed_secs();
|
||||
|
||||
for (mut bg_gradient, node) in &mut gradients {
|
||||
let offset = node.index as f32 * 0.01;
|
||||
let hue_shift = (t + offset).sin() * 0.5 + 0.5;
|
||||
|
||||
if let Some(Gradient::Linear(gradient)) = bg_gradient.0.get_mut(0) {
|
||||
let color1 = Color::hsl(hue_shift * 360.0, 1.0, 0.5);
|
||||
let color2 = Color::hsl((hue_shift + 0.3) * 360.0 % 360.0, 1.0, 0.5);
|
||||
|
||||
gradient.stops = vec![
|
||||
ColorStop::new(color1, Val::Percent(0.0)),
|
||||
ColorStop::new(color2, Val::Percent(100.0)),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user