use crate::draw::texture::{ColorFormat, Texture};
#[allow(clippy::too_many_arguments)]
pub fn blit_generic_slow(
dst: &mut Texture,
src: &Texture,
sx0: i32,
sy0: i32,
sw: u16,
sh: u16,
dx0: i32,
dy0: i32,
dw: i32,
dh: i32,
clip_x0: i32,
clip_y0: i32,
clip_x1: i32,
clip_y1: i32,
) {
for drow in 0..dh {
let iy = dy0 + drow;
if iy < clip_y0 || iy >= clip_y1 {
continue;
}
let sy = sy0 + (drow * sh as i32) / dh;
for dcol in 0..dw {
let ix = dx0 + dcol;
if ix < clip_x0 || ix >= clip_x1 {
continue;
}
let sx = sx0 + (dcol * sw as i32) / dw;
let src_color = src.get_pixel(sx, sy);
if src_color.a == 0 {
continue;
}
if src_color.a == 255 {
dst.set_pixel(ix, iy, &src_color);
} else {
dst.blend_pixel_int(ix, iy, &src_color, src_color.a);
}
}
}
}
#[allow(clippy::too_many_arguments)]
pub fn blit_1to1_fast(
dst: &mut Texture,
src: &Texture,
sx0: i32,
sy0: i32,
sw: u16,
sh: u16,
dx0: i32,
dy0: i32,
clip_x0: i32,
clip_y0: i32,
clip_x1: i32,
clip_y1: i32,
) {
let vx0 = dx0.max(clip_x0);
let vy0 = dy0.max(clip_y0);
let vx1 = (dx0 + sw as i32).min(clip_x1);
let vy1 = (dy0 + sh as i32).min(clip_y1);
if vx1 <= vx0 || vy1 <= vy0 {
return;
}
let src_x0 = sx0 + (vx0 - dx0);
let src_y0 = sy0 + (vy0 - dy0);
let run_w = (vx1 - vx0) as usize;
let run_h = (vy1 - vy0) as usize;
match (src.format, dst.format) {
(ColorFormat::RGBA8888, ColorFormat::RGBA8888) => {
blit_1to1_argb_to_argb(dst, src, src_x0, src_y0, vx0, vy0, run_w, run_h)
}
(ColorFormat::RGBA8888, ColorFormat::RGB565Swapped) => {
blit_1to1_argb_to_565sw(dst, src, src_x0, src_y0, vx0, vy0, run_w, run_h)
}
(ColorFormat::RGB565Swapped, ColorFormat::RGB565Swapped) => {
blit_1to1_565sw_to_565sw(dst, src, src_x0, src_y0, vx0, vy0, run_w, run_h)
}
(ColorFormat::RGBA8888, ColorFormat::RGB565) => {
blit_1to1_argb_to_565(dst, src, src_x0, src_y0, vx0, vy0, run_w, run_h)
}
_ => blit_generic_slow(
dst,
src,
src_x0,
src_y0,
run_w as u16,
run_h as u16,
vx0,
vy0,
run_w as i32,
run_h as i32,
clip_x0,
clip_y0,
clip_x1,
clip_y1,
),
}
}
#[allow(clippy::too_many_arguments)]
fn blit_1to1_argb_to_argb(
dst: &mut Texture,
src: &Texture,
sx0: i32,
sy0: i32,
dx0: i32,
dy0: i32,
run_w: usize,
run_h: usize,
) {
let src_stride = src.stride;
let dst_stride = dst.stride;
let src_buf = src.buf.as_slice();
let dst_buf = dst.buf.as_mut_slice();
for row in 0..run_h {
let src_row_off = (sy0 as usize + row) * src_stride + sx0 as usize * 4;
let dst_row_off = (dy0 as usize + row) * dst_stride + dx0 as usize * 4;
for col in 0..run_w {
let si = src_row_off + col * 4;
let di = dst_row_off + col * 4;
let a = src_buf[si + 3];
if a == 0 {
continue;
}
if a == 255 {
dst_buf[di] = src_buf[si];
dst_buf[di + 1] = src_buf[si + 1];
dst_buf[di + 2] = src_buf[si + 2];
dst_buf[di + 3] = 255;
} else {
let inv = 255 - a as u16;
let sa = a as u16;
dst_buf[di] = ((src_buf[si] as u16 * sa + dst_buf[di] as u16 * inv) / 255) as u8;
dst_buf[di + 1] =
((src_buf[si + 1] as u16 * sa + dst_buf[di + 1] as u16 * inv) / 255) as u8;
dst_buf[di + 2] =
((src_buf[si + 2] as u16 * sa + dst_buf[di + 2] as u16 * inv) / 255) as u8;
dst_buf[di + 3] = 255;
}
}
}
}
#[allow(clippy::too_many_arguments)]
fn blit_1to1_argb_to_565sw(
dst: &mut Texture,
src: &Texture,
sx0: i32,
sy0: i32,
dx0: i32,
dy0: i32,
run_w: usize,
run_h: usize,
) {
let src_stride = src.stride;
let dst_stride = dst.stride;
let src_buf = src.buf.as_slice();
let dst_buf = dst.buf.as_mut_slice();
for row in 0..run_h {
let src_row_off = (sy0 as usize + row) * src_stride + sx0 as usize * 4;
let dst_row_off = (dy0 as usize + row) * dst_stride + dx0 as usize * 2;
for col in 0..run_w {
let si = src_row_off + col * 4;
let di = dst_row_off + col * 2;
let a = src_buf[si + 3];
if a == 0 {
continue;
}
let (r, g, b) = if a == 255 {
(src_buf[si], src_buf[si + 1], src_buf[si + 2])
} else {
let hi = dst_buf[di] as u16;
let lo = dst_buf[di + 1] as u16;
let px = lo | (hi << 8);
let dr = ((px >> 11) as u8) << 3;
let dg = (((px >> 5) & 0x3F) as u8) << 2;
let db = ((px & 0x1F) as u8) << 3;
let inv = 255 - a as u16;
let sa = a as u16;
(
((src_buf[si] as u16 * sa + dr as u16 * inv) / 255) as u8,
((src_buf[si + 1] as u16 * sa + dg as u16 * inv) / 255) as u8,
((src_buf[si + 2] as u16 * sa + db as u16 * inv) / 255) as u8,
)
};
let px = ((r as u16 >> 3) << 11) | ((g as u16 >> 2) << 5) | (b as u16 >> 3);
dst_buf[di] = (px >> 8) as u8;
dst_buf[di + 1] = px as u8;
}
}
}
#[allow(clippy::too_many_arguments)]
fn blit_1to1_565sw_to_565sw(
dst: &mut Texture,
src: &Texture,
sx0: i32,
sy0: i32,
dx0: i32,
dy0: i32,
run_w: usize,
run_h: usize,
) {
let src_stride = src.stride;
let dst_stride = dst.stride;
let src_buf = src.buf.as_slice();
let dst_buf = dst.buf.as_mut_slice();
for row in 0..run_h {
let src_row_off = (sy0 as usize + row) * src_stride + sx0 as usize * 2;
let dst_row_off = (dy0 as usize + row) * dst_stride + dx0 as usize * 2;
dst_buf[dst_row_off..dst_row_off + run_w * 2]
.copy_from_slice(&src_buf[src_row_off..src_row_off + run_w * 2]);
}
}
#[allow(clippy::too_many_arguments)]
fn blit_1to1_argb_to_565(
dst: &mut Texture,
src: &Texture,
sx0: i32,
sy0: i32,
dx0: i32,
dy0: i32,
run_w: usize,
run_h: usize,
) {
let src_stride = src.stride;
let dst_stride = dst.stride;
let src_buf = src.buf.as_slice();
let dst_buf = dst.buf.as_mut_slice();
for row in 0..run_h {
let src_row_off = (sy0 as usize + row) * src_stride + sx0 as usize * 4;
let dst_row_off = (dy0 as usize + row) * dst_stride + dx0 as usize * 2;
for col in 0..run_w {
let si = src_row_off + col * 4;
let di = dst_row_off + col * 2;
let a = src_buf[si + 3];
if a == 0 {
continue;
}
let (r, g, b) = if a == 255 {
(src_buf[si], src_buf[si + 1], src_buf[si + 2])
} else {
let lo = dst_buf[di] as u16;
let hi = dst_buf[di + 1] as u16;
let px = lo | (hi << 8);
let dr = ((px >> 11) as u8) << 3;
let dg = (((px >> 5) & 0x3F) as u8) << 2;
let db = ((px & 0x1F) as u8) << 3;
let inv = 255 - a as u16;
let sa = a as u16;
(
((src_buf[si] as u16 * sa + dr as u16 * inv) / 255) as u8,
((src_buf[si + 1] as u16 * sa + dg as u16 * inv) / 255) as u8,
((src_buf[si + 2] as u16 * sa + db as u16 * inv) / 255) as u8,
)
};
let px = ((r as u16 >> 3) << 11) | ((g as u16 >> 2) << 5) | (b as u16 >> 3);
dst_buf[di] = px as u8;
dst_buf[di + 1] = (px >> 8) as u8;
}
}
}
#[allow(clippy::too_many_arguments)]
pub fn blit_2to2_fast(
dst: &mut Texture,
src: &Texture,
sx0: i32,
sy0: i32,
sw: u16,
sh: u16,
dx0: i32,
dy0: i32,
clip_x0: i32,
clip_y0: i32,
clip_x1: i32,
clip_y1: i32,
) {
let vx0 = dx0.max(clip_x0);
let vy0 = dy0.max(clip_y0);
let vx1 = (dx0 + (sw as i32) * 2).min(clip_x1);
let vy1 = (dy0 + (sh as i32) * 2).min(clip_y1);
if vx1 <= vx0 || vy1 <= vy0 {
return;
}
let dx_off = vx0 - dx0;
let dy_off = vy0 - dy0;
if dx_off & 1 != 0 || dy_off & 1 != 0 || (vx1 - vx0) & 1 != 0 || (vy1 - vy0) & 1 != 0 {
blit_dda(
dst,
src,
sx0,
sy0,
sw,
sh,
dx0,
dy0,
(sw as i32) * 2,
(sh as i32) * 2,
clip_x0,
clip_y0,
clip_x1,
clip_y1,
);
return;
}
let src_x0 = sx0 + dx_off / 2;
let src_y0 = sy0 + dy_off / 2;
let block_w = (vx1 - vx0) as usize / 2;
let block_h = (vy1 - vy0) as usize / 2;
match (src.format, dst.format) {
(ColorFormat::RGBA8888, ColorFormat::RGBA8888) => {
blit_2to2_argb_to_argb(dst, src, src_x0, src_y0, vx0, vy0, block_w, block_h)
}
(ColorFormat::RGBA8888, ColorFormat::RGB565Swapped) => {
blit_2to2_argb_to_565sw(dst, src, src_x0, src_y0, vx0, vy0, block_w, block_h)
}
(ColorFormat::RGB565Swapped, ColorFormat::RGB565Swapped) => {
blit_2to2_565sw_to_565sw(dst, src, src_x0, src_y0, vx0, vy0, block_w, block_h)
}
(ColorFormat::RGBA8888, ColorFormat::RGB565) => {
blit_2to2_argb_to_565(dst, src, src_x0, src_y0, vx0, vy0, block_w, block_h)
}
_ => blit_dda(
dst,
src,
sx0,
sy0,
sw,
sh,
dx0,
dy0,
(sw as i32) * 2,
(sh as i32) * 2,
clip_x0,
clip_y0,
clip_x1,
clip_y1,
),
}
}
#[allow(clippy::too_many_arguments)]
fn blit_2to2_argb_to_argb(
dst: &mut Texture,
src: &Texture,
sx0: i32,
sy0: i32,
dx0: i32,
dy0: i32,
block_w: usize,
block_h: usize,
) {
let src_stride = src.stride;
let dst_stride = dst.stride;
let src_buf = src.buf.as_slice();
let dst_buf = dst.buf.as_mut_slice();
for block_row in 0..block_h {
let src_row_off = (sy0 as usize + block_row) * src_stride + sx0 as usize * 4;
let dst_row0 = (dy0 as usize + block_row * 2) * dst_stride + dx0 as usize * 4;
let dst_row1 = dst_row0 + dst_stride;
for col in 0..block_w {
let si = src_row_off + col * 4;
let a = src_buf[si + 3];
if a == 0 {
continue;
}
let px = [src_buf[si], src_buf[si + 1], src_buf[si + 2], a];
if a == 255 {
let d00 = dst_row0 + col * 8;
let d01 = d00 + 4;
let d10 = dst_row1 + col * 8;
let d11 = d10 + 4;
dst_buf[d00..d00 + 4].copy_from_slice(&px);
dst_buf[d01..d01 + 4].copy_from_slice(&px);
dst_buf[d10..d10 + 4].copy_from_slice(&px);
dst_buf[d11..d11 + 4].copy_from_slice(&px);
} else {
let inv = 255 - a as u16;
let sa = a as u16;
for &di in &[
dst_row0 + col * 8,
dst_row0 + col * 8 + 4,
dst_row1 + col * 8,
dst_row1 + col * 8 + 4,
] {
dst_buf[di] = ((px[0] as u16 * sa + dst_buf[di] as u16 * inv) / 255) as u8;
dst_buf[di + 1] =
((px[1] as u16 * sa + dst_buf[di + 1] as u16 * inv) / 255) as u8;
dst_buf[di + 2] =
((px[2] as u16 * sa + dst_buf[di + 2] as u16 * inv) / 255) as u8;
dst_buf[di + 3] = 255;
}
}
}
}
}
#[allow(clippy::too_many_arguments)]
fn blit_2to2_argb_to_565sw(
dst: &mut Texture,
src: &Texture,
sx0: i32,
sy0: i32,
dx0: i32,
dy0: i32,
block_w: usize,
block_h: usize,
) {
let src_stride = src.stride;
let dst_stride = dst.stride;
let src_buf = src.buf.as_slice();
let dst_buf = dst.buf.as_mut_slice();
for block_row in 0..block_h {
let src_row_off = (sy0 as usize + block_row) * src_stride + sx0 as usize * 4;
let dst_row0 = (dy0 as usize + block_row * 2) * dst_stride + dx0 as usize * 2;
let dst_row1 = dst_row0 + dst_stride;
for col in 0..block_w {
let si = src_row_off + col * 4;
let a = src_buf[si + 3];
if a == 0 {
continue;
}
if a == 255 {
let r = src_buf[si] as u16;
let g = src_buf[si + 1] as u16;
let b = src_buf[si + 2] as u16;
let px = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
let hi = (px >> 8) as u8;
let lo = px as u8;
let d00 = dst_row0 + col * 4;
let d10 = dst_row1 + col * 4;
dst_buf[d00] = hi;
dst_buf[d00 + 1] = lo;
dst_buf[d00 + 2] = hi;
dst_buf[d00 + 3] = lo;
dst_buf[d10] = hi;
dst_buf[d10 + 1] = lo;
dst_buf[d10 + 2] = hi;
dst_buf[d10 + 3] = lo;
} else {
let sr = src_buf[si];
let sg = src_buf[si + 1];
let sb = src_buf[si + 2];
let inv = 255 - a as u16;
let sa = a as u16;
for &di in &[
dst_row0 + col * 4,
dst_row0 + col * 4 + 2,
dst_row1 + col * 4,
dst_row1 + col * 4 + 2,
] {
let hi = dst_buf[di] as u16;
let lo = dst_buf[di + 1] as u16;
let dpx = lo | (hi << 8);
let dr = ((dpx >> 11) as u8) << 3;
let dg = (((dpx >> 5) & 0x3F) as u8) << 2;
let db = ((dpx & 0x1F) as u8) << 3;
let br = ((sr as u16 * sa + dr as u16 * inv) / 255) as u8;
let bg = ((sg as u16 * sa + dg as u16 * inv) / 255) as u8;
let bb = ((sb as u16 * sa + db as u16 * inv) / 255) as u8;
let px = ((br as u16 >> 3) << 11) | ((bg as u16 >> 2) << 5) | (bb as u16 >> 3);
dst_buf[di] = (px >> 8) as u8;
dst_buf[di + 1] = px as u8;
}
}
}
}
}
#[allow(clippy::too_many_arguments)]
fn blit_2to2_565sw_to_565sw(
dst: &mut Texture,
src: &Texture,
sx0: i32,
sy0: i32,
dx0: i32,
dy0: i32,
block_w: usize,
block_h: usize,
) {
let src_stride = src.stride;
let dst_stride = dst.stride;
let src_buf = src.buf.as_slice();
let dst_buf = dst.buf.as_mut_slice();
for block_row in 0..block_h {
let src_row_off = (sy0 as usize + block_row) * src_stride + sx0 as usize * 2;
let dst_row0 = (dy0 as usize + block_row * 2) * dst_stride + dx0 as usize * 2;
let dst_row1 = dst_row0 + dst_stride;
for col in 0..block_w {
let si = src_row_off + col * 2;
let hi = src_buf[si];
let lo = src_buf[si + 1];
let d00 = dst_row0 + col * 4;
let d10 = dst_row1 + col * 4;
dst_buf[d00] = hi;
dst_buf[d00 + 1] = lo;
dst_buf[d00 + 2] = hi;
dst_buf[d00 + 3] = lo;
dst_buf[d10] = hi;
dst_buf[d10 + 1] = lo;
dst_buf[d10 + 2] = hi;
dst_buf[d10 + 3] = lo;
}
}
}
#[allow(clippy::too_many_arguments)]
fn blit_2to2_argb_to_565(
dst: &mut Texture,
src: &Texture,
sx0: i32,
sy0: i32,
dx0: i32,
dy0: i32,
block_w: usize,
block_h: usize,
) {
let src_stride = src.stride;
let dst_stride = dst.stride;
let src_buf = src.buf.as_slice();
let dst_buf = dst.buf.as_mut_slice();
for block_row in 0..block_h {
let src_row_off = (sy0 as usize + block_row) * src_stride + sx0 as usize * 4;
let dst_row0 = (dy0 as usize + block_row * 2) * dst_stride + dx0 as usize * 2;
let dst_row1 = dst_row0 + dst_stride;
for col in 0..block_w {
let si = src_row_off + col * 4;
let a = src_buf[si + 3];
if a == 0 {
continue;
}
if a == 255 {
let r = src_buf[si] as u16;
let g = src_buf[si + 1] as u16;
let b = src_buf[si + 2] as u16;
let px = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
let lo = px as u8;
let hi = (px >> 8) as u8;
let d00 = dst_row0 + col * 4;
let d10 = dst_row1 + col * 4;
dst_buf[d00] = lo;
dst_buf[d00 + 1] = hi;
dst_buf[d00 + 2] = lo;
dst_buf[d00 + 3] = hi;
dst_buf[d10] = lo;
dst_buf[d10 + 1] = hi;
dst_buf[d10 + 2] = lo;
dst_buf[d10 + 3] = hi;
} else {
let sr = src_buf[si];
let sg = src_buf[si + 1];
let sb = src_buf[si + 2];
let inv = 255 - a as u16;
let sa = a as u16;
for &di in &[
dst_row0 + col * 4,
dst_row0 + col * 4 + 2,
dst_row1 + col * 4,
dst_row1 + col * 4 + 2,
] {
let lo = dst_buf[di] as u16;
let hi = dst_buf[di + 1] as u16;
let dpx = lo | (hi << 8);
let dr = ((dpx >> 11) as u8) << 3;
let dg = (((dpx >> 5) & 0x3F) as u8) << 2;
let db = ((dpx & 0x1F) as u8) << 3;
let br = ((sr as u16 * sa + dr as u16 * inv) / 255) as u8;
let bg = ((sg as u16 * sa + dg as u16 * inv) / 255) as u8;
let bb = ((sb as u16 * sa + db as u16 * inv) / 255) as u8;
let px = ((br as u16 >> 3) << 11) | ((bg as u16 >> 2) << 5) | (bb as u16 >> 3);
dst_buf[di] = px as u8;
dst_buf[di + 1] = (px >> 8) as u8;
}
}
}
}
}
#[allow(clippy::too_many_arguments)]
pub fn blit_dda(
dst: &mut Texture,
src: &Texture,
sx0: i32,
sy0: i32,
sw: u16,
sh: u16,
dx0: i32,
dy0: i32,
dw: i32,
dh: i32,
clip_x0: i32,
clip_y0: i32,
clip_x1: i32,
clip_y1: i32,
) {
let sx_step = ((sw as u32) << 16) / dw as u32;
let sy_step = ((sh as u32) << 16) / dh as u32;
let mut sy_acc: u32 = 0;
for drow in 0..dh {
let iy = dy0 + drow;
if iy < clip_y0 || iy >= clip_y1 {
sy_acc = sy_acc.wrapping_add(sy_step);
continue;
}
let sy = sy0 + (sy_acc >> 16) as i32;
sy_acc = sy_acc.wrapping_add(sy_step);
let mut sx_acc: u32 = 0;
for dcol in 0..dw {
let ix = dx0 + dcol;
if ix < clip_x0 || ix >= clip_x1 {
sx_acc = sx_acc.wrapping_add(sx_step);
continue;
}
let sx = sx0 + (sx_acc >> 16) as i32;
sx_acc = sx_acc.wrapping_add(sx_step);
let src_color = src.get_pixel(sx, sy);
if src_color.a == 0 {
continue;
}
if src_color.a == 255 {
dst.set_pixel(ix, iy, &src_color);
} else {
dst.blend_pixel_int(ix, iy, &src_color, src_color.a);
}
}
}
}