VIP inspection tooling #4
			
				
			
		
		
		
	| 
						 | 
				
			
			@ -98,8 +98,11 @@ macro_rules! primitive_memory_value_impl {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
primitive_memory_value_impl!(u8, 1);
 | 
			
		||||
primitive_memory_value_impl!(i8, 2);
 | 
			
		||||
primitive_memory_value_impl!(u16, 2);
 | 
			
		||||
primitive_memory_value_impl!(i16, 2);
 | 
			
		||||
primitive_memory_value_impl!(u32, 4);
 | 
			
		||||
primitive_memory_value_impl!(i32, 2);
 | 
			
		||||
 | 
			
		||||
impl<const N: usize, T: MemoryValue> MemoryValue for [T; N] {
 | 
			
		||||
    #[inline]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,10 +34,11 @@ pub trait UiExt {
 | 
			
		|||
 | 
			
		||||
impl UiExt for Ui {
 | 
			
		||||
    fn section(&mut self, title: impl Into<String>, add_contents: impl FnOnce(&mut Ui)) {
 | 
			
		||||
        let title: String = title.into();
 | 
			
		||||
        let mut frame = Frame::group(self.style());
 | 
			
		||||
        frame.outer_margin.top += 10.0;
 | 
			
		||||
        frame.inner_margin.top += 2.0;
 | 
			
		||||
        let res = frame.show(self, add_contents);
 | 
			
		||||
        let res = self.push_id(&title, |ui| frame.show(ui, add_contents));
 | 
			
		||||
        let text = RichText::new(title).background_color(self.style().visuals.panel_fill);
 | 
			
		||||
        let old_rect = res.response.rect;
 | 
			
		||||
        let mut text_rect = old_rect;
 | 
			
		||||
| 
						 | 
				
			
			@ -133,12 +134,14 @@ impl<'a, T: Number> NumberEdit<'a, T> {
 | 
			
		|||
 | 
			
		||||
impl<T: Number> Widget for NumberEdit<'_, T> {
 | 
			
		||||
    fn ui(self, ui: &mut Ui) -> Response {
 | 
			
		||||
        let id = ui.id();
 | 
			
		||||
 | 
			
		||||
        let (last_value, mut str, focus) = ui.memory(|m| {
 | 
			
		||||
            let (lv, s) = m
 | 
			
		||||
                .data
 | 
			
		||||
                .get_temp(ui.id())
 | 
			
		||||
                .get_temp(id)
 | 
			
		||||
                .unwrap_or((*self.value, self.value.to_string()));
 | 
			
		||||
            let focus = m.has_focus(ui.id());
 | 
			
		||||
            let focus = m.has_focus(id);
 | 
			
		||||
            (lv, s, focus)
 | 
			
		||||
        });
 | 
			
		||||
        let mut stale = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -174,7 +177,7 @@ impl<T: Number> Widget for NumberEdit<'_, T> {
 | 
			
		|||
        }
 | 
			
		||||
        let text = TextEdit::singleline(&mut str)
 | 
			
		||||
            .horizontal_align(Align::Max)
 | 
			
		||||
            .id(ui.id())
 | 
			
		||||
            .id(id)
 | 
			
		||||
            .margin(Margin {
 | 
			
		||||
                left: 4.0,
 | 
			
		||||
                right: 20.0,
 | 
			
		||||
| 
						 | 
				
			
			@ -242,7 +245,7 @@ impl<T: Number> Widget for NumberEdit<'_, T> {
 | 
			
		|||
            stale = true;
 | 
			
		||||
        }
 | 
			
		||||
        if stale {
 | 
			
		||||
            ui.memory_mut(|m| m.data.insert_temp(ui.id(), (*self.value, str)));
 | 
			
		||||
            ui.memory_mut(|m| m.data.insert_temp(id, (*self.value, str)));
 | 
			
		||||
        }
 | 
			
		||||
        res
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,9 @@ pub struct WorldWindow {
 | 
			
		|||
    sim_id: SimId,
 | 
			
		||||
    loader: Arc<VramTextureLoader>,
 | 
			
		||||
    worlds: MemoryView,
 | 
			
		||||
    bgmaps: MemoryView,
 | 
			
		||||
    index: usize,
 | 
			
		||||
    param_index: usize,
 | 
			
		||||
    generic_palette: bool,
 | 
			
		||||
    params: VramParams<WorldParams>,
 | 
			
		||||
    scale: f32,
 | 
			
		||||
| 
						 | 
				
			
			@ -45,7 +47,9 @@ impl WorldWindow {
 | 
			
		|||
            sim_id,
 | 
			
		||||
            loader: Arc::new(loader),
 | 
			
		||||
            worlds: memory.watch(sim_id, 0x3d800, 0x400),
 | 
			
		||||
            bgmaps: memory.watch(sim_id, 0x00020000, 0x20000),
 | 
			
		||||
            index: params.index,
 | 
			
		||||
            param_index: 0,
 | 
			
		||||
            generic_palette: params.generic_palette,
 | 
			
		||||
            params,
 | 
			
		||||
            scale: 1.0,
 | 
			
		||||
| 
						 | 
				
			
			@ -262,6 +266,57 @@ impl WorldWindow {
 | 
			
		|||
                        });
 | 
			
		||||
                    });
 | 
			
		||||
            });
 | 
			
		||||
            if world.header.mode == WorldMode::HBias {
 | 
			
		||||
                ui.section("H-bias", |ui| {
 | 
			
		||||
                    TableBuilder::new(ui)
 | 
			
		||||
                        .column(Column::remainder())
 | 
			
		||||
                        .column(Column::remainder())
 | 
			
		||||
                        .body(|mut body| {
 | 
			
		||||
                            body.row(row_height, |mut row| {
 | 
			
		||||
                                row.col(|ui| {
 | 
			
		||||
                                    ui.label("Index");
 | 
			
		||||
                                });
 | 
			
		||||
                                row.col(|ui| {
 | 
			
		||||
                                    ui.add(NumberEdit::new(&mut self.param_index).range(0..32));
 | 
			
		||||
                                });
 | 
			
		||||
                            });
 | 
			
		||||
                            let base = world.param_base + self.param_index * 2;
 | 
			
		||||
                            let mut param = HBiasParam::load(&self.bgmaps.borrow(), base);
 | 
			
		||||
                            body.row(row_height, |mut row| {
 | 
			
		||||
                                row.col(|ui| {
 | 
			
		||||
                                    ui.label("Address");
 | 
			
		||||
                                });
 | 
			
		||||
                                row.col(|ui| {
 | 
			
		||||
                                    let address = 0x00020000 + base * 2;
 | 
			
		||||
                                    let mut address_str = format!("{address:08x}");
 | 
			
		||||
                                    ui.add_enabled(
 | 
			
		||||
                                        false,
 | 
			
		||||
                                        TextEdit::singleline(&mut address_str)
 | 
			
		||||
                                            .horizontal_align(Align::Max),
 | 
			
		||||
                                    );
 | 
			
		||||
                                });
 | 
			
		||||
                            });
 | 
			
		||||
                            body.row(row_height, |mut row| {
 | 
			
		||||
                                row.col(|ui| {
 | 
			
		||||
                                    ui.label("Left");
 | 
			
		||||
                                });
 | 
			
		||||
                                row.col(|ui| {
 | 
			
		||||
                                    ui.add(NumberEdit::new(&mut param.left).range(-4096..4096));
 | 
			
		||||
                                });
 | 
			
		||||
                            });
 | 
			
		||||
                            body.row(row_height, |mut row| {
 | 
			
		||||
                                row.col(|ui| {
 | 
			
		||||
                                    ui.label("Right");
 | 
			
		||||
                                });
 | 
			
		||||
                                row.col(|ui| {
 | 
			
		||||
                                    ui.add(NumberEdit::new(&mut param.right).range(-4096..4096));
 | 
			
		||||
                                });
 | 
			
		||||
                            });
 | 
			
		||||
                        });
 | 
			
		||||
                });
 | 
			
		||||
            } else {
 | 
			
		||||
                self.param_index = 0;
 | 
			
		||||
            }
 | 
			
		||||
            ui.section("Display", |ui| {
 | 
			
		||||
                ui.horizontal(|ui| {
 | 
			
		||||
                    ui.label("Scale");
 | 
			
		||||
| 
						 | 
				
			
			@ -497,44 +552,39 @@ impl WorldRenderer {
 | 
			
		|||
            ]
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let mut chars = CharCache::new(self.chardata.borrow());
 | 
			
		||||
        let mut cells = CellCache::new(self.bgmaps.borrow());
 | 
			
		||||
        let chardata = self.chardata.borrow();
 | 
			
		||||
        let bgmaps = self.bgmaps.borrow();
 | 
			
		||||
        let mut chars = [CharCache::new(&chardata), CharCache::new(&chardata)];
 | 
			
		||||
        let mut cells = [CellCache::new(&bgmaps), CellCache::new(&bgmaps)];
 | 
			
		||||
        let mut source = SourceCoordCalculator::new(&bgmaps, &world);
 | 
			
		||||
 | 
			
		||||
        for y in 0..height {
 | 
			
		||||
            let dy = y + world.dst_y;
 | 
			
		||||
            if !(0..224).contains(&dy) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            let sy = y + world.src_y;
 | 
			
		||||
 | 
			
		||||
            // left side
 | 
			
		||||
            for x in 0..world.width {
 | 
			
		||||
                let dx = x + world.dst_x - world.dst_parallax;
 | 
			
		||||
                if !(0..384).contains(&dx) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                let sx = x + world.src_x - world.src_parallax;
 | 
			
		||||
                if world.header.lon && (0..384).contains(&dx) {
 | 
			
		||||
                    let (sx, sy) = source.left(x, y);
 | 
			
		||||
 | 
			
		||||
                    let cell_index = world.source_cell(sx, sy);
 | 
			
		||||
                let cell = cells.get(cell_index);
 | 
			
		||||
                let char = chars.get(cell.char_index);
 | 
			
		||||
                    let cell = cells[0].get(cell_index);
 | 
			
		||||
                    let char = chars[0].get(cell.char_index);
 | 
			
		||||
                    let row = (sy & 0x7) as usize;
 | 
			
		||||
                    let col = (sx & 0x7) as usize;
 | 
			
		||||
                    let pixel = utils::read_char_pixel(char, cell.hflip, cell.vflip, row, col);
 | 
			
		||||
                    image.add((dx as usize, dy as usize), colors[0][pixel as usize]);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            // right side
 | 
			
		||||
            for x in 0..world.width {
 | 
			
		||||
                let dx = x + world.dst_x + world.dst_parallax;
 | 
			
		||||
                if !(0..384).contains(&dx) {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                let sx = x + world.src_x + world.src_parallax;
 | 
			
		||||
                if world.header.ron && (0..384).contains(&dx) {
 | 
			
		||||
                    let (sx, sy) = source.right(x, y);
 | 
			
		||||
 | 
			
		||||
                    let cell_index = world.source_cell(sx, sy);
 | 
			
		||||
                let cell = cells.get(cell_index);
 | 
			
		||||
                let char = chars.get(cell.char_index);
 | 
			
		||||
                    let cell = cells[1].get(cell_index);
 | 
			
		||||
                    let char = chars[1].get(cell.char_index);
 | 
			
		||||
                    let row = (sy & 0x7) as usize;
 | 
			
		||||
                    let col = (sx & 0x7) as usize;
 | 
			
		||||
                    let pixel = utils::read_char_pixel(char, cell.hflip, cell.vflip, row, col);
 | 
			
		||||
| 
						 | 
				
			
			@ -543,6 +593,7 @@ impl WorldRenderer {
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl VramRenderer<1> for WorldRenderer {
 | 
			
		||||
    type Params = WorldParams;
 | 
			
		||||
| 
						 | 
				
			
			@ -556,7 +607,7 @@ impl VramRenderer<1> for WorldRenderer {
 | 
			
		|||
 | 
			
		||||
        let worlds = self.worlds.borrow();
 | 
			
		||||
        let header = WorldHeader::parse(worlds.read(params.index * 16));
 | 
			
		||||
        if header.end || (!header.lon && header.ron) {
 | 
			
		||||
        if header.end || (!header.lon && !header.ron) {
 | 
			
		||||
            image.clear();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -693,13 +744,13 @@ impl Display for WorldMode {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
struct CellCache<'a> {
 | 
			
		||||
    bgmaps: MemoryRef<'a>,
 | 
			
		||||
    bgmaps: &'a MemoryRef<'a>,
 | 
			
		||||
    index: usize,
 | 
			
		||||
    cell: CellData,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> CellCache<'a> {
 | 
			
		||||
    fn new(bgmaps: MemoryRef<'a>) -> Self {
 | 
			
		||||
    fn new(bgmaps: &'a MemoryRef<'a>) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            bgmaps,
 | 
			
		||||
            index: 0x10000,
 | 
			
		||||
| 
						 | 
				
			
			@ -718,13 +769,13 @@ impl<'a> CellCache<'a> {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
struct CharCache<'a> {
 | 
			
		||||
    chardata: MemoryRef<'a>,
 | 
			
		||||
    chardata: &'a MemoryRef<'a>,
 | 
			
		||||
    index: usize,
 | 
			
		||||
    char: [u16; 8],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> CharCache<'a> {
 | 
			
		||||
    fn new(chardata: MemoryRef<'a>) -> Self {
 | 
			
		||||
    fn new(chardata: &'a MemoryRef<'a>) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            chardata,
 | 
			
		||||
            index: 2048,
 | 
			
		||||
| 
						 | 
				
			
			@ -740,3 +791,82 @@ impl<'a> CharCache<'a> {
 | 
			
		|||
        &self.char
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct SourceCoordCalculator<'a> {
 | 
			
		||||
    params: &'a MemoryRef<'a>,
 | 
			
		||||
    world: &'a World,
 | 
			
		||||
    y: i16,
 | 
			
		||||
    param: SourceParam,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> SourceCoordCalculator<'a> {
 | 
			
		||||
    fn new(params: &'a MemoryRef<'a>, world: &'a World) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            params,
 | 
			
		||||
            world,
 | 
			
		||||
            y: -1,
 | 
			
		||||
            param: SourceParam::Normal,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn left(&mut self, x: i16, y: i16) -> (i16, i16) {
 | 
			
		||||
        self.update_param(y);
 | 
			
		||||
        match &self.param {
 | 
			
		||||
            SourceParam::HBias(HBiasParam { left, .. }) => {
 | 
			
		||||
                let sx = x + self.world.src_x - self.world.src_parallax + *left;
 | 
			
		||||
                let sy = y + self.world.src_y;
 | 
			
		||||
                (sx, sy)
 | 
			
		||||
            }
 | 
			
		||||
            SourceParam::Normal => {
 | 
			
		||||
                let sx = x + self.world.src_x - self.world.src_parallax;
 | 
			
		||||
                let sy = y + self.world.src_y;
 | 
			
		||||
                (sx, sy)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn right(&mut self, x: i16, y: i16) -> (i16, i16) {
 | 
			
		||||
        self.update_param(y);
 | 
			
		||||
        match &self.param {
 | 
			
		||||
            SourceParam::HBias(HBiasParam { right, .. }) => {
 | 
			
		||||
                let sx = x + self.world.src_x + self.world.src_parallax + *right;
 | 
			
		||||
                let sy = y + self.world.src_y;
 | 
			
		||||
                (sx, sy)
 | 
			
		||||
            }
 | 
			
		||||
            SourceParam::Normal => {
 | 
			
		||||
                let sx = x + self.world.src_x + self.world.src_parallax;
 | 
			
		||||
                let sy = y + self.world.src_y;
 | 
			
		||||
                (sx, sy)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn update_param(&mut self, y: i16) {
 | 
			
		||||
        if self.y == y {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if self.world.header.mode == WorldMode::HBias {
 | 
			
		||||
            let base = self.world.param_base + (2 * y as usize);
 | 
			
		||||
            self.param = SourceParam::HBias(HBiasParam::load(self.params, base));
 | 
			
		||||
        }
 | 
			
		||||
        self.y = y;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum SourceParam {
 | 
			
		||||
    Normal,
 | 
			
		||||
    HBias(HBiasParam),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct HBiasParam {
 | 
			
		||||
    left: i16,
 | 
			
		||||
    right: i16,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl HBiasParam {
 | 
			
		||||
    fn load(params: &MemoryRef, index: usize) -> Self {
 | 
			
		||||
        let left = params.read::<i16>(index) << 3 >> 3;
 | 
			
		||||
        let right = params.read::<i16>(index | 1) << 3 >> 3;
 | 
			
		||||
        Self { left, right }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue