use crate::renderer::GlowCommand;
use crate::{HaloMode, HaloStyle, QueuedItem, RenderItem};
use crate::{PlutoniumEngine, Rectangle};
use uuid::Uuid;
impl<'a> PlutoniumEngine<'a> {
fn draw_halo_world_rect(&mut self, world_rect: Rectangle, style: HaloStyle) {
let radius = style.radius.max(0.0);
if radius <= f32::EPSILON {
return;
}
let glow_radius = radius + style.inner_padding.max(0.0);
let (mode_f, sigma) = match style.mode {
HaloMode::Glow => (0.0_f32, glow_radius / 2.5),
HaloMode::Border => (1.0_f32, style.border_width / 2.0),
};
let effective_alpha = style.alpha_at(0.0);
if effective_alpha <= 0.0 {
return;
}
let oversized_bounds = Rectangle::new(
world_rect.x - glow_radius,
world_rect.y - glow_radius,
world_rect.width + glow_radius * 2.0,
world_rect.height + glow_radius * 2.0,
);
let pos = crate::utils::Position {
x: oversized_bounds.x,
y: oversized_bounds.y,
} * self.dpi_scale_factor;
let size = oversized_bounds.size() * self.dpi_scale_factor;
let width_ndc = size.width / self.viewport_size.width;
let height_ndc = size.height / self.viewport_size.height;
let ndc_dx = (2.0 * (pos.x - self.camera.get_pos(self.dpi_scale_factor).x))
/ self.viewport_size.width
- 1.0;
let ndc_dy = 1.0
- (2.0 * (pos.y - self.camera.get_pos(self.dpi_scale_factor).y))
/ self.viewport_size.height;
let ndc_x = ndc_dx + width_ndc;
let ndc_y = ndc_dy - height_ndc;
let model = [
[width_ndc, 0.0, 0.0, 0.0],
[0.0, height_ndc, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[ndc_x, ndc_y, 0.0, 1.0],
];
let inner_size = world_rect.size() * self.dpi_scale_factor;
let rgb = [
style.color[0].clamp(0.0, 1.0),
style.color[1].clamp(0.0, 1.0),
style.color[2].clamp(0.0, 1.0),
];
let cmd = GlowCommand {
transform: model,
color: [rgb[0], rgb[1], rgb[2], effective_alpha],
width_px: inner_size.width,
height_px: inner_size.height,
corner_radius_px: style.corner_radius * self.dpi_scale_factor,
glow_radius_px: glow_radius * self.dpi_scale_factor,
sigma: sigma * self.dpi_scale_factor,
max_alpha: style.max_alpha.clamp(0.0, 1.0),
mode: mode_f,
border_width: style.border_width * self.dpi_scale_factor,
};
self.render_queue.push(QueuedItem {
z: style.z,
clip_rect: None,
item: RenderItem::Glow(cmd),
});
}
pub fn draw_halo(&mut self, target_rect: Rectangle, style: HaloStyle) {
let world_rect = self.halo_world_rect_from_screen_rect(target_rect);
self.draw_halo_world_rect(world_rect, style);
}
pub fn draw_rect_glow(
&mut self,
rect: Rectangle,
color: [f32; 4],
thickness: f32, glow_radius: f32, corner_radius: f32, intensity: f32, z: i32,
) {
let world_rect = self.halo_world_rect_from_screen_rect(rect);
let glow_radius_capped = glow_radius.max(0.0);
let thickness_capped = thickness.max(0.0);
let oversized_bounds = Rectangle::new(
world_rect.x - glow_radius_capped,
world_rect.y - glow_radius_capped,
world_rect.width + glow_radius_capped * 2.0,
world_rect.height + glow_radius_capped * 2.0,
);
let pos = crate::utils::Position {
x: oversized_bounds.x,
y: oversized_bounds.y,
} * self.dpi_scale_factor;
let size = oversized_bounds.size() * self.dpi_scale_factor;
let width_ndc = size.width / self.viewport_size.width;
let height_ndc = size.height / self.viewport_size.height;
let ndc_dx = (2.0 * (pos.x - self.camera.get_pos(self.dpi_scale_factor).x))
/ self.viewport_size.width
- 1.0;
let ndc_dy = 1.0
- (2.0 * (pos.y - self.camera.get_pos(self.dpi_scale_factor).y))
/ self.viewport_size.height;
let ndc_x = ndc_dx + width_ndc;
let ndc_y = ndc_dy - height_ndc;
let model = [
[width_ndc, 0.0, 0.0, 0.0],
[0.0, height_ndc, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[ndc_x, ndc_y, 0.0, 1.0],
];
let inner_size = world_rect.size() * self.dpi_scale_factor;
let cmd = GlowCommand {
transform: model,
color: [color[0], color[1], color[2], color[3] * intensity],
width_px: inner_size.width,
height_px: inner_size.height,
corner_radius_px: corner_radius * self.dpi_scale_factor,
glow_radius_px: glow_radius_capped * self.dpi_scale_factor, sigma: glow_radius_capped * self.dpi_scale_factor,
max_alpha: (color[3] * intensity).clamp(0.0, 1.0),
mode: 2.0, border_width: thickness_capped * self.dpi_scale_factor,
};
self.render_queue.push(QueuedItem {
z,
clip_rect: None,
item: RenderItem::Glow(cmd),
});
}
pub fn draw_halo_for_object(&mut self, object_id: &Uuid, style: HaloStyle) -> bool {
let bounds = match self.pluto_objects.get(object_id) {
Some(obj) => obj.borrow().dimensions(),
None => return false,
};
if bounds.width <= 0.0 || bounds.height <= 0.0 {
return false;
}
let screen_bounds = self.halo_screen_rect_from_world_rect(bounds);
if !Self::rects_intersect(screen_bounds, self.screen_space_viewport_rect()) {
return false;
}
self.draw_halo(screen_bounds, style);
true
}
}