VIP inspection tooling #4
			
				
			
		
		
		
	| 
						 | 
				
			
			@ -40,7 +40,7 @@ impl BgMapWindow {
 | 
			
		|||
            sim_id,
 | 
			
		||||
            loader: Arc::new(loader),
 | 
			
		||||
            memory: memory.clone(),
 | 
			
		||||
            bgmaps: memory.watch(sim_id, 0x00020000, 0x1d800),
 | 
			
		||||
            bgmaps: memory.watch(sim_id, 0x00020000, 0x20000),
 | 
			
		||||
            cell_index: params.cell_index,
 | 
			
		||||
            generic_palette: params.generic_palette,
 | 
			
		||||
            params,
 | 
			
		||||
| 
						 | 
				
			
			@ -62,7 +62,7 @@ impl BgMapWindow {
 | 
			
		|||
                        });
 | 
			
		||||
                        row.col(|ui| {
 | 
			
		||||
                            let mut bgmap_index = self.cell_index / 4096;
 | 
			
		||||
                            ui.add(NumberEdit::new(&mut bgmap_index).range(0..14));
 | 
			
		||||
                            ui.add(NumberEdit::new(&mut bgmap_index).range(0..16));
 | 
			
		||||
                            if bgmap_index != self.cell_index / 4096 {
 | 
			
		||||
                                self.cell_index = (bgmap_index * 4096) + (self.cell_index % 4096);
 | 
			
		||||
                            }
 | 
			
		||||
| 
						 | 
				
			
			@ -227,7 +227,7 @@ impl BgMapRenderer {
 | 
			
		|||
    pub fn new(sim_id: SimId, memory: &MemoryClient) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            chardata: memory.watch(sim_id, 0x00078000, 0x8000),
 | 
			
		||||
            bgmaps: memory.watch(sim_id, 0x00020000, 0x1d800),
 | 
			
		||||
            bgmaps: memory.watch(sim_id, 0x00020000, 0x20000),
 | 
			
		||||
            brightness: memory.watch(sim_id, 0x0005f824, 8),
 | 
			
		||||
            palettes: memory.watch(sim_id, 0x0005f860, 16),
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -134,6 +134,12 @@ pub fn read_char_row(
 | 
			
		|||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn read_char_pixel(char: &[u16; 8], hflip: bool, vflip: bool, row: usize, col: usize) -> u8 {
 | 
			
		||||
    let pixels = if vflip { char[7 - row] } else { char[row] };
 | 
			
		||||
    let pixel = if hflip { 7 - col } else { col } << 1;
 | 
			
		||||
    ((pixels >> pixel) & 0x3) as u8
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct CharacterGrid<'a> {
 | 
			
		||||
    source: ImageSource<'a>,
 | 
			
		||||
    scale: f32,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
use std::{fmt::Display, sync::Arc};
 | 
			
		||||
 | 
			
		||||
use egui::{
 | 
			
		||||
    CentralPanel, Checkbox, Color32, ComboBox, Context, Image, ScrollArea, Slider, TextureOptions,
 | 
			
		||||
    Ui, ViewportBuilder, ViewportId,
 | 
			
		||||
    Align, CentralPanel, Checkbox, Color32, ComboBox, Context, Image, ScrollArea, Slider, TextEdit,
 | 
			
		||||
    TextureOptions, Ui, ViewportBuilder, ViewportId,
 | 
			
		||||
};
 | 
			
		||||
use egui_extras::{Column, Size, StripBuilder, TableBuilder};
 | 
			
		||||
use num_derive::{FromPrimitive, ToPrimitive};
 | 
			
		||||
| 
						 | 
				
			
			@ -10,7 +10,7 @@ use num_traits::FromPrimitive;
 | 
			
		|||
 | 
			
		||||
use crate::{
 | 
			
		||||
    emulator::SimId,
 | 
			
		||||
    memory::{MemoryClient, MemoryView},
 | 
			
		||||
    memory::{MemoryClient, MemoryRef, MemoryView},
 | 
			
		||||
    vram::{VramImage, VramParams, VramProcessor, VramRenderer, VramTextureLoader},
 | 
			
		||||
    window::{
 | 
			
		||||
        utils::{NumberEdit, UiExt as _},
 | 
			
		||||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ use crate::{
 | 
			
		|||
    },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use super::utils::{self, shade, Object};
 | 
			
		||||
use super::utils::{self, shade, CellData, Object};
 | 
			
		||||
 | 
			
		||||
pub struct WorldWindow {
 | 
			
		||||
    sim_id: SimId,
 | 
			
		||||
| 
						 | 
				
			
			@ -67,6 +67,19 @@ impl WorldWindow {
 | 
			
		|||
                            ui.add(NumberEdit::new(&mut self.index).range(0..32));
 | 
			
		||||
                        });
 | 
			
		||||
                    });
 | 
			
		||||
                    body.row(row_height, |mut row| {
 | 
			
		||||
                        row.col(|ui| {
 | 
			
		||||
                            ui.label("Address");
 | 
			
		||||
                        });
 | 
			
		||||
                        row.col(|ui| {
 | 
			
		||||
                            let address = 0x3d800 + self.index * 32;
 | 
			
		||||
                            let mut address_str = format!("{address:08x}");
 | 
			
		||||
                            ui.add_enabled(
 | 
			
		||||
                                false,
 | 
			
		||||
                                TextEdit::singleline(&mut address_str).horizontal_align(Align::Max),
 | 
			
		||||
                            );
 | 
			
		||||
                        });
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
            let data = {
 | 
			
		||||
                let worlds = self.worlds.borrow();
 | 
			
		||||
| 
						 | 
				
			
			@ -78,6 +91,118 @@ impl WorldWindow {
 | 
			
		|||
                    .column(Column::remainder())
 | 
			
		||||
                    .column(Column::remainder())
 | 
			
		||||
                    .body(|mut body| {
 | 
			
		||||
                        body.row(row_height, |mut row| {
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.label("Map base");
 | 
			
		||||
                            });
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.add(NumberEdit::new(&mut world.header.base).range(0..16));
 | 
			
		||||
                            });
 | 
			
		||||
                        });
 | 
			
		||||
                        body.row(row_height, |mut row| {
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.label("BG width");
 | 
			
		||||
                            });
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                let widths = ["1", "2", "4", "8"];
 | 
			
		||||
                                ComboBox::from_id_salt("width")
 | 
			
		||||
                                    .selected_text(widths[world.header.scx as usize])
 | 
			
		||||
                                    .width(ui.available_width())
 | 
			
		||||
                                    .show_ui(ui, |ui| {
 | 
			
		||||
                                        for (value, label) in widths.into_iter().enumerate() {
 | 
			
		||||
                                            ui.selectable_value(
 | 
			
		||||
                                                &mut world.header.scx,
 | 
			
		||||
                                                value as u32,
 | 
			
		||||
                                                label,
 | 
			
		||||
                                            );
 | 
			
		||||
                                        }
 | 
			
		||||
                                    });
 | 
			
		||||
                            });
 | 
			
		||||
                        });
 | 
			
		||||
                        body.row(row_height, |mut row| {
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.label("BG height");
 | 
			
		||||
                            });
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                let heights = ["1", "2", "4", "8"];
 | 
			
		||||
                                ComboBox::from_id_salt("height")
 | 
			
		||||
                                    .selected_text(heights[world.header.scy as usize])
 | 
			
		||||
                                    .width(ui.available_width())
 | 
			
		||||
                                    .show_ui(ui, |ui| {
 | 
			
		||||
                                        for (value, label) in heights.into_iter().enumerate() {
 | 
			
		||||
                                            ui.selectable_value(
 | 
			
		||||
                                                &mut world.header.scy,
 | 
			
		||||
                                                value as u32,
 | 
			
		||||
                                                label,
 | 
			
		||||
                                            );
 | 
			
		||||
                                        }
 | 
			
		||||
                                    });
 | 
			
		||||
                            });
 | 
			
		||||
                        });
 | 
			
		||||
                        body.row(row_height, |mut row| {
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.label("Dest X");
 | 
			
		||||
                            });
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.add(NumberEdit::new(&mut world.dst_x).range(-512..512));
 | 
			
		||||
                            });
 | 
			
		||||
                        });
 | 
			
		||||
                        body.row(row_height, |mut row| {
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.label("Dest Y");
 | 
			
		||||
                            });
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.add(NumberEdit::new(&mut world.dst_y));
 | 
			
		||||
                            });
 | 
			
		||||
                        });
 | 
			
		||||
                        body.row(row_height, |mut row| {
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.label("Dest parallax");
 | 
			
		||||
                            });
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.add(NumberEdit::new(&mut world.dst_parallax).range(-512..512));
 | 
			
		||||
                            });
 | 
			
		||||
                        });
 | 
			
		||||
                        body.row(row_height, |mut row| {
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.label("Src X");
 | 
			
		||||
                            });
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.add(NumberEdit::new(&mut world.src_x).range(-4096..4096));
 | 
			
		||||
                            });
 | 
			
		||||
                        });
 | 
			
		||||
                        body.row(row_height, |mut row| {
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.label("Src Y");
 | 
			
		||||
                            });
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.add(NumberEdit::new(&mut world.src_y).range(-16384..16384));
 | 
			
		||||
                            });
 | 
			
		||||
                        });
 | 
			
		||||
                        body.row(row_height, |mut row| {
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.label("Src parallax");
 | 
			
		||||
                            });
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.add(NumberEdit::new(&mut world.src_parallax).range(-4096..4096));
 | 
			
		||||
                            });
 | 
			
		||||
                        });
 | 
			
		||||
                        body.row(row_height, |mut row| {
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.label("Width");
 | 
			
		||||
                            });
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.add(NumberEdit::new(&mut world.width).range(-4096..4096));
 | 
			
		||||
                            });
 | 
			
		||||
                        });
 | 
			
		||||
                        body.row(row_height, |mut row| {
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.label("Height");
 | 
			
		||||
                            });
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.add(NumberEdit::new(&mut world.height));
 | 
			
		||||
                            });
 | 
			
		||||
                        });
 | 
			
		||||
                        body.row(row_height, |mut row| {
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.label("Mode");
 | 
			
		||||
| 
						 | 
				
			
			@ -97,6 +222,28 @@ impl WorldWindow {
 | 
			
		|||
                                    });
 | 
			
		||||
                            });
 | 
			
		||||
                        });
 | 
			
		||||
                        body.row(row_height, |mut row| {
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.label("Params");
 | 
			
		||||
                            });
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                let address = 0x00020000 + world.param_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("Overplane");
 | 
			
		||||
                            });
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.add(NumberEdit::new(&mut world.overplane).range(0..65536));
 | 
			
		||||
                            });
 | 
			
		||||
                        });
 | 
			
		||||
                        body.row(row_height, |mut row| {
 | 
			
		||||
                            row.col(|ui| {
 | 
			
		||||
                                ui.add(Checkbox::new(&mut world.header.lon, "Left"));
 | 
			
		||||
| 
						 | 
				
			
			@ -154,7 +301,7 @@ impl AppWindow for WorldWindow {
 | 
			
		|||
    fn initial_viewport(&self) -> ViewportBuilder {
 | 
			
		||||
        ViewportBuilder::default()
 | 
			
		||||
            .with_title(format!("Worlds ({})", self.sim_id))
 | 
			
		||||
            .with_inner_size((640.0, 480.0))
 | 
			
		||||
            .with_inner_size((640.0, 500.0))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn on_init(&mut self, ctx: &Context, _render_state: &egui_wgpu::RenderState) {
 | 
			
		||||
| 
						 | 
				
			
			@ -190,6 +337,7 @@ struct WorldParams {
 | 
			
		|||
 | 
			
		||||
struct WorldRenderer {
 | 
			
		||||
    chardata: MemoryView,
 | 
			
		||||
    bgmaps: MemoryView,
 | 
			
		||||
    objects: MemoryView,
 | 
			
		||||
    worlds: MemoryView,
 | 
			
		||||
    brightness: MemoryView,
 | 
			
		||||
| 
						 | 
				
			
			@ -204,6 +352,7 @@ impl WorldRenderer {
 | 
			
		|||
    pub fn new(sim_id: SimId, memory: &MemoryClient) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            chardata: memory.watch(sim_id, 0x00078000, 0x8000),
 | 
			
		||||
            bgmaps: memory.watch(sim_id, 0x00020000, 0x20000),
 | 
			
		||||
            objects: memory.watch(sim_id, 0x0003e000, 0x2000),
 | 
			
		||||
            worlds: memory.watch(sim_id, 0x0003d800, 0x400),
 | 
			
		||||
            brightness: memory.watch(sim_id, 0x0005f824, 8),
 | 
			
		||||
| 
						 | 
				
			
			@ -313,6 +462,86 @@ impl WorldRenderer {
 | 
			
		|||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn render_world(&mut self, world: World, params: &WorldParams, image: &mut VramImage) {
 | 
			
		||||
        image.clear();
 | 
			
		||||
 | 
			
		||||
        let height = if world.header.mode == WorldMode::Affine {
 | 
			
		||||
            world.height.max(8)
 | 
			
		||||
        } else {
 | 
			
		||||
            world.height
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let dx1 = world.dst_x;
 | 
			
		||||
        let dx2 = dx1 + world.width;
 | 
			
		||||
        if dx1 - world.dst_parallax > 384 || dx2 + world.dst_parallax < 0 {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        let dy1 = world.dst_y;
 | 
			
		||||
        let dy2 = dy1 + height;
 | 
			
		||||
        if dy1 > 224 || dy2 < 0 {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let colors = if params.generic_palette {
 | 
			
		||||
            [
 | 
			
		||||
                utils::generic_palette(params.left_color),
 | 
			
		||||
                utils::generic_palette(params.right_color),
 | 
			
		||||
            ]
 | 
			
		||||
        } else {
 | 
			
		||||
            let brts = self.brightness.borrow().read::<[u8; 8]>(0);
 | 
			
		||||
            let shades = utils::parse_shades(&brts);
 | 
			
		||||
            [
 | 
			
		||||
                shades.map(|s| shade(s, params.left_color)),
 | 
			
		||||
                shades.map(|s| shade(s, params.right_color)),
 | 
			
		||||
            ]
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let mut chars = CharCache::new(self.chardata.borrow());
 | 
			
		||||
        let mut cells = CellCache::new(self.bgmaps.borrow());
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
 | 
			
		||||
                let cell_index = world.source_cell(sx, sy);
 | 
			
		||||
                let cell = cells.get(cell_index);
 | 
			
		||||
                let char = chars.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;
 | 
			
		||||
 | 
			
		||||
                let cell_index = world.source_cell(sx, sy);
 | 
			
		||||
                let cell = cells.get(cell_index);
 | 
			
		||||
                let char = chars.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[1][pixel as usize]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl VramRenderer<1> for WorldRenderer {
 | 
			
		||||
| 
						 | 
				
			
			@ -342,28 +571,77 @@ impl VramRenderer<1> for WorldRenderer {
 | 
			
		|||
            }
 | 
			
		||||
            drop(worlds);
 | 
			
		||||
            self.render_object_world(group, params, image);
 | 
			
		||||
        } else {
 | 
			
		||||
            let world = World::parse(&worlds.read(params.index));
 | 
			
		||||
            drop(worlds);
 | 
			
		||||
            self.render_world(world, params, image);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct World {
 | 
			
		||||
    header: WorldHeader,
 | 
			
		||||
    dst_x: i16,
 | 
			
		||||
    dst_parallax: i16,
 | 
			
		||||
    dst_y: i16,
 | 
			
		||||
    src_x: i16,
 | 
			
		||||
    src_parallax: i16,
 | 
			
		||||
    src_y: i16,
 | 
			
		||||
    width: i16,
 | 
			
		||||
    height: i16,
 | 
			
		||||
    param_base: usize,
 | 
			
		||||
    overplane: usize,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl World {
 | 
			
		||||
    pub fn parse(data: &[u16; 16]) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            header: WorldHeader::parse(data[0]),
 | 
			
		||||
            dst_x: (data[1] as i16) << 6 >> 6,
 | 
			
		||||
            dst_parallax: (data[2] as i16) << 6 >> 6,
 | 
			
		||||
            dst_y: data[3] as i16,
 | 
			
		||||
            src_x: (data[4] as i16) << 3 >> 3,
 | 
			
		||||
            src_parallax: (data[5] as i16) << 1 >> 1,
 | 
			
		||||
            src_y: (data[6] as i16) << 3 >> 3,
 | 
			
		||||
            width: 1 + ((data[7] as i16) << 3 >> 3),
 | 
			
		||||
            height: 1 + data[8] as i16,
 | 
			
		||||
            param_base: data[9] as usize,
 | 
			
		||||
            overplane: data[10] as usize,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn source_cell(&self, sx: i16, sy: i16) -> usize {
 | 
			
		||||
        if self.header.over {
 | 
			
		||||
            let bg_width = 1 << self.header.scx << 9;
 | 
			
		||||
            let bg_height = 1 << self.header.scy << 9;
 | 
			
		||||
            if !(0..bg_width).contains(&sx) || !(0..bg_height).contains(&sy) {
 | 
			
		||||
                return self.overplane;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let scx = 1 << self.header.scx.min(3 - self.header.scy);
 | 
			
		||||
        let scy = 1 << self.header.scy;
 | 
			
		||||
        let map_x = ((sx >> 9) & (scx - 1)) as usize;
 | 
			
		||||
        let map_y = ((sy >> 9) & (scy - 1)) as usize;
 | 
			
		||||
        let map_index = self.header.base + (map_y * scx as usize) + map_x;
 | 
			
		||||
 | 
			
		||||
        let cell_x = (sx >> 3) as usize & 0x3f;
 | 
			
		||||
        let cell_y = (sy >> 3) as usize & 0x3f;
 | 
			
		||||
        let cell_index = (cell_y * 64) + cell_x;
 | 
			
		||||
 | 
			
		||||
        (map_index << 12) + cell_index
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct WorldHeader {
 | 
			
		||||
    lon: bool,
 | 
			
		||||
    ron: bool,
 | 
			
		||||
    mode: WorldMode,
 | 
			
		||||
    scx: u32,
 | 
			
		||||
    scy: u32,
 | 
			
		||||
    over: bool,
 | 
			
		||||
    end: bool,
 | 
			
		||||
    base: usize,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl WorldHeader {
 | 
			
		||||
| 
						 | 
				
			
			@ -371,14 +649,20 @@ impl WorldHeader {
 | 
			
		|||
        let lon = data & 0x8000 != 0;
 | 
			
		||||
        let ron = data & 0x4000 != 0;
 | 
			
		||||
        let mode = WorldMode::from_u16((data >> 12) & 0x3).unwrap();
 | 
			
		||||
        let scx = (data >> 10) as u32 & 0x03;
 | 
			
		||||
        let scy = (data >> 10) as u32 & 0x03;
 | 
			
		||||
        let over = data & 0x0080 != 0;
 | 
			
		||||
        let end = data & 0x0040 != 0;
 | 
			
		||||
        let base = (data & 0x000f) as usize;
 | 
			
		||||
        Self {
 | 
			
		||||
            lon,
 | 
			
		||||
            ron,
 | 
			
		||||
            mode,
 | 
			
		||||
            scx,
 | 
			
		||||
            scy,
 | 
			
		||||
            over,
 | 
			
		||||
            end,
 | 
			
		||||
            base,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -407,3 +691,52 @@ impl Display for WorldMode {
 | 
			
		|||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct CellCache<'a> {
 | 
			
		||||
    bgmaps: MemoryRef<'a>,
 | 
			
		||||
    index: usize,
 | 
			
		||||
    cell: CellData,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> CellCache<'a> {
 | 
			
		||||
    fn new(bgmaps: MemoryRef<'a>) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            bgmaps,
 | 
			
		||||
            index: 0x10000,
 | 
			
		||||
            cell: CellData::parse(0),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get(&mut self, index: usize) -> &CellData {
 | 
			
		||||
        if self.index != index {
 | 
			
		||||
            let data = self.bgmaps.read(index);
 | 
			
		||||
            self.cell = CellData::parse(data);
 | 
			
		||||
            self.index = index;
 | 
			
		||||
        }
 | 
			
		||||
        &self.cell
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct CharCache<'a> {
 | 
			
		||||
    chardata: MemoryRef<'a>,
 | 
			
		||||
    index: usize,
 | 
			
		||||
    char: [u16; 8],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'a> CharCache<'a> {
 | 
			
		||||
    fn new(chardata: MemoryRef<'a>) -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
            chardata,
 | 
			
		||||
            index: 2048,
 | 
			
		||||
            char: [0; 8],
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get(&mut self, index: usize) -> &[u16; 8] {
 | 
			
		||||
        if self.index != index {
 | 
			
		||||
            self.char = self.chardata.read(index);
 | 
			
		||||
            self.index = index;
 | 
			
		||||
        }
 | 
			
		||||
        &self.char
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue