use nihav_core::codecs::*;
+use nihav_core::io::byteio::*;
+
+struct MaskState<'a> {
+ is_intra: bool,
+ pos: usize,
+ row_pos: usize,
+ row_size: usize,
+ mask: u8,
+ src: &'a [u8],
+}
+
+impl<'a> MaskState<'a> {
+ fn new(is_intra: bool, src: &'a [u8], row_size: usize) -> Self {
+ Self { is_intra, src, pos: 0, row_pos: 0, row_size, mask: 0x01 }
+ }
+ fn get_next(&mut self) -> bool {
+ if self.is_intra {
+ true
+ } else {
+ let res = (self.src[self.pos] & self.mask) == 0;
+ self.mask <<= 1;
+ if self.mask == 0 {
+ self.pos += 1;
+ self.mask = 0x01;
+ }
+ res
+ }
+ }
+ fn reset_row(&mut self) {
+ self.pos = self.row_pos;
+ self.mask = 0x01;
+ }
+ fn next_row(&mut self) {
+ self.row_pos += self.row_size;
+ self.reset_row();
+ }
+}
+
+struct IndexState<'a> {
+ src: &'a [u8],
+ pos: usize,
+ vec_idx: usize,
+ vec_subidx: usize,
+}
+
+impl<'a> IndexState<'a> {
+ fn new(src: &'a [u8]) -> Self {
+ Self { src, pos: 0, vec_idx: 0, vec_subidx: 0 }
+ }
+ fn get_next(&mut self) -> DecoderResult<()> {
+ validate!(self.pos < self.src.len());
+ self.vec_idx = self.src[self.pos] as usize;
+ self.vec_subidx = 0;
+ self.pos += 1;
+ Ok(())
+ }
+ fn get_pred(&self, dtab: &[[u32; 4]; 256]) -> u32 { dtab[self.vec_idx][self.vec_subidx] }
+ fn get_diff16(&mut self, dtab: &[[u32; 4]; 256]) -> DecoderResult<u32> {
+ let pred1 = self.get_pred(dtab);
+ let mut pred = pred1 >> 1;
+ if (pred1 & 1) != 0 {
+ self.get_next()?;
+ if self.vec_idx == 0 {
+ self.get_next()?;
+ let pred2 = self.get_pred(dtab);
+ pred = pred.wrapping_add((pred2 >> 1).wrapping_mul(5));
+ if (pred2 & 1) != 0 {
+ self.get_next()?;
+ } else {
+ self.vec_subidx += 1;
+ }
+ }
+ } else {
+ self.vec_subidx += 1;
+ }
+ Ok(pred)
+ }
+ fn get_diff16_noesc(&mut self, dtab: &[[u32; 4]; 256]) -> DecoderResult<u32> {
+ let pred1 = self.get_pred(dtab);
+ let pred = pred1 >> 1;
+ if (pred1 & 1) != 0 {
+ self.get_next()?;
+ } else {
+ self.vec_subidx += 1;
+ }
+ Ok(pred)
+ }
+ fn get_diff24(&mut self, dtab: &[[u32; 4]; 256], esctab: &[[u32; 4]; 256]) -> DecoderResult<u32> {
+ let pred1 = self.get_pred(dtab);
+ let mut pred = pred1 >> 1;
+ if (pred1 & 1) != 0 {
+ self.get_next()?;
+ if self.vec_idx == 0 {
+ self.get_next()?;
+ let pred2 = self.get_pred(esctab);
+ pred = pred.wrapping_add(pred2 >> 1);
+ if (pred2 & 1) != 0 {
+ self.get_next()?;
+ } else {
+ self.vec_subidx += 1;
+ }
+ }
+ } else {
+ self.vec_subidx += 1;
+ }
+ Ok(pred)
+ }
+}
+
+struct DeltaTables {
+ ydt: [[u32; 4]; 256],
+ cdt: [[u32; 4]; 256],
+ fat_ydt: [[u32; 4]; 256],
+ fat_cdt: [[u32; 4]; 256],
+ adt: [[u32; 4]; 256],
+}
+
+impl Default for DeltaTables {
+ fn default() -> Self {
+ Self {
+ ydt: [[0; 4]; 256],
+ cdt: [[0; 4]; 256],
+ fat_ydt: [[0; 4]; 256],
+ fat_cdt: [[0; 4]; 256],
+ adt: [[0; 4]; 256],
+ }
+ }
+}
+
+struct FrameBuf {
+ last16: Option<NAVideoBuffer<u16>>,
+ last24: Option<NAVideoBuffer<u8>>,
+}
+
+impl FrameBuf {
+ fn set16(&mut self, buf: NAVideoBuffer<u16>) { self.last16 = Some(buf); }
+ fn set24(&mut self, buf: NAVideoBuffer<u8>) { self.last24 = Some(buf); }
+ fn get16(&mut self) -> Option<NAVideoBuffer<u16>> {
+ if let Some(ref mut frm) = self.last16 {
+ let newfrm = frm.copy_buffer();
+ *frm = newfrm.clone();
+ Some(newfrm)
+ } else {
+ None
+ }
+ }
+ fn get24(&mut self) -> Option<NAVideoBuffer<u8>> {
+ if let Some(ref mut frm) = self.last24 {
+ let newfrm = frm.copy_buffer();
+ *frm = newfrm.clone();
+ Some(newfrm)
+ } else {
+ None
+ }
+ }
+ fn reset(&mut self) {
+ self.last16 = None;
+ self.last24 = None;
+ }
+}
+
+impl Default for FrameBuf {
+ fn default() -> Self {
+ Self { last16: None, last24: None }
+ }
+}
+
+#[derive(Default)]
+struct TM1Decoder {
+ info: Rc<NACodecInfo>,
+ last_delta_set: usize,
+ last_table_idx: usize,
+ delta_tables: DeltaTables,
+ blk_w: usize,
+ blk_h: usize,
+ vert_pred: Vec<u32>,
+ lastframe: FrameBuf,
+}
+
+const RGB555_FORMAT: NAPixelFormaton = NAPixelFormaton { model: ColorModel::RGB(RGBSubmodel::RGB), components: 3,
+ comp_info: [
+ Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 10, comp_offs: 0, next_elem: 2 }),
+ Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 5, comp_offs: 0, next_elem: 2 }),
+ Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 0, comp_offs: 0, next_elem: 2 }),
+ None, None],
+ elem_size: 2, be: false, alpha: false, palette: false };
+const BGR0_FORMAT: NAPixelFormaton = NAPixelFormaton { model: ColorModel::RGB(RGBSubmodel::RGB), components: 3,
+ comp_info: [
+ Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 2, next_elem: 4 }),
+ Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 1, next_elem: 4 }),
+ Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 0, next_elem: 4 }),
+ None, None],
+ elem_size: 4, be: false, alpha: false, palette: false };
+
+impl TM1Decoder {
+ fn new() -> Self { Self::default() }
+ fn set_delta_tables(&mut self, delta_set: usize, table_idx: usize, is_24bit: bool) {
+ if (self.last_delta_set == delta_set) && (self.last_table_idx == table_idx) { return; }
+ let ydt = &DUCK_Y_DELTAS[delta_set];
+ let yfdt = DUCK_Y_FAT_DELTAS[delta_set];
+ let cdt = &DUCK_C_DELTAS[delta_set];
+ let cfdt = DUCK_C_FAT_DELTAS[delta_set];
+ let vec = DUCK_VECTABLES[table_idx - 1];
+
+ let mut vec_iter = vec.into_iter();
+ for i in 0..256 {
+ let len = (*vec_iter.next().unwrap() as usize) >> 1;
+ for j in 0..len {
+ let pair = vec_iter.next().unwrap();
+ let lo = (pair >> 4) as usize;
+ let hi = (pair & 0xF) as usize;
+ if !is_24bit {
+ let d_lo = ydt[lo] + (ydt[lo] << 5) + (ydt[lo] << 10);
+ let d_hi = ydt[hi] + (ydt[hi] << 5) + (ydt[hi] << 10);
+ self.delta_tables.ydt[i][j] = ((d_lo + (d_hi << 16)) << 1) as u32;
+ let d_c = cdt[hi] + (cdt[lo] << 10);
+ self.delta_tables.cdt[i][j] = ((d_c + (d_c << 16)) << 1) as u32;
+ let d_a = lo + hi * 5;
+ self.delta_tables.adt[i][j] = ((d_a << 16) << 1) as u32;
+ } else {
+ self.delta_tables.ydt[i][j] = ((ydt [lo] + (ydt [hi] << 8) + (ydt [hi] << 16)) << 1) as u32;
+ self.delta_tables.fat_ydt[i][j] = ((yfdt[lo] + (yfdt[hi] << 8) + (yfdt[hi] << 16)) << 1) as u32;
+ self.delta_tables.cdt[i][j] = ((cdt [hi] + (cdt [lo] << 16)) << 1) as u32;
+ self.delta_tables.fat_cdt[i][j] = ((cfdt[hi] + (cfdt[lo] << 16)) << 1) as u32;
+ }
+ }
+ self.delta_tables.ydt[i][len - 1] |= 1;
+ self.delta_tables.cdt[i][len - 1] |= 1;
+ self.delta_tables.adt[i][len - 1] |= 1;
+ self.delta_tables.fat_ydt[i][len - 1] |= 1;
+ self.delta_tables.fat_cdt[i][len - 1] |= 1;
+ }
+
+ self.last_delta_set = delta_set;
+ self.last_table_idx = table_idx;
+ }
+ fn decode_16bit(&mut self, dst: &mut [u16], stride: usize, width: usize, height: usize, mask: &mut MaskState<'_>, index: &mut IndexState<'_>) -> DecoderResult<()> {
+ let mut off = 0;
+ index.get_next()?;
+ for y in 0..height {
+ let mut hor_pred: u32 = 0;
+ for x in (0..width).step_by(4) {
+ if mask.get_next() {
+ match y & 3 {
+ 0 => {
+ let dc0 = index.get_diff16(&self.delta_tables.cdt)?;
+ let dy0 = index.get_diff16(&self.delta_tables.ydt)?;
+ hor_pred = hor_pred.wrapping_add(dc0);
+ hor_pred = hor_pred.wrapping_add(dy0);
+ let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 0]);
+ self.vert_pred[(x >> 1) + 0] = cur;
+ dst[off + x + 0] = cur as u16;
+ dst[off + x + 1] = (cur >> 16) as u16;
+ if self.blk_w == 2 {
+ let dc1 = index.get_diff16(&self.delta_tables.cdt)?;
+ hor_pred = hor_pred.wrapping_add(dc1);
+ }
+ let dy1 = index.get_diff16(&self.delta_tables.ydt)?;
+ hor_pred = hor_pred.wrapping_add(dy1);
+ let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 1]);
+ self.vert_pred[(x >> 1) + 1] = cur;
+ dst[off + x + 2] = cur as u16;
+ dst[off + x + 3] = (cur >> 16) as u16;
+ },
+ 1 | 3 => {
+ let dy0 = index.get_diff16(&self.delta_tables.ydt)?;
+ hor_pred = hor_pred.wrapping_add(dy0);
+ let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 0]);
+ self.vert_pred[(x >> 1) + 0] = cur;
+ dst[off + x + 0] = cur as u16;
+ dst[off + x + 1] = (cur >> 16) as u16;
+ let dy1 = index.get_diff16(&self.delta_tables.ydt)?;
+ hor_pred = hor_pred.wrapping_add(dy1);
+ let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 1]);
+ self.vert_pred[(x >> 1) + 1] = cur;
+ dst[off + x + 2] = cur as u16;
+ dst[off + x + 3] = (cur >> 16) as u16;
+ },
+ 2 => {
+ if self.blk_h == 2 {
+ let dc0 = index.get_diff16(&self.delta_tables.cdt)?;
+ let dy0 = index.get_diff16(&self.delta_tables.ydt)?;
+ hor_pred = hor_pred.wrapping_add(dc0);
+ hor_pred = hor_pred.wrapping_add(dy0);
+ let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 0]);
+ self.vert_pred[(x >> 1) + 0] = cur;
+ dst[off + x + 0] = cur as u16;
+ dst[off + x + 1] = (cur >> 16) as u16;
+ if self.blk_w == 2 {
+ let dc1 = index.get_diff16(&self.delta_tables.cdt)?;
+ hor_pred = hor_pred.wrapping_add(dc1);
+ }
+ let dy1 = index.get_diff16(&self.delta_tables.ydt)?;
+ hor_pred = hor_pred.wrapping_add(dy1);
+ let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 1]);
+ self.vert_pred[(x >> 1) + 1] = cur;
+ dst[off + x + 2] = cur as u16;
+ dst[off + x + 3] = (cur >> 16) as u16;
+ } else {
+ let dy0 = index.get_diff16(&self.delta_tables.ydt)?;
+ hor_pred = hor_pred.wrapping_add(dy0);
+ let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 0]);
+ self.vert_pred[(x >> 1) + 0] = cur;
+ dst[off + x + 0] = cur as u16;
+ dst[off + x + 1] = (cur >> 16) as u16;
+ let dy1 = index.get_diff16(&self.delta_tables.ydt)?;
+ hor_pred = hor_pred.wrapping_add(dy1);
+ let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 1]);
+ self.vert_pred[(x >> 1) + 1] = cur;
+ dst[off + x + 2] = cur as u16;
+ dst[off + x + 3] = (cur >> 16) as u16;
+ }
+ },
+ _ => unreachable!(),
+ };
+ } else {
+ let cur = (dst[off + x + 0] as u32) | ((dst[off + x + 1] as u32) << 16);
+ self.vert_pred[(x >> 1) + 0] = cur;
+ let cur = (dst[off + x + 2] as u32) | ((dst[off + x + 3] as u32) << 16);
+ hor_pred = cur.wrapping_sub(self.vert_pred[(x >> 1) + 1]);
+ self.vert_pred[(x >> 1) + 1] = cur;
+ }
+ }
+ if (y & 3) != 3 {
+ mask.reset_row();
+ } else {
+ mask.next_row();
+ }
+ off += stride;
+ }
+ Ok(())
+ }
+ fn decode_sprite(&mut self, dst: &mut [u16], stride: usize, width: usize, height: usize, mask: &mut MaskState<'_>, index: &mut IndexState<'_>) -> DecoderResult<()> {
+ let mut off = 0;
+ let _ = index.get_next();
+ for y in 0..height {
+ let mut hor_pred: u32 = 0;
+ for x in (0..width).step_by(4) {
+ let is_tm = !mask.get_next();
+ let is_sprite = !mask.get_next();
+ if is_tm {
+ if (y & 3) == 0 {
+ let dc0 = index.get_diff16(&self.delta_tables.cdt)?;
+ hor_pred = hor_pred.wrapping_add(dc0);
+ }
+ let dy0 = index.get_diff16(&self.delta_tables.ydt)?;
+ hor_pred = hor_pred.wrapping_add(dy0);
+ let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 0]);
+ self.vert_pred[(x >> 1) + 0] = cur;
+ dst[off + x + 0] = cur as u16;
+ dst[off + x + 1] = (cur >> 16) as u16;
+ let dy1 = index.get_diff16(&self.delta_tables.ydt)?;
+ hor_pred = hor_pred.wrapping_add(dy1);
+ let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 1]);
+ self.vert_pred[(x >> 1) + 1] = cur;
+ dst[off + x + 2] = cur as u16;
+ dst[off + x + 3] = (cur >> 16) as u16;
+ } else if is_sprite {
+ if (y & 3) == 0 {
+ let dc0 = index.get_diff16(&self.delta_tables.cdt)?;
+ hor_pred = hor_pred.wrapping_add(dc0);
+ }
+ let dy0 = index.get_diff16(&self.delta_tables.ydt)?;
+ hor_pred = hor_pred.wrapping_add(dy0);
+ let _da0 = index.get_diff16_noesc(&self.delta_tables.adt)?;
+ let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 0]);
+ self.vert_pred[(x >> 1) + 0] = cur;
+ dst[off + x + 0] = cur as u16;
+ dst[off + x + 1] = (cur >> 16) as u16;
+ let dy1 = index.get_diff16(&self.delta_tables.ydt)?;
+ hor_pred = hor_pred.wrapping_add(dy1);
+ let _da1 = index.get_diff16_noesc(&self.delta_tables.adt)?;
+ let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 1]);
+ self.vert_pred[(x >> 1) + 1] = cur;
+ dst[off + x + 2] = cur as u16;
+ dst[off + x + 3] = (cur >> 16) as u16;
+ } else {
+ hor_pred = 0;
+ dst[off + x + 0] = 0;
+ dst[off + x + 1] = 0;
+ dst[off + x + 2] = 0;
+ dst[off + x + 3] = 0;
+ self.vert_pred[(x >> 1) + 0] = 0;
+ self.vert_pred[(x >> 1) + 1] = 0;
+ }
+ }
+ if (y & 3) != 3 {
+ mask.reset_row();
+ } else {
+ mask.next_row();
+ }
+ off += stride;
+ }
+ Ok(())
+ }
+ fn decode_24bit(&mut self, dst: &mut [u8], stride: usize, width: usize, height: usize, mask: &mut MaskState<'_>, index: &mut IndexState<'_>) -> DecoderResult<()> {
+ let mut off = 0;
+ index.get_next()?;
+ for y in 0..height {
+ let mut hor_pred: u32 = 0;
+ for x in (0..width).step_by(2) {
+ if mask.get_next() {
+ match y & 3 {
+ 0 => {
+ let dc0 = index.get_diff24(&self.delta_tables.cdt, &self.delta_tables.fat_cdt)?;
+ let dy0 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?;
+ hor_pred = hor_pred.wrapping_add(dc0);
+ hor_pred = hor_pred.wrapping_add(dy0);
+ let cur = hor_pred.wrapping_add(self.vert_pred[x + 0]);
+ self.vert_pred[x + 0] = cur;
+ dst[off + x*4 + 0] = cur as u8;
+ dst[off + x*4 + 1] = (cur >> 8) as u8;
+ dst[off + x*4 + 2] = (cur >> 16) as u8;
+ dst[off + x*4 + 3] = 0;
+ if self.blk_w == 2 {
+ let dc1 = index.get_diff24(&self.delta_tables.cdt, &self.delta_tables.fat_cdt)?;
+ hor_pred = hor_pred.wrapping_add(dc1);
+ }
+ let dy1 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?;
+ hor_pred = hor_pred.wrapping_add(dy1);
+ let cur = hor_pred.wrapping_add(self.vert_pred[x + 1]);
+ self.vert_pred[x + 1] = cur;
+ dst[off + x*4 + 4] = cur as u8;
+ dst[off + x*4 + 5] = (cur >> 8) as u8;
+ dst[off + x*4 + 6] = (cur >> 16) as u8;
+ dst[off + x*4 + 7] = 0;
+ },
+ 1 | 3 => {
+ let dy0 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?;
+ hor_pred = hor_pred.wrapping_add(dy0);
+ let cur = hor_pred.wrapping_add(self.vert_pred[x + 0]);
+ self.vert_pred[x + 0] = cur;
+ dst[off + x*4 + 0] = cur as u8;
+ dst[off + x*4 + 1] = (cur >> 8) as u8;
+ dst[off + x*4 + 2] = (cur >> 16) as u8;
+ dst[off + x*4 + 3] = 0;
+ let dy1 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?;
+ hor_pred = hor_pred.wrapping_add(dy1);
+ let cur = hor_pred.wrapping_add(self.vert_pred[x + 1]);
+ self.vert_pred[x + 1] = cur;
+ dst[off + x*4 + 4] = cur as u8;
+ dst[off + x*4 + 5] = (cur >> 8) as u8;
+ dst[off + x*4 + 6] = (cur >> 16) as u8;
+ dst[off + x*4 + 7] = 0;
+ },
+ 2 => {
+ if self.blk_h == 2 {
+ let dc0 = index.get_diff24(&self.delta_tables.cdt, &self.delta_tables.fat_cdt)?;
+ let dy0 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?;
+ hor_pred = hor_pred.wrapping_add(dc0);
+ hor_pred = hor_pred.wrapping_add(dy0);
+ let cur = hor_pred.wrapping_add(self.vert_pred[x + 0]);
+ self.vert_pred[x + 0] = cur;
+ dst[off + x*4 + 0] = cur as u8;
+ dst[off + x*4 + 1] = (cur >> 8) as u8;
+ dst[off + x*4 + 2] = (cur >> 16) as u8;
+ dst[off + x*4 + 3] = 0;
+ if self.blk_w == 2 {
+ let dc1 = index.get_diff24(&self.delta_tables.cdt, &self.delta_tables.fat_cdt)?;
+ hor_pred = hor_pred.wrapping_add(dc1);
+ }
+ let dy1 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?;
+ hor_pred = hor_pred.wrapping_add(dy1);
+ let cur = hor_pred.wrapping_add(self.vert_pred[x + 1]);
+ self.vert_pred[x + 1] = cur;
+ dst[off + x*4 + 4] = cur as u8;
+ dst[off + x*4 + 5] = (cur >> 8) as u8;
+ dst[off + x*4 + 6] = (cur >> 16) as u8;
+ dst[off + x*4 + 7] = 0;
+ } else {
+ let dy0 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?;
+ hor_pred = hor_pred.wrapping_add(dy0);
+ let cur = hor_pred.wrapping_add(self.vert_pred[x + 0]);
+ self.vert_pred[x + 0] = cur;
+ dst[off + x*4 + 0] = cur as u8;
+ dst[off + x*4 + 1] = (cur >> 8) as u8;
+ dst[off + x*4 + 2] = (cur >> 16) as u8;
+ dst[off + x*4 + 3] = 0;
+ let dy1 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?;
+ hor_pred = hor_pred.wrapping_add(dy1);
+ let cur = hor_pred.wrapping_add(self.vert_pred[x + 1]);
+ self.vert_pred[x + 1] = cur;
+ dst[off + x*4 + 4] = cur as u8;
+ dst[off + x*4 + 5] = (cur >> 8) as u8;
+ dst[off + x*4 + 6] = (cur >> 16) as u8;
+ dst[off + x*4 + 7] = 0;
+ }
+ },
+ _ => unreachable!(),
+ };
+ } else {
+ let cur = (dst[off + x*4 + 0] as u32)
+ | ((dst[off + x*4 + 1] as u32) << 8)
+ | ((dst[off + x*4 + 2] as u32) << 16)
+ | ((dst[off + x*4 + 3] as u32) << 24);
+ self.vert_pred[x + 0] = cur;
+ let cur = (dst[off + x*4 + 4] as u32)
+ | ((dst[off + x*4 + 5] as u32) << 8)
+ | ((dst[off + x*4 + 6] as u32) << 16)
+ | ((dst[off + x*4 + 7] as u32) << 24);
+ hor_pred = cur.wrapping_sub(self.vert_pred[x + 1]);
+ self.vert_pred[x + 1] = cur;
+ }
+ }
+ if (y & 3) != 3 {
+ mask.reset_row();
+ } else {
+ mask.next_row();
+ }
+ off += stride;
+ }
+ Ok(())
+ }
+}
+
+impl NADecoder for TM1Decoder {
+ fn init(&mut self, info: Rc<NACodecInfo>) -> DecoderResult<()> {
+ if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
+ let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, YUV410_FORMAT));
+ self.info = Rc::new(NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()));
+ Ok(())
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ }
+ fn decode(&mut self, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+ let src = pkt.get_buffer();
+ validate!(src.len() > 10);
+ let hdr_size = (src[0].rotate_left(3) & 0x7F) as usize;
+ validate!(hdr_size >= 12 && hdr_size < src.len());
+ let mut hdr: [u8; 127] = [0; 127];
+ for i in 1..hdr_size {
+ hdr[i - 1] = src[i] ^ src[i + 1];
+ }
+ let mut mr = MemoryReader::new_read(&hdr[0..hdr_size-1]);
+ let mut br = ByteReader::new(&mut mr);
+
+ let tm1type = br.read_byte()? as usize;
+ let delta_set = br.read_byte()? as usize;
+ let table_idx = br.read_byte()? as usize;
+ let height = br.read_u16le()? as usize;
+ let width = br.read_u16le()? as usize;
+ let _frameno = br.read_u16le()? as usize;
+ let version = br.read_byte()?;
+ let meta_type = br.read_byte()?;
+ validate!(width > 0 && height > 0);
+ let is_intra;
+ let mut is_sprite = false;
+ let mut spr_xoff = 0;
+ let mut spr_yoff = 0;
+ let mut spr_width = 0;
+ let mut spr_height = 0;
+ if version >= 2 {
+ validate!(meta_type <= 3);
+ if meta_type >= 2 {
+ let frameinfo = br.read_byte()?;
+ let _control = br.read_byte()?;
+
+ is_intra = ((frameinfo & 0x10) != 0) || ((frameinfo & 0x08) == 0);
+ } else {
+ is_intra = true;
+ }
+ if meta_type == 3 {
+ spr_xoff = br.read_u16le()? as usize;
+ spr_yoff = br.read_u16le()? as usize;
+ spr_width = br.read_u16le()? as usize;
+ spr_height = br.read_u16le()? as usize;
+ is_sprite = true;
+ }
+ } else {
+ is_intra = true;
+ }
+ validate!(tm1type < TM1_COMPR_TYPES.len());
+ let cinfo = TM1_COMPR_TYPES[tm1type];
+ if cinfo.is_none() {
+//check for missing ref
+ let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::None);
+ frm.set_keyframe(false);
+ frm.set_frame_type(FrameType::Skip);
+ return Ok(Rc::new(RefCell::new(frm)));
+ }
+ let compr_info = cinfo.unwrap();
+ let is_24bit = !is_sprite && compr_info.is_24bit;
+
+ let vec_idx = if ((tm1type & 1) != 0) && (meta_type > 0) { 1 } else { table_idx };
+ validate!((delta_set < DUCK_Y_DELTAS.len()) && (vec_idx > 0) && (vec_idx <= DUCK_VECTABLES.len()));
+ self.set_delta_tables(delta_set, vec_idx, is_24bit);
+
+ let out_width = if is_24bit { width >> 1 } else { width };
+ let mask_row_size = if is_sprite {
+ ((spr_width >> 2) + 3) >> 2
+ } else if is_intra {
+ 0
+ } else {
+ ((width >> 2) + 7) >> 3
+ };
+ let mask_size = mask_row_size * (if is_sprite { spr_height >> 2 } else { height >> 2 });
+ let mask_bits = &src[hdr_size..][..mask_size];
+ let index_bytes = &src[hdr_size+mask_size..];
+ validate!(src.len() >= hdr_size + mask_size);
+ self.vert_pred.truncate(0);
+ self.vert_pred.resize(out_width, 0);
+
+ if is_intra || is_sprite {
+ let fmt = if is_24bit { BGR0_FORMAT } else { RGB555_FORMAT };
+ let myinfo = NAVideoInfo::new(out_width, height, false, fmt);
+ let bufret = alloc_video_buffer(myinfo, 2);
+ if let Err(_) = bufret { return Err(DecoderError::InvalidData); }
+ let mut bufinfo = bufret.unwrap();
+ self.lastframe.reset();
+ if !is_24bit {
+ self.lastframe.set16(bufinfo.get_vbuf16().unwrap());
+ } else {
+ self.lastframe.set24(bufinfo.get_vbuf().unwrap());
+ }
+ }
+
+ self.blk_w = compr_info.block_w;
+ self.blk_h = compr_info.block_h;
+ let mut mask = MaskState::new(is_intra && !is_sprite, &mask_bits, mask_row_size);
+ let mut index = IndexState::new(&index_bytes);
+ let bufinfo;
+ if !is_24bit {
+ if let Some(mut buf) = self.lastframe.get16() {
+ let stride = buf.get_stride(0);
+ {
+ let mut data = buf.get_data_mut();
+ if !is_sprite {
+ self.decode_16bit(data.as_mut_slice(), stride, out_width, height, &mut mask, &mut index)?;
+ } else {
+ validate!(spr_xoff + spr_width <= out_width);
+ validate!(spr_yoff + spr_height <= height);
+ for el in data.iter_mut() { *el = 0; }
+ let dst = &mut data[spr_xoff + spr_yoff * stride..];
+ self.decode_sprite(dst, stride, spr_width, spr_height, &mut mask, &mut index)?;
+ }
+ }
+ bufinfo = NABufferType::Video16(buf);
+ } else {
+ return Err(DecoderError::MissingReference);
+ }
+ } else {
+ if let Some(mut buf) = self.lastframe.get24() {
+ let stride = buf.get_stride(0);
+ {
+ let mut data = buf.get_data_mut();
+ self.decode_24bit(data.as_mut_slice(), stride, out_width, height, &mut mask, &mut index)?;
+ }
+ bufinfo = NABufferType::VideoPacked(buf);
+ } else {
+ return Err(DecoderError::MissingReference);
+ }
+ }
+
+ let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
+ frm.set_keyframe(is_intra || is_sprite);
+ frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P });
+ Ok(Rc::new(RefCell::new(frm)))
+ }
+}
pub fn get_decoder() -> Box<NADecoder> {
-unimplemented!();
+ Box::new(TM1Decoder::new())
}
+#[cfg(test)]
+mod test {
+ use nihav_core::codecs::RegisteredDecoders;
+ use nihav_core::demuxers::RegisteredDemuxers;
+ use nihav_core::test::dec_video::*;
+ use crate::codecs::duck_register_all_codecs;
+ use nihav_commonfmt::demuxers::generic_register_all_demuxers;
+ #[test]
+ fn test_tm1() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ generic_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ duck_register_all_codecs(&mut dec_reg);
+
+ //let file = "assets/Duck/AVI-DUCK-dk3.duk";
+ let file = "assets/Duck/phant2-940.duk";
+ //let file = "assets/Duck/bugsampler-m01-16bit.avi";
+ //let file = "assets/Duck/sonic3dblast_intro.avi";
+ //let file = "assets/Duck/BUTTONS.AVI";
+ //let file = "assets/Duck/SPRITES.AVI";
+ //let file = "assets/Duck/TRICORD.AVI";
+ test_file_decoding("avi", file, Some(42), true, false, None/*Some("tm1-")*/, &dmx_reg, &dec_reg);
+ }
+}
+
+#[derive(Clone,Copy)]
+struct TM1ComprInfo {
+ is_24bit: bool,
+ block_w: usize,
+ block_h: usize,
+}
+
+const TM1_COMPR_TYPES: [Option<TM1ComprInfo>; 17] = [
+ None,
+ Some(TM1ComprInfo { is_24bit: false, block_w: 4, block_h: 4 }),
+ Some(TM1ComprInfo { is_24bit: false, block_w: 4, block_h: 4 }),
+ Some(TM1ComprInfo { is_24bit: false, block_w: 4, block_h: 2 }),
+ Some(TM1ComprInfo { is_24bit: false, block_w: 4, block_h: 2 }),
+ Some(TM1ComprInfo { is_24bit: false, block_w: 2, block_h: 4 }),
+ Some(TM1ComprInfo { is_24bit: false, block_w: 2, block_h: 4 }),
+ Some(TM1ComprInfo { is_24bit: false, block_w: 2, block_h: 2 }),
+ Some(TM1ComprInfo { is_24bit: false, block_w: 2, block_h: 2 }),
+ None,
+ Some(TM1ComprInfo { is_24bit: true, block_w: 4, block_h: 4 }),
+ None,
+ Some(TM1ComprInfo { is_24bit: true, block_w: 4, block_h: 2 }),
+ None,
+ Some(TM1ComprInfo { is_24bit: true, block_w: 2, block_h: 4 }),
+ None,
+ Some(TM1ComprInfo { is_24bit: true, block_w: 2, block_h: 2 }),
+];
+
+const DUCK_Y_DELTAS: [[i32; 8]; 4] = [
+ [ 0, -1, 1, -3, 3, -6, 6, -6 ],
+ [ 0, -1, 2, -3, 4, -6, 6, -6 ],
+ [ 2, -3, 10, -10, 23, -23, 47, -47 ],
+ [ 0, -2, 2, -8, 8, -18, 18, -40 ]
+];
+const DUCK_Y_FAT_DELTA3: [i32; 8] = [ 0, -15, 50, -50, 115, -115, 235, -235 ];
+const DUCK_Y_FAT_DELTA4: [i32; 8] = [ 0, 40, 80, -76, 160, -154, 236, -236 ];
+const DUCK_Y_FAT_DELTAS: [&[i32]; 4] = [
+ &DUCK_Y_FAT_DELTA3, &DUCK_Y_FAT_DELTA3, &DUCK_Y_FAT_DELTA3, &DUCK_Y_FAT_DELTA4
+];
+
+const DUCK_C_DELTAS: [[i32; 8]; 4] = [
+ [ 0, -1, 1, -2, 3, -4, 5, -4 ],
+ [ 0, -1, 1, -2, 3, -4, 5, -4 ],
+ [ 0, -4, 3, -16, 20, -32, 36, -32 ],
+ [ 0, -2, 2, -8, 8, -18, 18, -40 ]
+];
+const DUCK_C_FAT_DELTA3: [i32; 8] = [ 0, -20, 15, -80, 100, -160, 180, -160 ];
+const DUCK_C_FAT_DELTAS: [&[i32]; 4] = [
+ &DUCK_C_FAT_DELTA3, &DUCK_C_FAT_DELTA3, &DUCK_C_FAT_DELTA3, &DUCK_Y_FAT_DELTA4
+];
+
+const DUCK_VECTBL2: &[u8] = &[
+0x8,0x00,0x00,0x00,0x00,
+0x8,0x00,0x00,0x00,0x00,
+0x8,0x10,0x00,0x00,0x00,
+0x8,0x01,0x00,0x00,0x00,
+0x8,0x00,0x10,0x00,0x00,
+0x8,0x00,0x01,0x00,0x00,
+0x8,0x00,0x00,0x10,0x00,
+0x8,0x00,0x00,0x01,0x00,
+0x8,0x00,0x00,0x00,0x10,
+0x8,0x00,0x00,0x00,0x01,
+0x6,0x00,0x00,0x00,
+0x6,0x10,0x00,0x00,
+0x6,0x01,0x00,0x00,
+0x6,0x00,0x10,0x00,
+0x6,0x00,0x01,0x00,
+0x6,0x00,0x00,0x01,
+0x6,0x00,0x00,0x10,
+0x6,0x00,0x00,0x02,
+0x6,0x00,0x00,0x20,
+0x6,0x20,0x10,0x00,
+0x6,0x00,0x02,0x01,
+0x6,0x00,0x20,0x10,
+0x6,0x02,0x01,0x00,
+0x6,0x11,0x00,0x00,
+0x6,0x00,0x20,0x00,
+0x6,0x00,0x02,0x00,
+0x6,0x20,0x00,0x00,
+0x6,0x01,0x10,0x00,
+0x6,0x02,0x00,0x00,
+0x6,0x01,0x00,0x02,
+0x6,0x10,0x00,0x20,
+0x6,0x00,0x01,0x02,
+0x6,0x10,0x01,0x00,
+0x6,0x00,0x10,0x20,
+0x6,0x10,0x10,0x00,
+0x6,0x10,0x00,0x01,
+0x6,0x20,0x00,0x10,
+0x6,0x02,0x00,0x01,
+0x6,0x01,0x01,0x00,
+0x6,0x01,0x00,0x10,
+0x6,0x00,0x11,0x00,
+0x6,0x10,0x00,0x02,
+0x6,0x00,0x01,0x10,
+0x6,0x00,0x00,0x11,
+0x6,0x10,0x00,0x10,
+0x6,0x01,0x00,0x01,
+0x6,0x00,0x00,0x22,
+0x6,0x02,0x01,0x01,
+0x6,0x10,0x20,0x10,
+0x6,0x01,0x02,0x01,
+0x6,0x20,0x10,0x10,
+0x6,0x01,0x00,0x20,
+0x6,0x00,0x10,0x01,
+0x6,0x21,0x10,0x00,
+0x6,0x10,0x02,0x01,
+0x6,0x12,0x01,0x00,
+0x6,0x01,0x20,0x10,
+0x6,0x01,0x02,0x00,
+0x6,0x10,0x20,0x00,
+0x6,0x00,0x10,0x02,
+0x6,0x00,0x01,0x20,
+0x6,0x00,0x02,0x21,
+0x6,0x00,0x02,0x20,
+0x6,0x00,0x00,0x12,
+0x6,0x00,0x00,0x21,
+0x6,0x20,0x11,0x00,
+0x6,0x00,0x01,0x01,
+0x6,0x11,0x10,0x00,
+0x6,0x00,0x20,0x12,
+0x6,0x00,0x20,0x11,
+0x6,0x20,0x10,0x02,
+0x6,0x02,0x01,0x20,
+0x6,0x00,0x22,0x11,
+0x6,0x00,0x10,0x10,
+0x6,0x02,0x11,0x00,
+0x6,0x00,0x21,0x10,
+0x6,0x00,0x02,0x03,
+0x6,0x20,0x10,0x01,
+0x6,0x00,0x12,0x01,
+0x4,0x11,0x00,
+0x4,0x00,0x22,
+0x4,0x20,0x00,
+0x4,0x01,0x10,
+0x4,0x02,0x20,
+0x4,0x00,0x20,
+0x4,0x02,0x00,
+0x4,0x10,0x01,
+0x4,0x00,0x11,
+0x4,0x02,0x01,
+0x4,0x02,0x21,
+0x4,0x00,0x02,
+0x4,0x20,0x02,
+0x4,0x01,0x01,
+0x4,0x10,0x10,
+0x4,0x10,0x02,
+0x4,0x22,0x00,
+0x4,0x10,0x00,
+0x4,0x01,0x00,
+0x4,0x21,0x00,
+0x4,0x12,0x00,
+0x4,0x00,0x10,
+0x4,0x20,0x12,
+0x4,0x01,0x11,
+0x4,0x00,0x01,
+0x4,0x01,0x02,
+0x4,0x11,0x02,
+0x4,0x11,0x01,
+0x4,0x10,0x20,
+0x4,0x20,0x01,
+0x4,0x22,0x11,
+0x4,0x00,0x12,
+0x4,0x20,0x10,
+0x4,0x22,0x01,
+0x4,0x01,0x20,
+0x4,0x00,0x21,
+0x4,0x10,0x11,
+0x4,0x21,0x10,
+0x4,0x10,0x22,
+0x4,0x02,0x03,
+0x4,0x12,0x01,
+0x4,0x20,0x11,
+0x4,0x11,0x10,
+0x4,0x20,0x30,
+0x4,0x11,0x20,
+0x4,0x02,0x10,
+0x4,0x22,0x10,
+0x4,0x11,0x11,
+0x4,0x30,0x20,
+0x4,0x30,0x00,
+0x4,0x01,0x22,
+0x4,0x01,0x12,
+0x4,0x02,0x11,
+0x4,0x03,0x02,
+0x4,0x03,0x00,
+0x4,0x10,0x21,
+0x4,0x12,0x20,
+0x4,0x00,0x00,
+0x4,0x12,0x21,
+0x4,0x21,0x11,
+0x4,0x02,0x22,
+0x4,0x10,0x12,
+0x4,0x31,0x00,
+0x4,0x20,0x20,
+0x4,0x00,0x03,
+0x4,0x02,0x02,
+0x4,0x22,0x20,
+0x4,0x01,0x21,
+0x4,0x21,0x02,
+0x4,0x21,0x12,
+0x4,0x11,0x22,
+0x4,0x00,0x30,
+0x4,0x12,0x11,
+0x4,0x20,0x22,
+0x4,0x31,0x20,
+0x4,0x21,0x30,
+0x4,0x22,0x02,
+0x4,0x22,0x22,
+0x4,0x20,0x31,
+0x4,0x13,0x02,
+0x4,0x03,0x10,
+0x4,0x11,0x12,
+0x4,0x00,0x13,
+0x4,0x21,0x01,
+0x4,0x12,0x03,
+0x4,0x13,0x00,
+0x4,0x13,0x10,
+0x4,0x02,0x13,
+0x4,0x30,0x01,
+0x4,0x12,0x10,
+0x4,0x22,0x13,
+0x4,0x03,0x12,
+0x4,0x31,0x01,
+0x4,0x30,0x22,
+0x4,0x00,0x31,
+0x4,0x01,0x31,
+0x4,0x02,0x23,
+0x4,0x01,0x30,
+0x4,0x11,0x21,
+0x4,0x22,0x21,
+0x4,0x01,0x13,
+0x4,0x10,0x03,
+0x4,0x22,0x03,
+0x4,0x30,0x21,
+0x4,0x21,0x31,
+0x4,0x33,0x00,
+0x4,0x13,0x12,
+0x4,0x11,0x31,
+0x4,0x30,0x02,
+0x4,0x12,0x02,
+0x4,0x11,0x13,
+0x4,0x12,0x22,
+0x4,0x20,0x32,
+0x4,0x10,0x13,
+0x4,0x22,0x31,
+0x4,0x21,0x20,
+0x4,0x01,0x33,
+0x4,0x33,0x10,
+0x4,0x20,0x13,
+0x4,0x31,0x22,
+0x4,0x13,0x30,
+0x4,0x01,0x03,
+0x4,0x11,0x33,
+0x4,0x20,0x21,
+0x4,0x13,0x31,
+0x4,0x03,0x22,
+0x4,0x31,0x02,
+0x4,0x00,0x24,
+0x2,0x00,
+0x2,0x10,
+0x2,0x20,
+0x2,0x30,
+0x2,0x40,
+0x2,0x50,
+0x2,0x60,
+0x2,0x01,
+0x2,0x11,
+0x2,0x21,
+0x2,0x31,
+0x2,0x41,
+0x2,0x51,
+0x2,0x61,
+0x2,0x02,
+0x2,0x12,
+0x2,0x22,
+0x2,0x32,
+0x2,0x42,
+0x2,0x52,
+0x2,0x62,
+0x2,0x03,
+0x2,0x13,
+0x2,0x23,
+0x2,0x33,
+0x2,0x43,
+0x2,0x53,
+0x2,0x63,
+0x2,0x04,
+0x2,0x14,
+0x2,0x24,
+0x2,0x34,
+0x2,0x44,
+0x2,0x54,
+0x2,0x64,
+0x2,0x05,
+0x2,0x15,
+0x2,0x25,
+0x2,0x35,
+0x2,0x45,
+0x2,0x55,
+0x2,0x65,
+0x2,0x06,
+0x2,0x16,
+0x2,0x26,
+0x2,0x36,
+0x2,0x46,
+0x2,0x56,
+0x2,0x66
+];
+
+const DUCK_VECTBL3: &[u8] = &[
+0x6,0x00,0x00,0x00,
+0x6,0x00,0x00,0x00,
+0x6,0x00,0x00,0x01,
+0x6,0x00,0x00,0x10,
+0x6,0x00,0x00,0x11,
+0x6,0x00,0x01,0x00,
+0x6,0x00,0x01,0x01,
+0x6,0x00,0x01,0x10,
+0x6,0x00,0x01,0x11,
+0x6,0x00,0x10,0x00,
+0x6,0x00,0x10,0x01,
+0x6,0x00,0x10,0x10,
+0x6,0x00,0x10,0x11,
+0x6,0x00,0x11,0x00,
+0x6,0x00,0x11,0x01,
+0x6,0x00,0x11,0x10,
+0x6,0x00,0x11,0x11,
+0x6,0x01,0x00,0x00,
+0x6,0x01,0x00,0x01,
+0x6,0x01,0x00,0x10,
+0x6,0x01,0x00,0x11,
+0x6,0x01,0x01,0x00,
+0x6,0x01,0x01,0x01,
+0x6,0x01,0x01,0x10,
+0x6,0x01,0x01,0x11,
+0x6,0x01,0x10,0x00,
+0x6,0x01,0x10,0x01,
+0x6,0x01,0x10,0x10,
+0x6,0x01,0x10,0x11,
+0x6,0x01,0x11,0x00,
+0x6,0x01,0x11,0x01,
+0x6,0x01,0x11,0x10,
+0x6,0x01,0x11,0x11,
+0x6,0x10,0x00,0x00,
+0x6,0x10,0x00,0x01,
+0x6,0x10,0x00,0x10,
+0x6,0x10,0x00,0x11,
+0x6,0x10,0x01,0x00,
+0x6,0x10,0x01,0x01,
+0x6,0x10,0x01,0x10,
+0x6,0x10,0x01,0x11,
+0x6,0x10,0x10,0x00,
+0x6,0x10,0x10,0x01,
+0x6,0x10,0x10,0x10,
+0x6,0x10,0x10,0x11,
+0x6,0x10,0x11,0x00,
+0x6,0x10,0x11,0x01,
+0x6,0x10,0x11,0x10,
+0x6,0x10,0x11,0x11,
+0x6,0x11,0x00,0x00,
+0x6,0x11,0x00,0x01,
+0x6,0x11,0x00,0x10,
+0x6,0x11,0x00,0x11,
+0x6,0x11,0x01,0x00,
+0x6,0x11,0x01,0x01,
+0x6,0x11,0x01,0x10,
+0x6,0x11,0x01,0x11,
+0x6,0x11,0x10,0x00,
+0x6,0x11,0x10,0x01,
+0x6,0x11,0x10,0x10,
+0x6,0x11,0x10,0x11,
+0x6,0x11,0x11,0x00,
+0x6,0x11,0x11,0x01,
+0x6,0x11,0x11,0x10,
+0x4,0x00,0x00,
+0x4,0x00,0x01,
+0x4,0x00,0x02,
+0x4,0x00,0x03,
+0x4,0x00,0x10,
+0x4,0x00,0x11,
+0x4,0x00,0x12,
+0x4,0x00,0x13,
+0x4,0x00,0x20,
+0x4,0x00,0x21,
+0x4,0x00,0x22,
+0x4,0x00,0x23,
+0x4,0x00,0x30,
+0x4,0x00,0x31,
+0x4,0x00,0x32,
+0x4,0x00,0x33,
+0x4,0x01,0x00,
+0x4,0x01,0x01,
+0x4,0x01,0x02,
+0x4,0x01,0x03,
+0x4,0x01,0x10,
+0x4,0x01,0x11,
+0x4,0x01,0x12,
+0x4,0x01,0x13,
+0x4,0x01,0x20,
+0x4,0x01,0x21,
+0x4,0x01,0x22,
+0x4,0x01,0x23,
+0x4,0x01,0x30,
+0x4,0x01,0x31,
+0x4,0x01,0x32,
+0x4,0x01,0x33,
+0x4,0x02,0x00,
+0x4,0x02,0x01,
+0x4,0x02,0x02,
+0x4,0x02,0x03,
+0x4,0x02,0x10,
+0x4,0x02,0x11,
+0x4,0x02,0x12,
+0x4,0x02,0x13,
+0x4,0x02,0x20,
+0x4,0x02,0x21,
+0x4,0x02,0x22,
+0x4,0x02,0x23,
+0x4,0x02,0x30,
+0x4,0x02,0x31,
+0x4,0x02,0x32,
+0x4,0x02,0x33,
+0x4,0x03,0x00,
+0x4,0x03,0x01,
+0x4,0x03,0x02,
+0x4,0x03,0x03,
+0x4,0x03,0x10,
+0x4,0x03,0x11,
+0x4,0x03,0x12,
+0x4,0x03,0x13,
+0x4,0x03,0x20,
+0x4,0x03,0x21,
+0x4,0x03,0x22,
+0x4,0x03,0x23,
+0x4,0x03,0x30,
+0x4,0x03,0x31,
+0x4,0x03,0x32,
+0x4,0x03,0x33,
+0x4,0x10,0x00,
+0x4,0x10,0x01,
+0x4,0x10,0x02,
+0x4,0x10,0x03,
+0x4,0x10,0x10,
+0x4,0x10,0x11,
+0x4,0x10,0x12,
+0x4,0x10,0x13,
+0x4,0x10,0x20,
+0x4,0x10,0x21,
+0x4,0x10,0x22,
+0x4,0x10,0x23,
+0x4,0x10,0x30,
+0x4,0x10,0x31,
+0x4,0x10,0x32,
+0x4,0x10,0x33,
+0x4,0x11,0x00,
+0x4,0x11,0x01,
+0x4,0x11,0x02,
+0x4,0x11,0x03,
+0x4,0x11,0x10,
+0x4,0x11,0x11,
+0x4,0x11,0x12,
+0x4,0x11,0x13,
+0x4,0x11,0x20,
+0x4,0x11,0x21,
+0x4,0x11,0x22,
+0x4,0x11,0x23,
+0x4,0x11,0x30,
+0x4,0x11,0x31,
+0x4,0x11,0x32,
+0x4,0x11,0x33,
+0x4,0x12,0x00,
+0x4,0x12,0x01,
+0x4,0x12,0x02,
+0x4,0x12,0x03,
+0x4,0x12,0x10,
+0x4,0x12,0x11,
+0x4,0x12,0x12,
+0x4,0x12,0x13,
+0x4,0x12,0x20,
+0x4,0x12,0x21,
+0x4,0x12,0x22,
+0x4,0x12,0x23,
+0x4,0x12,0x30,
+0x4,0x12,0x31,
+0x4,0x12,0x32,
+0x4,0x12,0x33,
+0x4,0x13,0x00,
+0x4,0x13,0x01,
+0x4,0x13,0x02,
+0x4,0x13,0x03,
+0x4,0x13,0x10,
+0x4,0x13,0x11,
+0x4,0x13,0x12,
+0x4,0x13,0x13,
+0x4,0x13,0x20,
+0x4,0x13,0x21,
+0x4,0x13,0x22,
+0x4,0x13,0x23,
+0x4,0x13,0x30,
+0x4,0x13,0x31,
+0x4,0x13,0x32,
+0x4,0x13,0x33,
+0x2,0x00,
+0x2,0x10,
+0x2,0x20,
+0x2,0x30,
+0x2,0x40,
+0x2,0x50,
+0x2,0x60,
+0x2,0x70,
+0x2,0x01,
+0x2,0x11,
+0x2,0x21,
+0x2,0x31,
+0x2,0x41,
+0x2,0x51,
+0x2,0x61,
+0x2,0x71,
+0x2,0x02,
+0x2,0x12,
+0x2,0x22,
+0x2,0x32,
+0x2,0x42,
+0x2,0x52,
+0x2,0x62,
+0x2,0x72,
+0x2,0x03,
+0x2,0x13,
+0x2,0x23,
+0x2,0x33,
+0x2,0x43,
+0x2,0x53,
+0x2,0x63,
+0x2,0x73,
+0x2,0x04,
+0x2,0x14,
+0x2,0x24,
+0x2,0x34,
+0x2,0x44,
+0x2,0x54,
+0x2,0x64,
+0x2,0x74,
+0x2,0x05,
+0x2,0x15,
+0x2,0x25,
+0x2,0x35,
+0x2,0x45,
+0x2,0x55,
+0x2,0x65,
+0x2,0x75,
+0x2,0x06,
+0x2,0x16,
+0x2,0x26,
+0x2,0x36,
+0x2,0x46,
+0x2,0x56,
+0x2,0x66,
+0x2,0x76,
+0x2,0x07,
+0x2,0x17,
+0x2,0x27,
+0x2,0x37,
+0x2,0x47,
+0x2,0x57,
+0x2,0x67,
+0x2,0x77
+];
+
+const DUCK_VECTBL4: &[u8] = &[
+0x8,0x00,0x00,0x00,0x00,
+0x8,0x00,0x00,0x00,0x00,
+0x8,0x20,0x00,0x00,0x00,
+0x8,0x00,0x00,0x00,0x01,
+0x8,0x10,0x00,0x00,0x00,
+0x8,0x00,0x00,0x00,0x02,
+0x8,0x01,0x00,0x00,0x00,
+0x8,0x00,0x00,0x00,0x10,
+0x8,0x02,0x00,0x00,0x00,
+0x6,0x00,0x00,0x00,
+0x6,0x20,0x00,0x00,
+0x6,0x00,0x00,0x01,
+0x6,0x10,0x00,0x00,
+0x6,0x00,0x00,0x02,
+0x6,0x00,0x10,0x00,
+0x6,0x00,0x20,0x00,
+0x6,0x00,0x02,0x00,
+0x6,0x00,0x01,0x00,
+0x6,0x01,0x00,0x00,
+0x6,0x00,0x00,0x20,
+0x6,0x02,0x00,0x00,
+0x6,0x00,0x00,0x10,
+0x6,0x10,0x00,0x20,
+0x6,0x01,0x00,0x02,
+0x6,0x20,0x00,0x10,
+0x6,0x02,0x00,0x01,
+0x6,0x20,0x10,0x00,
+0x6,0x00,0x12,0x00,
+0x6,0x00,0x02,0x01,
+0x6,0x02,0x01,0x00,
+0x6,0x00,0x21,0x00,
+0x6,0x00,0x01,0x02,
+0x6,0x00,0x20,0x10,
+0x6,0x00,0x00,0x21,
+0x6,0x00,0x00,0x12,
+0x6,0x00,0x01,0x20,
+0x6,0x12,0x00,0x00,
+0x6,0x00,0x10,0x20,
+0x6,0x01,0x20,0x00,
+0x6,0x02,0x10,0x00,
+0x6,0x10,0x20,0x00,
+0x6,0x01,0x02,0x00,
+0x6,0x21,0x00,0x00,
+0x6,0x00,0x02,0x10,
+0x6,0x20,0x01,0x00,
+0x6,0x00,0x22,0x00,
+0x6,0x10,0x02,0x00,
+0x6,0x00,0x10,0x02,
+0x6,0x11,0x00,0x00,
+0x6,0x00,0x11,0x00,
+0x6,0x22,0x00,0x00,
+0x6,0x20,0x00,0x02,
+0x6,0x10,0x00,0x01,
+0x6,0x00,0x20,0x01,
+0x6,0x02,0x20,0x00,
+0x6,0x01,0x10,0x00,
+0x6,0x01,0x00,0x20,
+0x6,0x00,0x20,0x02,
+0x6,0x01,0x20,0x02,
+0x6,0x10,0x01,0x00,
+0x6,0x02,0x00,0x10,
+0x6,0x00,0x10,0x01,
+0x6,0x10,0x01,0x20,
+0x6,0x20,0x02,0x10,
+0x6,0x00,0x00,0x22,
+0x6,0x10,0x00,0x02,
+0x6,0x00,0x02,0x20,
+0x6,0x20,0x02,0x00,
+0x6,0x00,0x00,0x11,
+0x6,0x02,0x10,0x01,
+0x6,0x00,0x01,0x10,
+0x6,0x00,0x02,0x11,
+0x4,0x01,0x02,
+0x4,0x02,0x01,
+0x4,0x01,0x00,
+0x4,0x10,0x20,
+0x4,0x20,0x10,
+0x4,0x20,0x00,
+0x4,0x11,0x00,
+0x4,0x02,0x00,
+0x4,0x12,0x00,
+0x4,0x00,0x21,
+0x4,0x22,0x00,
+0x4,0x00,0x12,
+0x4,0x21,0x00,
+0x4,0x02,0x11,
+0x4,0x00,0x01,
+0x4,0x10,0x02,
+0x4,0x02,0x20,
+0x4,0x20,0x11,
+0x4,0x01,0x10,
+0x4,0x21,0x10,
+0x4,0x10,0x00,
+0x4,0x10,0x22,
+0x4,0x20,0x20,
+0x4,0x00,0x22,
+0x4,0x01,0x22,
+0x4,0x20,0x01,
+0x4,0x02,0x02,
+0x4,0x00,0x20,
+0x4,0x00,0x10,
+0x4,0x00,0x11,
+0x4,0x22,0x01,
+0x4,0x11,0x20,
+0x4,0x12,0x01,
+0x4,0x12,0x20,
+0x4,0x11,0x02,
+0x4,0x10,0x10,
+0x4,0x01,0x01,
+0x4,0x02,0x21,
+0x4,0x20,0x12,
+0x4,0x01,0x12,
+0x4,0x22,0x11,
+0x4,0x21,0x12,
+0x4,0x22,0x10,
+0x4,0x21,0x02,
+0x4,0x20,0x02,
+0x4,0x10,0x01,
+0x4,0x00,0x02,
+0x4,0x10,0x21,
+0x4,0x01,0x20,
+0x4,0x11,0x22,
+0x4,0x12,0x21,
+0x4,0x22,0x20,
+0x4,0x02,0x10,
+0x4,0x02,0x22,
+0x4,0x11,0x10,
+0x4,0x22,0x02,
+0x4,0x20,0x21,
+0x4,0x01,0x11,
+0x4,0x11,0x01,
+0x4,0x10,0x12,
+0x4,0x02,0x12,
+0x4,0x20,0x22,
+0x4,0x21,0x20,
+0x4,0x01,0x21,
+0x4,0x12,0x02,
+0x4,0x21,0x11,
+0x4,0x12,0x22,
+0x4,0x12,0x10,
+0x4,0x22,0x21,
+0x4,0x10,0x11,
+0x4,0x21,0x01,
+0x4,0x11,0x12,
+0x4,0x12,0x11,
+0x4,0x66,0x66,
+0x4,0x22,0x22,
+0x4,0x11,0x21,
+0x4,0x11,0x11,
+0x4,0x21,0x22,
+0x4,0x00,0x00,
+0x4,0x22,0x12,
+0x4,0x12,0x12,
+0x4,0x21,0x21,
+0x4,0x42,0x00,
+0x4,0x00,0x04,
+0x4,0x40,0x00,
+0x4,0x30,0x00,
+0x4,0x31,0x00,
+0x4,0x00,0x03,
+0x4,0x00,0x14,
+0x4,0x00,0x13,
+0x4,0x01,0x24,
+0x4,0x20,0x13,
+0x4,0x01,0x42,
+0x4,0x14,0x20,
+0x4,0x42,0x02,
+0x4,0x13,0x00,
+0x4,0x00,0x24,
+0x4,0x31,0x20,
+0x4,0x22,0x13,
+0x4,0x11,0x24,
+0x4,0x12,0x66,
+0x4,0x30,0x01,
+0x4,0x02,0x13,
+0x4,0x12,0x42,
+0x4,0x40,0x10,
+0x4,0x40,0x02,
+0x4,0x01,0x04,
+0x4,0x24,0x00,
+0x4,0x42,0x10,
+0x4,0x21,0x13,
+0x4,0x13,0x12,
+0x4,0x31,0x21,
+0x4,0x21,0x24,
+0x4,0x00,0x40,
+0x4,0x10,0x24,
+0x4,0x10,0x42,
+0x4,0x32,0x01,
+0x4,0x11,0x42,
+0x4,0x20,0x31,
+0x4,0x12,0x40,
+0x2,0x00,
+0x2,0x10,
+0x2,0x20,
+0x2,0x30,
+0x2,0x40,
+0x2,0x50,
+0x2,0x60,
+0x2,0x70,
+0x2,0x01,
+0x2,0x11,
+0x2,0x21,
+0x2,0x31,
+0x2,0x41,
+0x2,0x51,
+0x2,0x61,
+0x2,0x71,
+0x2,0x02,
+0x2,0x12,
+0x2,0x22,
+0x2,0x32,
+0x2,0x42,
+0x2,0x52,
+0x2,0x62,
+0x2,0x72,
+0x2,0x03,
+0x2,0x13,
+0x2,0x23,
+0x2,0x33,
+0x2,0x43,
+0x2,0x53,
+0x2,0x63,
+0x2,0x73,
+0x2,0x04,
+0x2,0x14,
+0x2,0x24,
+0x2,0x34,
+0x2,0x44,
+0x2,0x54,
+0x2,0x64,
+0x2,0x74,
+0x2,0x05,
+0x2,0x15,
+0x2,0x25,
+0x2,0x35,
+0x2,0x45,
+0x2,0x55,
+0x2,0x65,
+0x2,0x75,
+0x2,0x06,
+0x2,0x16,
+0x2,0x26,
+0x2,0x36,
+0x2,0x46,
+0x2,0x56,
+0x2,0x66,
+0x2,0x76,
+0x2,0x07,
+0x2,0x17,
+0x2,0x27,
+0x2,0x37,
+0x2,0x47,
+0x2,0x57,
+0x2,0x67,
+0x2,0x77
+];
+
+const DUCK_VECTABLES: [&[u8]; 3] = [ DUCK_VECTBL2, DUCK_VECTBL3, DUCK_VECTBL4 ];