}
}
+#[derive(Clone,Copy,Default)]
+struct Rect {
+ sx: isize,
+ sy: isize,
+ dx: isize,
+ dy: isize,
+}
+
+impl Rect {
+ fn read(br: &mut dyn ByteIO) -> DecoderResult<Self> {
+ let sy = isize::from(br.read_u16be()? as i16);
+ let sx = isize::from(br.read_u16be()? as i16);
+ let dy = isize::from(br.read_u16be()? as i16);
+ let dx = isize::from(br.read_u16be()? as i16);
+ validate!(sy < dy && sx < dx);
+ Ok(Self { sx, sy, dx, dy })
+ }
+ fn paint(&self, dst: &mut [u8], stride: usize, width: usize, height: usize, clr: &[u8; 3]) {
+ let sx = self.sx.max(0) as usize;
+ let sy = self.sy.max(0) as usize;
+ let dx = self.dx.max(0) as usize;
+ let dy = self.dy.max(0) as usize;
+ for dline in dst.chunks_exact_mut(stride).take(dy.min(height)).skip(sy) {
+ for pix in dline.chunks_exact_mut(3).take(dx.min(width)).skip(sx) {
+ pix.copy_from_slice(clr);
+ }
+ }
+ }
+ fn paint_ellipse(&self, dst: &mut [u8], stride: usize, width: usize, height: usize, clr: &[u8; 3]) {
+ let (cx, cy) = ((self.sx + self.dx) as f32 * 0.5, (self.sy + self.dy) as f32 * 0.5);
+ let ell_x = 1.0 / ((self.dx as f32 - cx) * (self.dx as f32 - cx));
+ let ell_y = 1.0 / ((self.dy as f32 - cy) * (self.dy as f32 - cy));
+
+ let sx = self.sx.max(0) as usize;
+ let sy = self.sy.max(0) as usize;
+ let dx = self.dx.max(0) as usize;
+ let dy = self.dy.max(0) as usize;
+ for (y, dline) in dst.chunks_exact_mut(stride).enumerate().take(dy.min(height)).skip(sy) {
+ for (x, pix) in dline.chunks_exact_mut(3).enumerate().take(dx.min(width)).skip(sx) {
+ let dx = (x as f32 - cx).abs();
+ let dy = (y as f32 - cy).abs();
+ if dx * dx * ell_x + dy * dy * ell_y <= 1.0 {
+ pix.copy_from_slice(clr);
+ }
+ }
+ }
+ }
+}
+
+#[derive(Default)]
+struct Painter {
+ width: usize,
+ height: usize,
+ stride: usize,
+ pos_x: isize,
+ pos_y: isize,
+ fg_clr: [u8; 3],
+ bg_clr: [u8; 3],
+ fill_clr: [u8; 3],
+ last_rect: Option<Rect>,
+ last_oval: Option<Rect>,
+}
+
+impl Painter {
+ fn line_to(&mut self, dst: &mut [u8], mut dx: isize, mut dy: isize) {
+ let mut sx = self.pos_x;
+ let mut sy = self.pos_y;
+ if sx > dx {
+ std::mem::swap(&mut sx, &mut dx);
+ std::mem::swap(&mut sy, &mut dy);
+ }
+ let bound_x = 0..(self.width as isize);
+ let bound_y = 0..(self.height as isize);
+ let xdiff = dx - sx;
+ let mut ydiff = dy - sy;
+ let mut yinc = 1;
+ if ydiff < 0 {
+ ydiff = -ydiff;
+ yinc = -yinc;
+ }
+
+ if xdiff >= ydiff {
+ let mut delta = 2 * ydiff - xdiff;
+ let mut y = sy;
+ for x in sx..dy {
+ if bound_x.contains(&x) && bound_y.contains(&y) {
+ dst[(x as usize) * 3 + (y as usize) * self.stride..][..3].copy_from_slice(&self.fg_clr);
+ }
+ if delta > 0 {
+ y += yinc;
+ delta += 2 * (ydiff - xdiff);
+ } else {
+ delta += 2 * ydiff;
+ }
+ }
+ } else {
+ let mut delta = 2 * xdiff - ydiff;
+ let mut x = sx;
+ for y in sy..dy {
+ if bound_x.contains(&x) && bound_y.contains(&y) {
+ dst[(x as usize) * 3 + (y as usize) * self.stride..][..3].copy_from_slice(&self.fg_clr);
+ }
+ if delta > 0 {
+ x += 1;
+ delta += 2 * (xdiff - ydiff);
+ } else {
+ delta += 2 * xdiff;
+ }
+ }
+ }
+ }
+ fn paint_rect(&mut self, dst: &mut [u8], rect: Rect) {
+ rect.paint(dst, self.stride, self.width, self.height, &self.fg_clr);
+ self.last_rect = Some(rect);
+ }
+ fn paint_same_rect(&mut self, dst: &mut [u8]) {
+ if let Some(ref rect) = self.last_rect {
+ rect.paint(dst, self.stride, self.width, self.height, &self.fg_clr);
+ }
+ }
+ fn erase_rect(&mut self, dst: &mut [u8], rect: Rect) {
+ rect.paint(dst, self.stride, self.width, self.height, &self.bg_clr);
+ self.last_rect = Some(rect);
+ }
+ fn paint_oval(&mut self, dst: &mut [u8], oval: Rect) {
+ oval.paint_ellipse(dst, self.stride, self.width, self.height, &self.fg_clr);
+ self.last_oval = Some(oval);
+ }
+ fn paint_same_oval(&mut self, dst: &mut [u8]) {
+ if let Some(ref oval) = self.last_oval {
+ oval.paint_ellipse(dst, self.stride, self.width, self.height, &self.fg_clr);
+ }
+ }
+ fn erase_oval(&mut self, dst: &mut [u8], oval: Rect) {
+ oval.paint_ellipse(dst, self.stride, self.width, self.height, &self.fg_clr);
+ self.last_oval = Some(oval);
+ }
+}
+
#[derive(Default)]
struct QDrawDecoder {
info: NACodecInfoRef,
}
let mut frm = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap();
- let mut fg_clr = [0; 3];
- let mut bg_clr = [0; 3];
- let mut fill_clr = [0; 3];
+ let mut painter = Painter { width: self.width, height: self.height, stride: frm.stride[0], ..Default::default() };
+ let mut dst = &mut frm.data[frm.offset[0]..];
while br.left() >= 2 {
let op = br.read_u16be()?;
match op {
return Err(DecoderError::InvalidData);
},
0x001A => { // fore color
- fg_clr = br.read_colour()?;
+ painter.fg_clr = br.read_colour()?;
},
0x001B => { // back color
- bg_clr = br.read_colour()?;
+ painter.bg_clr = br.read_colour()?;
},
0x001E => {}, // def hilite
0x001F => { // fill color
- fill_clr = br.read_colour()?;
+ painter.fill_clr = br.read_colour()?;
},
0x0020 => { // line
- let sx = br.read_u16be()?;
- let sy = br.read_u16be()?;
- let dx = br.read_u16be()?;
- let dy = br.read_u16be()?;
+ painter.pos_y = isize::from(br.read_u16be()? as i16);
+ painter.pos_x = isize::from(br.read_u16be()? as i16);
+ let dy = isize::from(br.read_u16be()? as i16);
+ let dx = isize::from(br.read_u16be()? as i16);
+ painter.line_to(dst, dx, dy);
},
0x0021 => { // line from
- let dx = br.read_u16be()?;
- let dy = br.read_u16be()?;
+ let dy = isize::from(br.read_u16be()? as i16);
+ let dx = isize::from(br.read_u16be()? as i16);
+ painter.line_to(dst, dx, dy);
},
0x0022 => { // short line
- let xpos = br.read_u16be()?;
- let ypos = br.read_u16be()?;
- let dx = br.read_byte()? as i8;
- let dy = br.read_byte()? as i8;
+ painter.pos_y = isize::from(br.read_u16be()? as i16);
+ painter.pos_x = isize::from(br.read_u16be()? as i16);
+ let dy = isize::from(br.read_byte()? as i8);
+ let dx = isize::from(br.read_byte()? as i8);
+ painter.line_to(dst, dx, dy);
},
0x0023 => { // short line from
- let dx = br.read_byte()? as i8;
- let dy = br.read_byte()? as i8;
+ let dy = isize::from(br.read_byte()? as i8);
+ let dx = isize::from(br.read_byte()? as i8);
+ painter.line_to(dst, dx, dy);
},
0x0028 => { // long text
- let _xpos = br.read_u16be()?;
let _ypos = br.read_u16be()?;
+ let _xpos = br.read_u16be()?;
let count = usize::from(br.read_byte()?);
br.read_skip(count)?;
},
0x0031 => { // paint rect
- let sy = usize::from(br.read_u16be()?);
- let sx = usize::from(br.read_u16be()?);
- let dy = usize::from(br.read_u16be()?);
- let dx = usize::from(br.read_u16be()?);
- validate!(sy < dy && sx < dx);
- for dline in frm.data[frm.offset[0]..].chunks_exact_mut(frm.stride[0])
- .take(dy.min(self.height)).skip(sy) {
- for pix in dline.chunks_exact_mut(3).take(dx.min(self.width)).skip(sx) {
- pix.copy_from_slice(&fg_clr);
- }
- }
+ let rect = Rect::read(&mut br)?;
+ painter.paint_rect(dst, rect);
+ },
+ 0x0032 => { // erase rect
+ let rect = Rect::read(&mut br)?;
+ painter.erase_rect(dst, rect);
+ },
+ 0x0039 => { // paint same rect
+ painter.paint_same_rect(dst);
+ },
+ 0x0051 => { // paint oval
+ let oval = Rect::read(&mut br)?;
+ painter.paint_oval(dst, oval);
+ },
+ 0x0052 => { // erase oval
+ let oval = Rect::read(&mut br)?;
+ painter.erase_oval(dst, oval);
+ },
+ 0x0059 => { // paint same oval
+ painter.paint_same_oval(dst);
},
0x0098 => { // PackBits rect
decode_bits(&mut br, &mut frm, self.width, self.height, false, false)?;
+ dst = &mut frm.data[frm.offset[0]..];
},
0x0099 => { // PackBits region
decode_bits(&mut br, &mut frm, self.width, self.height, true, false)?;
+ dst = &mut frm.data[frm.offset[0]..];
},
0x009A => { // DirectBits rect
decode_bits(&mut br, &mut frm, self.width, self.height, false, true)?;
+ dst = &mut frm.data[frm.offset[0]..];
},
0x009B => { // DirectBits region
decode_bits(&mut br, &mut frm, self.width, self.height, true, true)?;
+ dst = &mut frm.data[frm.offset[0]..];
},
0x00A0 => { // short comment
br.read_u16be()?;