use crate::*; pub fn cell_diff_4_vertical(prev_frame: &Frame, frame: &Frame, loss: usize) -> EncodedFrame { let loss = loss / 4; const CELLS_X: usize = WIDTH / 4; const CELLS_Y: usize = HEIGHT / 4; let mut modified_cells = [[0; CELLS_Y]; CELLS_X]; for cellx in 0..CELLS_X { for celly in 0..CELLS_Y { let mut changed = 0; for dx in 0..4 { for dy in 0..4 { let x = cellx * 4 + dx; let y = celly * 4 + dy; let pixel = frame[x][y]; if pixel != prev_frame[x][y] { changed += 1; } } } if changed > loss { modified_cells[cellx][celly] = 1; } } } let mut changed_pixels = Vec::new(); for x in 0..WIDTH { for y in 0..HEIGHT { let cellx = x / 4; let celly = y / 4; if modified_cells[cellx][celly] != 0 { changed_pixels.push(frame[x][y]); } } } let mut modified_cells_flat = Vec::new(); for x in 0..CELLS_X { for y in 0..CELLS_Y { modified_cells_flat.push(modified_cells[x][y]); } } let mut data = Vec::new(); data.extend_from_slice(&pack_nybbles(rle_encode(&modified_cells_flat, 15))); data.extend_from_slice(&rle_255_encode(&changed_pixels)); EncodedFrame { encoding: Encoding::CellDiff4VV, data, } } pub fn cell_diff_8_vertical_big(prev_frame: &Frame, frame: &Frame, loss: usize) -> EncodedFrame { let loss = loss / 8; const CELLS_X: usize = WIDTH / 8; const CELLS_Y: usize = HEIGHT / 8; let mut modified_cells = [[0; CELLS_Y]; CELLS_X]; for cellx in 0..CELLS_X { for celly in 0..CELLS_Y { let mut changed = 0; for dx in 0..8 { for dy in 0..8 { let x = cellx * 8 + dx; let y = celly * 8 + dy; let pixel = frame[x][y]; if pixel != prev_frame[x][y] { changed += 1; } } } if changed > loss { modified_cells[cellx][celly] = 1; } } } let mut changed_pixels = Vec::new(); for x in 0..WIDTH { for y in 0..HEIGHT { let cellx = x / 8; let celly = y / 8; if modified_cells[cellx][celly] != 0 { changed_pixels.push(frame[x][y]); } } } let mut modified_cells_flat = Vec::new(); for x in 0..CELLS_X { for y in 0..CELLS_Y { modified_cells_flat.push(modified_cells[x][y]); } } let mut data = Vec::new(); data.extend_from_slice(&pack_nybbles(rle_encode(&modified_cells_flat, 15))); data.extend_from_slice(&rle_255_encode(&changed_pixels)); EncodedFrame { encoding: Encoding::CellDiff8VBig, data, } } pub fn cell_diff_8_vertical(prev_frame: &Frame, frame: &Frame, loss: usize) -> EncodedFrame { const CELLS_X: usize = WIDTH / 8; const CELLS_Y: usize = HEIGHT / 8; let mut bitmap: u32 = 0; for cellx in 0..CELLS_X { for celly in 0..CELLS_Y { let mut changed = 0; for dx in 0..8 { for dy in 0..8 { let x = cellx * 8 + dx; let y = celly * 8 + dy; let pixel = frame[x][y]; if pixel != prev_frame[x][y] { changed += 1; } } } if changed > loss { bitmap |= 1 << (cellx + CELLS_X * celly); } } } let mut changed_pixels = Vec::new(); for x in 0..WIDTH { for y in 0..HEIGHT { let cellx = x / 8; let celly = y / 8; let bit = 1 << (cellx + CELLS_X * celly); if (bitmap & bit) != 0 { changed_pixels.push(frame[x][y]); } } } let mut data = vec![(bitmap >> 16) as u8, (bitmap >> 8) as u8, bitmap as u8]; data.extend_from_slice(&rle_255_encode(&changed_pixels)); EncodedFrame { encoding: Encoding::CellDiff8V, data, } } // meant for 42x32 mode pub fn bg_strips_horizontal_16(_prev_frame: &Frame, frame: &Frame) -> EncodedFrame { let bg = most_common_pixel(frame); fn pack_strip(x: usize, y: usize, width: usize) -> [u8; 2] { // Y is 0..31 so will only need 5 bits // x is 0..42 so needs 6 bits // 5 bits remain for width // y: 1111100000000000 let mut y_x_w: u16 = (y as u16) << 11; // x: 0000011111100000 y_x_w |= (x as u16) << 5; // w: 0000000000011111 y_x_w |= width as u16; [(y_x_w >> 8) as u8, (y_x_w as u8)] } let mut strips = Vec::new(); 'outer: for y in 0..HEIGHT { let mut strip_start = 0; let mut in_strip = false; for x in 0..WIDTH { let pixel = frame[x][y]; if !in_strip && pixel != bg { in_strip = true; strip_start = x; } if in_strip { if pixel == bg { strips.push((strip_start, y, x - strip_start)); in_strip = false; } else if x - strip_start == 31 { strips.push((strip_start, y, x - strip_start)); strip_start = x; } if strips.len() == 127 { break 'outer; } } } if in_strip { strips.push((strip_start, y, WIDTH - strip_start)); } } let mut frame_bytes = Vec::with_capacity(1 + strips.len() * 2); frame_bytes.push(bg << 7 | (strips.len() as u8)); for (x, y, width) in strips { frame_bytes.extend_from_slice(&pack_strip(x, y, width)); } EncodedFrame { encoding: Encoding::BGStripsH16, data: frame_bytes, } } // meant for 320x240 mode pub fn bg_strips_horizontal_24(_prev_frame: &Frame, frame: &Frame) -> EncodedFrame { let bg = most_common_pixel(frame); fn pack_strip(x: usize, y: usize, width: usize) -> [u8; 3] { // Y is 0..240 so will need 8 bits // x is 0..320 so needs 9 bits // 7 bits remain for width let x_width = ((x >> 1) & 0x80) as u8 | (width as u8); [y as u8, (x & 0xff) as u8, x_width] } let mut strips = Vec::new(); 'outer: for y in 0..HEIGHT { let mut strip_start = 0; let mut in_strip = false; for x in 0..WIDTH { let pixel = frame[x][y]; if !in_strip && pixel != bg { in_strip = true; strip_start = x; } if in_strip { if pixel == bg { strips.push((strip_start, y, x - strip_start)); in_strip = false; } else if x - strip_start == 127 { strips.push((strip_start, y, x - strip_start)); strip_start = x; } // if strips.len() == MAX_STRIPS { // break 'outer; // } } } if in_strip { strips.push((strip_start, y, WIDTH - strip_start)); } } let mut frame_bytes = Vec::with_capacity(2 + strips.len() * 2); frame_bytes.push(bg << 7 | ((strips.len() >> 8) as u8)); frame_bytes.push(strips.len() as u8); for (x, y, width) in strips { frame_bytes.extend_from_slice(&pack_strip(x, y, width)); } EncodedFrame { encoding: Encoding::BGStripsH24, data: frame_bytes, } } pub fn rle_diff_horizontal(prev_frame: &Frame, frame: &Frame) -> EncodedFrame { let mut pixels = Vec::new(); for y in 0..HEIGHT { for x in 0..WIDTH { pixels.push(frame[x][y] ^ prev_frame[x][y]); } } EncodedFrame { encoding: Encoding::RLEDiffHorizontal, data: rle_255_encode(&pixels), } } pub fn rle_diff_vertical(prev_frame: &Frame, frame: &Frame) -> EncodedFrame { let mut pixels = Vec::new(); for x in 0..WIDTH { for y in 0..HEIGHT { pixels.push(frame[x][y] ^ prev_frame[x][y]); } } EncodedFrame { encoding: Encoding::RLEDiffVertical, data: rle_255_encode(&pixels), } } pub fn rle_horizontal(_prev_frame: &Frame, frame: &Frame) -> EncodedFrame { let mut pixels = Vec::new(); for y in 0..HEIGHT { for x in 0..WIDTH { pixels.push(frame[x][y]); } } EncodedFrame { encoding: Encoding::RLEHorizontal, data: rle_255_encode(&pixels), } } /// requires WIDTH and HEIGHT to be multiples of 16 /// two-level tree with 4x4 branches per level pub fn tree_16(_prev_frame: &Frame, frame: &Frame) -> EncodedFrame { let mut top_node: u16 = 0; let mut second_nodes = Vec::new(); let mut included_pixels = Vec::new(); // todo allow using white as bg let fg = 1; for cx in 0..4 { for cy in 0..4 { let mut any_filled_here = false; 'a: for px in 0..(WIDTH / 4) { let x = cx * (WIDTH / 4) + px; for py in 0..(HEIGHT / 4) { let y = cy * (HEIGHT / 4) + py; if frame[x][y] == fg{ any_filled_here = true; break 'a; } } } if any_filled_here { top_node |= 1 << (cy * 4 + cx); let mut second_node: u16 = 0; for ccx in 0..4 { for ccy in 0..4 { let mut any_filled_here = false; let mut node_pixels = Vec::new(); for px in 0..(WIDTH / 16) { for py in 0..(HEIGHT / 16) { let x = cx * (WIDTH / 4) + ccx * (WIDTH / 16) + px; let y = cy * (HEIGHT / 4) + ccy * (HEIGHT / 16) + py; if frame[x][y] == fg { node_pixels.push(fg); any_filled_here = true; }else{ node_pixels.push(1-fg); } } } if any_filled_here { second_node |= 1 << (ccy * 4 + ccx); included_pixels.extend_from_slice(&node_pixels); } } } second_nodes.push(second_node); } } } let mut data = Vec::new(); data.push((top_node >>8) as u8); data.push(top_node as u8); for n in second_nodes{ data.push((n>>8)as u8); data.push(n as u8); } data.extend_from_slice(&rle_255_encode(&included_pixels)); EncodedFrame { encoding: Encoding::Tree16, data, } } pub fn rle_vertical(_prev_frame: &Frame, frame: &Frame) -> EncodedFrame { let mut pixels = Vec::new(); for x in 0..WIDTH { for y in 0..HEIGHT { pixels.push(frame[x][y]); } } EncodedFrame { encoding: Encoding::RLEVertical, data: rle_255_encode(&pixels), } } pub fn rle_vertical_ext(_prev_frame: &Frame, frame: &Frame) -> EncodedFrame { let mut data = Vec::new(); let mut last_pixel = 0; let mut run: u16 = 0; let push_run = |data: &mut Vec, run| { if run < 256 { data.push(run as u8); } else { // double zero to mark 16 bit run length // if data.last() != Some(&0) { // } data.push(0); data.push(0); data.push((run >> 8) as u8); data.push((run & 0xff) as u8); } }; for x in 0..WIDTH { for y in 0..HEIGHT { let pixel = frame[x][y]; if pixel != last_pixel || run == 0xffff { push_run(&mut data, run); if run == 0xffff && pixel == last_pixel { // inserting dummy run because we ran out of max len data.push(0); } run = 1; } else { run += 1; } last_pixel = pixel; } } push_run(&mut data, run); EncodedFrame { encoding: Encoding::RLEVerticalExt, data, } } pub fn rle_vertical_16(_prev_frame: &Frame, frame: &Frame) -> EncodedFrame { let mut data = Vec::new(); let mut last_pixel = 0; let mut run: u16 = 0; for x in 0..WIDTH { for y in 0..HEIGHT { let pixel = frame[x][y]; if pixel != last_pixel || run == 0xffff { data.push((run >> 8) as u8); data.push((run & 0xff) as u8); if run == 0xffff && pixel == last_pixel { // inserting dummy run because we ran out of max len data.push(0); data.push(0); } run = 1; } else { run += 1; } last_pixel = pixel; } } data.push((run >> 8) as u8); data.push((run & 0xff) as u8); EncodedFrame { encoding: Encoding::RLEVertical16, data, } } pub fn fill_white(_prev_frame: &Frame, _frame: &Frame, _loss: usize) -> EncodedFrame { EncodedFrame { encoding: Encoding::FillWhite, data: Vec::new(), } } pub fn fill_black(_prev_frame: &Frame, _frame: &Frame, _loss: usize) -> EncodedFrame { EncodedFrame { encoding: Encoding::FillBlack, data: Vec::new(), } }