use crate::draw::texture::Texture;
use crate::types::{Color, Fixed, Point, Rect, Transform};
pub fn fill_rect_transformed(
dst: &mut Texture,
phys_rect: Rect,
phys_clip: Rect,
tf: &Transform,
color: &Color,
opa: u8,
) {
let Some(inv) = tf.inverse() else { return };
let bbox = tf.apply_rect_bbox(phys_rect);
let Some(draw_area) = bbox.intersect(&phys_clip) else {
return;
};
let screen = Rect::new(0, 0, dst.width, dst.height);
let Some(draw_area) = draw_area.intersect(&screen) else {
return;
};
let (px_x0, px_y0, px_x1, px_y1) = draw_area.pixel_bounds();
let rx0 = phys_rect.x;
let ry0 = phys_rect.y;
let rx1 = phys_rect.x + phys_rect.w;
let ry1 = phys_rect.y + phys_rect.h;
for py in px_y0..px_y1 {
for px in px_x0..px_x1 {
let sample = inv.apply_point(Point {
x: Fixed::from_int(px) + Fixed::HALF,
y: Fixed::from_int(py) + Fixed::HALF,
});
if sample.x < rx0 || sample.x >= rx1 || sample.y < ry0 || sample.y >= ry1 {
continue;
}
if opa == 255 {
dst.set_pixel(px, py, color);
} else {
dst.blend_pixel_int(px, py, color, opa);
}
}
}
}
#[allow(clippy::too_many_arguments)]
pub fn blit_transformed(
dst: &mut Texture,
src: &Texture,
src_rect: &Rect,
phys_dst_rect: Rect,
phys_clip: Rect,
tf: &Transform,
) {
let Some(inv) = tf.inverse() else { return };
let bbox = tf.apply_rect_bbox(phys_dst_rect);
let Some(draw_area) = bbox.intersect(&phys_clip) else {
return;
};
let screen = Rect::new(0, 0, dst.width, dst.height);
let Some(draw_area) = draw_area.intersect(&screen) else {
return;
};
let (dx0, dy0, dx1, dy1) = draw_area.pixel_bounds();
let (sx0, sy0, sw, sh) = src_rect.to_px();
let dst_x0 = phys_dst_rect.x;
let dst_y0 = phys_dst_rect.y;
let dst_w = phys_dst_rect.w;
let dst_h = phys_dst_rect.h;
if dst_w <= Fixed::ZERO || dst_h <= Fixed::ZERO || sw == 0 || sh == 0 {
return;
}
for py in dy0..dy1 {
for px in dx0..dx1 {
let dp = inv.apply_point(Point {
x: Fixed::from_int(px) + Fixed::HALF,
y: Fixed::from_int(py) + Fixed::HALF,
});
let u = dp.x - dst_x0;
let v = dp.y - dst_y0;
if u < Fixed::ZERO || v < Fixed::ZERO || u >= dst_w || v >= dst_h {
continue;
}
let sx = sx0 + (u * Fixed::from_int(sw as i32) / dst_w).to_int();
let sy = sy0 + (v * Fixed::from_int(sh as i32) / dst_h).to_int();
if sx < sx0 || sx >= sx0 + sw as i32 || sy < sy0 || sy >= sy0 + sh as i32 {
continue;
}
let c = src.get_pixel(sx, sy);
if c.a == 0 {
continue;
}
if c.a == 255 {
dst.set_pixel(px, py, &c);
} else {
dst.blend_pixel_int(px, py, &c, c.a);
}
}
}
}
#[inline]
pub fn offset_rect(r: &Rect, tx: Fixed, ty: Fixed) -> Rect {
if tx == Fixed::ZERO && ty == Fixed::ZERO {
return *r;
}
Rect {
x: r.x + tx,
y: r.y + ty,
w: r.w,
h: r.h,
}
}
#[inline]
pub fn offset_point(p: &Point, tx: Fixed, ty: Fixed) -> Point {
Point {
x: p.x + tx,
y: p.y + ty,
}
}