View normal worlds
This commit is contained in:
parent
cfc08032e6
commit
2a4599756c
|
@ -40,7 +40,7 @@ impl BgMapWindow {
|
||||||
sim_id,
|
sim_id,
|
||||||
loader: Arc::new(loader),
|
loader: Arc::new(loader),
|
||||||
memory: memory.clone(),
|
memory: memory.clone(),
|
||||||
bgmaps: memory.watch(sim_id, 0x00020000, 0x1d800),
|
bgmaps: memory.watch(sim_id, 0x00020000, 0x20000),
|
||||||
cell_index: params.cell_index,
|
cell_index: params.cell_index,
|
||||||
generic_palette: params.generic_palette,
|
generic_palette: params.generic_palette,
|
||||||
params,
|
params,
|
||||||
|
@ -62,7 +62,7 @@ impl BgMapWindow {
|
||||||
});
|
});
|
||||||
row.col(|ui| {
|
row.col(|ui| {
|
||||||
let mut bgmap_index = self.cell_index / 4096;
|
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 {
|
if bgmap_index != self.cell_index / 4096 {
|
||||||
self.cell_index = (bgmap_index * 4096) + (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 {
|
pub fn new(sim_id: SimId, memory: &MemoryClient) -> Self {
|
||||||
Self {
|
Self {
|
||||||
chardata: memory.watch(sim_id, 0x00078000, 0x8000),
|
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),
|
brightness: memory.watch(sim_id, 0x0005f824, 8),
|
||||||
palettes: memory.watch(sim_id, 0x0005f860, 16),
|
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> {
|
pub struct CharacterGrid<'a> {
|
||||||
source: ImageSource<'a>,
|
source: ImageSource<'a>,
|
||||||
scale: f32,
|
scale: f32,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use std::{fmt::Display, sync::Arc};
|
use std::{fmt::Display, sync::Arc};
|
||||||
|
|
||||||
use egui::{
|
use egui::{
|
||||||
CentralPanel, Checkbox, Color32, ComboBox, Context, Image, ScrollArea, Slider, TextureOptions,
|
Align, CentralPanel, Checkbox, Color32, ComboBox, Context, Image, ScrollArea, Slider, TextEdit,
|
||||||
Ui, ViewportBuilder, ViewportId,
|
TextureOptions, Ui, ViewportBuilder, ViewportId,
|
||||||
};
|
};
|
||||||
use egui_extras::{Column, Size, StripBuilder, TableBuilder};
|
use egui_extras::{Column, Size, StripBuilder, TableBuilder};
|
||||||
use num_derive::{FromPrimitive, ToPrimitive};
|
use num_derive::{FromPrimitive, ToPrimitive};
|
||||||
|
@ -10,7 +10,7 @@ use num_traits::FromPrimitive;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
emulator::SimId,
|
emulator::SimId,
|
||||||
memory::{MemoryClient, MemoryView},
|
memory::{MemoryClient, MemoryRef, MemoryView},
|
||||||
vram::{VramImage, VramParams, VramProcessor, VramRenderer, VramTextureLoader},
|
vram::{VramImage, VramParams, VramProcessor, VramRenderer, VramTextureLoader},
|
||||||
window::{
|
window::{
|
||||||
utils::{NumberEdit, UiExt as _},
|
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 {
|
pub struct WorldWindow {
|
||||||
sim_id: SimId,
|
sim_id: SimId,
|
||||||
|
@ -67,6 +67,19 @@ impl WorldWindow {
|
||||||
ui.add(NumberEdit::new(&mut self.index).range(0..32));
|
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 data = {
|
||||||
let worlds = self.worlds.borrow();
|
let worlds = self.worlds.borrow();
|
||||||
|
@ -78,6 +91,118 @@ impl WorldWindow {
|
||||||
.column(Column::remainder())
|
.column(Column::remainder())
|
||||||
.column(Column::remainder())
|
.column(Column::remainder())
|
||||||
.body(|mut body| {
|
.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| {
|
body.row(row_height, |mut row| {
|
||||||
row.col(|ui| {
|
row.col(|ui| {
|
||||||
ui.label("Mode");
|
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| {
|
body.row(row_height, |mut row| {
|
||||||
row.col(|ui| {
|
row.col(|ui| {
|
||||||
ui.add(Checkbox::new(&mut world.header.lon, "Left"));
|
ui.add(Checkbox::new(&mut world.header.lon, "Left"));
|
||||||
|
@ -154,7 +301,7 @@ impl AppWindow for WorldWindow {
|
||||||
fn initial_viewport(&self) -> ViewportBuilder {
|
fn initial_viewport(&self) -> ViewportBuilder {
|
||||||
ViewportBuilder::default()
|
ViewportBuilder::default()
|
||||||
.with_title(format!("Worlds ({})", self.sim_id))
|
.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) {
|
fn on_init(&mut self, ctx: &Context, _render_state: &egui_wgpu::RenderState) {
|
||||||
|
@ -190,6 +337,7 @@ struct WorldParams {
|
||||||
|
|
||||||
struct WorldRenderer {
|
struct WorldRenderer {
|
||||||
chardata: MemoryView,
|
chardata: MemoryView,
|
||||||
|
bgmaps: MemoryView,
|
||||||
objects: MemoryView,
|
objects: MemoryView,
|
||||||
worlds: MemoryView,
|
worlds: MemoryView,
|
||||||
brightness: MemoryView,
|
brightness: MemoryView,
|
||||||
|
@ -204,6 +352,7 @@ impl WorldRenderer {
|
||||||
pub fn new(sim_id: SimId, memory: &MemoryClient) -> Self {
|
pub fn new(sim_id: SimId, memory: &MemoryClient) -> Self {
|
||||||
Self {
|
Self {
|
||||||
chardata: memory.watch(sim_id, 0x00078000, 0x8000),
|
chardata: memory.watch(sim_id, 0x00078000, 0x8000),
|
||||||
|
bgmaps: memory.watch(sim_id, 0x00020000, 0x20000),
|
||||||
objects: memory.watch(sim_id, 0x0003e000, 0x2000),
|
objects: memory.watch(sim_id, 0x0003e000, 0x2000),
|
||||||
worlds: memory.watch(sim_id, 0x0003d800, 0x400),
|
worlds: memory.watch(sim_id, 0x0003d800, 0x400),
|
||||||
brightness: memory.watch(sim_id, 0x0005f824, 8),
|
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 {
|
impl VramRenderer<1> for WorldRenderer {
|
||||||
|
@ -342,28 +571,77 @@ impl VramRenderer<1> for WorldRenderer {
|
||||||
}
|
}
|
||||||
drop(worlds);
|
drop(worlds);
|
||||||
self.render_object_world(group, params, image);
|
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 {
|
struct World {
|
||||||
header: WorldHeader,
|
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 {
|
impl World {
|
||||||
pub fn parse(data: &[u16; 16]) -> Self {
|
pub fn parse(data: &[u16; 16]) -> Self {
|
||||||
Self {
|
Self {
|
||||||
header: WorldHeader::parse(data[0]),
|
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 {
|
struct WorldHeader {
|
||||||
lon: bool,
|
lon: bool,
|
||||||
ron: bool,
|
ron: bool,
|
||||||
mode: WorldMode,
|
mode: WorldMode,
|
||||||
|
scx: u32,
|
||||||
|
scy: u32,
|
||||||
over: bool,
|
over: bool,
|
||||||
end: bool,
|
end: bool,
|
||||||
|
base: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WorldHeader {
|
impl WorldHeader {
|
||||||
|
@ -371,14 +649,20 @@ impl WorldHeader {
|
||||||
let lon = data & 0x8000 != 0;
|
let lon = data & 0x8000 != 0;
|
||||||
let ron = data & 0x4000 != 0;
|
let ron = data & 0x4000 != 0;
|
||||||
let mode = WorldMode::from_u16((data >> 12) & 0x3).unwrap();
|
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 over = data & 0x0080 != 0;
|
||||||
let end = data & 0x0040 != 0;
|
let end = data & 0x0040 != 0;
|
||||||
|
let base = (data & 0x000f) as usize;
|
||||||
Self {
|
Self {
|
||||||
lon,
|
lon,
|
||||||
ron,
|
ron,
|
||||||
mode,
|
mode,
|
||||||
|
scx,
|
||||||
|
scy,
|
||||||
over,
|
over,
|
||||||
end,
|
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