use crate::geometry::*; use crate::lib8::interpolate::scale8; use std::cmp::max; use std::fmt::{Formatter, Debug}; use ansi_term::Color; use rgb::Rgb; pub trait CoordinateView: Debug { fn next(&mut self) -> Option<(VirtualCoordinates, PhysicalCoordinates)>; } pub trait PixelMapping> { fn select(&self, rect: &Rectangle) -> impl CoordinateView; } pub trait DisplayDump, CoordData: CoordLimits> { fn dump(&self, map: &T); } impl DisplayDump for [Rgb; PIXEL_NUM] { fn dump(&self, _map: &LinearPixelMapping) { for ref pixel in self { print!("{}", Color::RGB(pixel.r, pixel.g, pixel.b).paint("█")); } println!(); } } impl DisplayDump for [Rgb; PIXEL_NUM] { fn dump(&self, map: &StrideMapping) { for y in 0..map.stride_count { let stride = &map.strides[y]; for x in 0..stride.length { let idx = if stride.reverse { stride.physical_idx + stride.length as usize - x as usize } else { stride.physical_idx + x as usize }; if idx >= self.len() { println!(); println!("frame!!!"); return; } let pixel = &self[idx]; print!("{}", Color::RGB(pixel.r, pixel.g, pixel.b).paint("█")); } println!(); } println!("frame!!!"); } } #[derive(Debug)] struct LinearCoordView { rect: Rectangle, idx: u8, } impl CoordinateView for LinearCoordView { fn next(&mut self) -> Option<(VirtualCoordinates, PhysicalCoordinates)> { if self.idx == self.rect.bottom_right.x { None } else { let virt = VirtualCoordinates::new(self.idx, 0); let phys = PhysicalCoordinates::new(self.idx as usize, 0); self.idx += 1; return Some((virt, phys)) } } } pub struct LinearPixelMapping { } impl LinearPixelMapping { pub fn new() -> Self { Self {} } } impl PixelMapping for LinearPixelMapping { fn select(&self, rect: &Rectangle) -> impl CoordinateView { LinearCoordView { rect: rect.clone(), idx: 0, } } } #[derive(Default, Clone, Copy, Debug, PartialEq, Eq)] pub struct Stride { pub length: u8, pub x: u8, pub y: u8, pub reverse: bool, pub physical_idx: usize } #[derive(Debug)] pub struct StrideMapping { pub strides: [Stride; STRIDE_NUM], pub stride_count: usize, pixel_count: usize, top: u8, left: u8, height: u8, width: u8 } impl StrideMapping { pub fn new() -> Self { /*let stride_json = vec!( (0, 0, 17), (1, 0, 17), (2, 0, 17), (3, 0, 17), (4, 0, 16), (5, 0, 17), (6, 0, 17), (7, 0, 17), (8, 0, 17), (9, 0, 17), (10, 0, 17), (11, 0, 17), (12, 0, 18), (13, 0, 17), (14, 0, 18), (15, 0, 17), (16, 0, 17), (17, 0, 17) );*/ let stride_json = vec!( (0, 0, 16, false), (1, 0, 16, true), (2, 0, 16, false), (3, 0, 16, true), (4, 0, 16, false), (5, 0, 16, true), (6, 0, 16, false), (7, 0, 16, true), (8, 0, 16, false), (9, 0, 16, true), (10, 0, 16, false), (11, 0, 16, true), (12, 0, 16, false), (13, 0, 16, true), (14, 0, 16, false), (15, 0, 16, true), ); let mut strides = [Stride::default(); STRIDE_NUM]; let stride_count = stride_json.len(); let mut physical_idx = 0; let mut height = 0; let mut width = 0; for stride_idx in 0..stride_count { let json_data = stride_json[stride_idx]; let x = json_data.0; let y = json_data.1; let length = json_data.2; let reverse = json_data.3; strides[stride_idx] = Stride { length, x, y, reverse, physical_idx }; physical_idx += length as usize; width = max(width, stride_idx + x as usize); height = max(height, length as usize + y as usize) } let top = 0; let left = 0; log::info!("strides={:?}", strides); Self { strides, stride_count, pixel_count: physical_idx, top, left, height: height as u8, width: width as u8 } } } impl PixelMapping for StrideMapping { fn select(&self, rect: &Rectangle) -> impl CoordinateView { let ret = StrideView::new(self, rect); //log::info!("select={:?}", ret); return ret; } } #[derive(Debug)] struct StrideSpace {} impl CoordinateSpace for StrideSpace {} type StrideCoords = Coordinates; struct StrideView<'a> { map: &'a StrideMapping, rect: Rectangle, span_start: u8, span_end: u8, offset_start: u8, offset_end: u8, virt_step_width: u8, virt_step_height: u8, cur_pixel: StrideCoords } impl<'a> Debug for StrideView<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.debug_struct("StrideView") .field("rect", &self.rect) .field("span", &(self.span_start, self.span_end)) .field("offset", &(self.offset_start, self.offset_end)) .field("step", &(self.virt_step_width, self.virt_step_height)) .field("cur", &self.cur_pixel).finish() } } impl<'a> StrideView<'a> { fn new(map: &'a StrideMapping, rect: &Rectangle) -> Self { let span_start = scale8(rect.top_left.x, map.width); let span_end = scale8(rect.bottom_right.x, map.width); let offset_start = scale8(rect.top_left.y, map.height); let offset_end = scale8(rect.bottom_right.y, map.height); let virt_step_width = u8::MAX / std::cmp::max(1, span_end - span_start); let virt_step_height = u8::MAX / std::cmp::max(1, offset_end - offset_start); return Self { map, rect: rect.clone(), span_start, span_end, offset_start, offset_end, virt_step_width, virt_step_height, cur_pixel: StrideCoords::new(span_start, offset_start) }; } } impl<'a> CoordinateView for StrideView<'a> { fn next(&mut self) -> Option<(VirtualCoordinates, PhysicalCoordinates)> { let mut search_idx = self.cur_pixel.x; let mut next_offset = self.cur_pixel.y + 1; //log::info!("view={:?}", self); while search_idx <= self.span_end { let cur = &self.map.strides[search_idx as usize]; if next_offset < self.offset_start || next_offset < cur.y { search_idx += 1; continue; } if next_offset > cur.y + cur.length || next_offset > self.offset_end { search_idx += 1; if search_idx <= self.span_end { next_offset = self.map.strides[search_idx as usize].y; continue } else { //log::info!("search end"); return None; } } self.cur_pixel = StrideCoords::new(search_idx, next_offset); let virt = VirtualCoordinates::new( (self.cur_pixel.x * self.virt_step_width).try_into().unwrap(), ((self.cur_pixel.y - cur.y) * self.virt_step_height).try_into().unwrap() ); let stride_pos = StrideCoords::new(self.cur_pixel.x.try_into().unwrap(), (self.cur_pixel.y - cur.y).try_into().unwrap()); let span = &self.map.strides[stride_pos.x as usize]; //log::info!("span={:?} stride={:?} cur={:?}", span, stride_pos, self.cur_pixel); let phys_idx = if span.reverse { span.physical_idx + (span.length - 1 - stride_pos.y) as usize } else { span.physical_idx + stride_pos.y as usize }; let phys = PhysicalCoordinates::new(phys_idx, 0); //log::info!("virt={:?} phys={:?}", virt, phys); return Some((virt, phys)); } //log::info!("end"); return None; } }