diff --git a/examples/every_option.rs b/examples/every_option.rs index 73ee7be3c21919e244b446f682b05eedd60a2fed..431906892ac73b7248cc820fdcf0bf830faa3c03 100644 --- a/examples/every_option.rs +++ b/examples/every_option.rs @@ -23,6 +23,7 @@ fn setup(mut commands: Commands, windows: Query<&Window, With<PrimaryWindow>>) { interaction: Interaction::default(), focus_policy: FocusPolicy::default(), text_position: CosmicTextPosition::default(), + fill_color: FillColor::default(), background_color: BackgroundColor::default(), global_transform: GlobalTransform::default(), background_image: CosmicBackground::default(), diff --git a/examples/multiple_sprites.rs b/examples/multiple_sprites.rs index 3fab9d47117ec3dc98430cfa93530b4202df8cdd..ad24adf121e8d9eb7b7a2c5cbfd34874b260acd5 100644 --- a/examples/multiple_sprites.rs +++ b/examples/multiple_sprites.rs @@ -32,7 +32,7 @@ fn setup(mut commands: Commands, windows: Query<&Window, With<PrimaryWindow>>) { }, transform: Transform::from_translation(Vec3::new(-primary_window.width() / 4., 0., 1.)), text_position: CosmicTextPosition::Center, - background_color: BackgroundColor(Color::ALICE_BLUE), + fill_color: FillColor(Color::ALICE_BLUE), text_setter: CosmicText::OneStyle("馃榾馃榾馃榾 x => y".to_string()), ..default() }; @@ -53,7 +53,7 @@ fn setup(mut commands: Commands, windows: Query<&Window, With<PrimaryWindow>>) { 1., )), text_position: CosmicTextPosition::Center, - background_color: BackgroundColor(Color::GRAY.with_a(0.5)), + fill_color: FillColor(Color::GRAY.with_a(0.5)), text_setter: CosmicText::OneStyle("Widget_2. Click on me".to_string()), ..default() }; diff --git a/src/lib.rs b/src/lib.rs index 747dcb8ebfa415319a719a9ae2c24d3b26dc0ec2..d45c5d3b620e0a95f7ac6b905a46a21ae63d0e16 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -211,6 +211,9 @@ pub struct CosmicMaxLines(pub usize); #[derive(Component, Default)] pub struct CosmicMaxChars(pub usize); +#[derive(Component, Default)] +pub struct FillColor(pub Color); + #[derive(Bundle)] pub struct CosmicEditUiBundle { // Bevy UI bits @@ -225,8 +228,10 @@ pub struct CosmicEditUiBundle { pub interaction: Interaction, /// Whether this node should block interaction with lower nodes pub focus_policy: FocusPolicy, - /// The background color, which serves as a "fill" for this node + /// UiNode Background Color, works as a tint. pub background_color: BackgroundColor, + /// The background color, which serves as a "fill" for this node + pub fill_color: FillColor, /// The color of the Node's border pub border_color: BorderColor, /// This is used as the cosmic text canvas @@ -275,7 +280,7 @@ impl Default for CosmicEditUiBundle { style: Default::default(), border_color: BorderColor(Color::NONE), interaction: Default::default(), - background_color: Default::default(), + fill_color: Default::default(), image: Default::default(), transform: Default::default(), global_transform: Default::default(), @@ -290,6 +295,7 @@ impl Default for CosmicEditUiBundle { max_chars: Default::default(), text_setter: Default::default(), mode: Default::default(), + background_color: BackgroundColor(Color::WHITE), } } } @@ -305,8 +311,8 @@ pub struct CosmicEditSpriteBundle { pub visibility: Visibility, /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering pub computed_visibility: ComputedVisibility, - // - pub background_color: BackgroundColor, + /// Widget background color + pub fill_color: FillColor, // cosmic bits /// text positioning enum pub text_position: CosmicTextPosition, @@ -335,7 +341,7 @@ impl Default for CosmicEditSpriteBundle { texture: DEFAULT_IMAGE_HANDLE.typed(), visibility: Visibility::Visible, computed_visibility: Default::default(), - background_color: Default::default(), + fill_color: Default::default(), text_position: Default::default(), cosmic_metrics: Default::default(), cosmic_attrs: Default::default(), @@ -1137,7 +1143,7 @@ fn redraw_buffer_common( editor: &mut Editor, attrs: &CosmicAttrs, background_image: Option<Handle<Image>>, - background_color: Color, + fill_color: Color, cosmic_canvas_img_handle: &mut Handle<Image>, text_position: &CosmicTextPosition, font_system: &mut ResMut<CosmicFontSystem>, @@ -1212,7 +1218,7 @@ fn redraw_buffer_common( } } } else { - let bg = background_color; + let bg = fill_color; for pixel in pixels.chunks_exact_mut(4) { pixel[0] = (bg.r() * 255.) as u8; // Red component pixel[1] = (bg.g() * 255.) as u8; // Green component @@ -1288,7 +1294,7 @@ fn cosmic_edit_redraw_buffer_ui( &mut CosmicEditor, &CosmicAttrs, &CosmicBackground, - &BackgroundColor, + &FillColor, &CosmicTextPosition, &mut UiImage, &Node, @@ -1305,7 +1311,7 @@ fn cosmic_edit_redraw_buffer_ui( mut editor, attrs, background_image, - background_color, + fill_color, text_position, mut img, node, @@ -1351,7 +1357,7 @@ fn cosmic_edit_redraw_buffer_ui( &mut editor.0, attrs, background_image.0.clone(), - background_color.0, + fill_color.0, &mut img.texture, text_position, &mut font_system, @@ -1484,7 +1490,7 @@ fn cosmic_edit_redraw_buffer( &CosmicAttrs, &mut Sprite, &CosmicBackground, - &BackgroundColor, + &FillColor, &CosmicTextPosition, &mut Handle<Image>, &mut XOffset, @@ -1500,7 +1506,7 @@ fn cosmic_edit_redraw_buffer( attrs, sprite, background_image, - background_color, + fill_color, text_position, mut handle, mut x_offset, @@ -1543,7 +1549,7 @@ fn cosmic_edit_redraw_buffer( &mut editor.0, attrs, background_image.0.clone(), - background_color.0, + fill_color.0, &mut handle, text_position, &mut font_system, @@ -1562,8 +1568,9 @@ fn draw_pixel( y: i32, color: cosmic_text::Color, ) { - let alpha = (color.0 >> 24) & 0xFF; - if alpha == 0 { + // TODO: perftest this fn against previous iteration + let a_a = color.a() as u32; + if a_a == 0 { // Do not draw if alpha is zero return; } @@ -1580,27 +1587,25 @@ fn draw_pixel( let offset = (y as usize * width as usize + x as usize) * 4; - let mut current = buffer[offset + 2] as u32 - | (buffer[offset + 1] as u32) << 8 - | (buffer[offset] as u32) << 16 - | (buffer[offset + 3] as u32) << 24; + let bg = Color::rgba_u8( + buffer[offset], + buffer[offset + 1], + buffer[offset + 2], + buffer[offset + 3], + ); - if alpha >= 255 || current == 0 { - // Alpha is 100% or current is null, replace with no blending - current = color.0; - } else { - // Alpha blend with current value - let n_alpha = 255 - alpha; - let rb = ((n_alpha * (current & 0x00FF00FF)) + (alpha * (color.0 & 0x00FF00FF))) >> 8; - let ag = (n_alpha * ((current & 0xFF00FF00) >> 8)) - + (alpha * (0x01000000 | ((color.0 & 0x0000FF00) >> 8))); - current = (rb & 0x00FF00FF) | (ag & 0xFF00FF00); - } + // TODO: if alpha is 100% or bg is empty skip blending + + let fg = Color::rgba_u8(color.r(), color.g(), color.b(), color.a()); + + let premul = fg * Vec3::splat(color.a() as f32 / 255.0); + + let out = premul + bg * (1.0 - fg.a()); - buffer[offset + 2] = current as u8; - buffer[offset + 1] = (current >> 8) as u8; - buffer[offset] = (current >> 16) as u8; - buffer[offset + 3] = (current >> 24) as u8; + buffer[offset + 2] = (out.b() * 255.0) as u8; + buffer[offset + 1] = (out.g() * 255.0) as u8; + buffer[offset] = (out.r() * 255.0) as u8; + buffer[offset + 3] = (bg.a() * 255.0) as u8; } #[cfg(target_arch = "wasm32")]