VIP inspection tooling #4
|
@ -10,7 +10,7 @@ use fixed::{
|
|||
FixedI32,
|
||||
};
|
||||
use num_derive::{FromPrimitive, ToPrimitive};
|
||||
use num_traits::FromPrimitive;
|
||||
use num_traits::{FromPrimitive, ToPrimitive};
|
||||
|
||||
use crate::{
|
||||
emulator::SimId,
|
||||
|
@ -27,6 +27,7 @@ use super::utils::{self, shade, CellData, Object};
|
|||
pub struct WorldWindow {
|
||||
sim_id: SimId,
|
||||
loader: Arc<VramTextureLoader>,
|
||||
memory: Arc<MemoryClient>,
|
||||
worlds: MemoryView,
|
||||
bgmaps: MemoryView,
|
||||
index: usize,
|
||||
|
@ -37,7 +38,7 @@ pub struct WorldWindow {
|
|||
}
|
||||
|
||||
impl WorldWindow {
|
||||
pub fn new(sim_id: SimId, memory: &MemoryClient, vram: &mut VramProcessor) -> Self {
|
||||
pub fn new(sim_id: SimId, memory: &Arc<MemoryClient>, vram: &mut VramProcessor) -> Self {
|
||||
let initial_params = WorldParams {
|
||||
index: 31,
|
||||
generic_palette: false,
|
||||
|
@ -50,7 +51,8 @@ impl WorldWindow {
|
|||
Self {
|
||||
sim_id,
|
||||
loader: Arc::new(loader),
|
||||
worlds: memory.watch(sim_id, 0x3d800, 0x400),
|
||||
memory: memory.clone(),
|
||||
worlds: memory.watch(sim_id, 0x0003d800, 0x400),
|
||||
bgmaps: memory.watch(sim_id, 0x00020000, 0x20000),
|
||||
index: params.index,
|
||||
param_index: 0,
|
||||
|
@ -80,7 +82,7 @@ impl WorldWindow {
|
|||
ui.label("Address");
|
||||
});
|
||||
row.col(|ui| {
|
||||
let address = 0x3d800 + self.index * 32;
|
||||
let address = 0x0003d800 + self.index * 32;
|
||||
let mut address_str = format!("{address:08x}");
|
||||
ui.add_enabled(
|
||||
false,
|
||||
|
@ -89,7 +91,7 @@ impl WorldWindow {
|
|||
});
|
||||
});
|
||||
});
|
||||
let data = {
|
||||
let mut data = {
|
||||
let worlds = self.worlds.borrow();
|
||||
worlds.read(self.index)
|
||||
};
|
||||
|
@ -270,6 +272,10 @@ impl WorldWindow {
|
|||
});
|
||||
});
|
||||
});
|
||||
if world.update(&mut data) {
|
||||
let address = 0x0003d800 + self.index * 32;
|
||||
self.memory.write(self.sim_id, address as u32, &data);
|
||||
}
|
||||
if world.header.mode == WorldMode::HBias {
|
||||
ui.section("H-bias", |ui| {
|
||||
TableBuilder::new(ui)
|
||||
|
@ -317,6 +323,7 @@ impl WorldWindow {
|
|||
ui.add(NumberEdit::new(&mut param.right).range(-4096..4096));
|
||||
});
|
||||
});
|
||||
param.save(&self.memory, self.sim_id, base);
|
||||
});
|
||||
});
|
||||
} else if world.header.mode == WorldMode::Affine {
|
||||
|
@ -390,6 +397,7 @@ impl WorldWindow {
|
|||
ui.add(NumberEdit::new(&mut param.dy).precision(9));
|
||||
});
|
||||
});
|
||||
param.save(&self.memory, self.sim_id, base);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
|
@ -599,6 +607,12 @@ impl WorldRenderer {
|
|||
fn render_world(&mut self, world: World, params: &WorldParams, image: &mut VramImage) {
|
||||
image.clear();
|
||||
|
||||
let width = if world.header.mode == WorldMode::Affine {
|
||||
world.width & 0x03ff
|
||||
} else {
|
||||
world.width
|
||||
};
|
||||
|
||||
let height = if world.header.mode == WorldMode::Affine {
|
||||
world.height.max(8)
|
||||
} else {
|
||||
|
@ -606,7 +620,7 @@ impl WorldRenderer {
|
|||
};
|
||||
|
||||
let dx1 = world.dst_x;
|
||||
let dx2 = dx1 + world.width;
|
||||
let dx2 = dx1 + width;
|
||||
if dx1 - world.dst_parallax > 384 || dx2 + world.dst_parallax < 0 {
|
||||
return;
|
||||
}
|
||||
|
@ -642,7 +656,7 @@ impl WorldRenderer {
|
|||
continue;
|
||||
}
|
||||
|
||||
for x in 0..world.width {
|
||||
for x in 0..width {
|
||||
let dx = x + world.dst_x - world.dst_parallax;
|
||||
if world.header.lon && (0..384).contains(&dx) {
|
||||
let (sx, sy) = source.left(x, y);
|
||||
|
@ -739,6 +753,52 @@ impl World {
|
|||
}
|
||||
}
|
||||
|
||||
fn update(&self, source: &mut [u16; 16]) -> bool {
|
||||
let mut changed = self.header.update(&mut source[0]);
|
||||
|
||||
let new_dst_x = (self.dst_x as u16 & 0x03ff) | (source[1] & 0xfc00);
|
||||
changed |= source[1] != new_dst_x;
|
||||
source[1] = new_dst_x;
|
||||
|
||||
let new_dst_parallax = (self.dst_parallax as u16 & 0x03ff) | (source[2] & 0xfc00);
|
||||
changed |= source[2] != new_dst_parallax;
|
||||
source[2] = new_dst_parallax;
|
||||
|
||||
let new_dst_y = self.dst_y as u16;
|
||||
changed |= source[3] != new_dst_y;
|
||||
source[3] = new_dst_y;
|
||||
|
||||
let new_src_x = (self.src_x as u16 & 0x1fff) | (source[4] & 0xe000);
|
||||
changed |= source[4] != new_src_x;
|
||||
source[4] = new_src_x;
|
||||
|
||||
let new_src_parallax = (self.src_parallax as u16 & 0x7fff) | (source[4] & 0x8000);
|
||||
changed |= source[5] != new_src_parallax;
|
||||
source[5] = new_src_parallax;
|
||||
|
||||
let new_src_y = (self.src_y as u16 & 0x1fff) | (source[6] & 0xe000);
|
||||
changed |= source[6] != new_src_y;
|
||||
source[6] = new_src_y;
|
||||
|
||||
let new_width = ((self.width - 1) as u16 & 0x1fff) | (source[7] & 0xe000);
|
||||
changed |= source[7] != new_width;
|
||||
source[7] = new_width;
|
||||
|
||||
let new_height = (self.height - 1) as u16;
|
||||
changed |= source[8] != new_height;
|
||||
source[8] = new_height;
|
||||
|
||||
let new_param_base = self.param_base as u16;
|
||||
changed |= source[9] != new_param_base;
|
||||
source[9] = new_param_base;
|
||||
|
||||
let new_overplane = self.overplane as u16;
|
||||
changed |= source[10] != new_overplane;
|
||||
source[10] = new_overplane;
|
||||
|
||||
changed
|
||||
}
|
||||
|
||||
fn source_cell(&self, sx: i16, sy: i16) -> usize {
|
||||
if self.header.over {
|
||||
let bg_width = 1 << self.header.scx << 9;
|
||||
|
@ -794,6 +854,21 @@ impl WorldHeader {
|
|||
base,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&self, source: &mut u16) -> bool {
|
||||
let new_value = (*source & 0x0030)
|
||||
| if self.lon { 0x8000 } else { 0x0000 }
|
||||
| if self.ron { 0x4000 } else { 0x0000 }
|
||||
| self.mode.to_u16().unwrap() << 12
|
||||
| ((self.scx as u16) << 10)
|
||||
| ((self.scy as u16) << 8)
|
||||
| if self.over { 0x0080 } else { 0x0000 }
|
||||
| if self.end { 0x0040 } else { 0x0000 }
|
||||
| (self.base as u16 & 0x000f);
|
||||
let changed = *source != new_value;
|
||||
*source = new_value;
|
||||
changed
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
|
||||
|
@ -954,13 +1029,29 @@ enum SourceParam {
|
|||
struct HBiasParam {
|
||||
left: i16,
|
||||
right: i16,
|
||||
data: [u16; 2],
|
||||
}
|
||||
|
||||
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 }
|
||||
let data = [params.read::<u16>(index), params.read::<u16>(index | 1)];
|
||||
let left = (data[0] as i16) << 3 >> 3;
|
||||
let right = (data[1] as i16) << 3 >> 3;
|
||||
Self { left, right, data }
|
||||
}
|
||||
|
||||
fn save(&self, memory: &MemoryClient, sim: SimId, index: usize) {
|
||||
let new_left = (self.left as u16 & 0x1fff) | (self.data[0] & 0xe000);
|
||||
if new_left != self.data[0] {
|
||||
let address = 0x00020000 + (index * 2);
|
||||
memory.write(sim, address as u32, &new_left);
|
||||
}
|
||||
|
||||
let new_right = (self.right as u16 & 0x1fff) | (self.data[1] & 0xe000);
|
||||
if new_right != self.data[1] {
|
||||
let address = 0x00020000 + ((index | 1) * 2);
|
||||
memory.write(sim, address as u32, &new_right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -970,23 +1061,24 @@ struct AffineParam {
|
|||
src_y: FixedI32<U3>,
|
||||
dx: FixedI32<U9>,
|
||||
dy: FixedI32<U9>,
|
||||
data: [u16; 5],
|
||||
}
|
||||
|
||||
impl AffineParam {
|
||||
fn load(params: &MemoryRef, index: usize) -> Self {
|
||||
let src_x = params.read::<i16>(index & 0x1ffff);
|
||||
let src_x = FixedI32::from_bits(src_x as i32);
|
||||
let data = [
|
||||
params.read(index & 0xffff),
|
||||
params.read((index + 1) & 0xffff),
|
||||
params.read((index + 2) & 0xffff),
|
||||
params.read((index + 3) & 0xffff),
|
||||
params.read((index + 4) & 0xffff),
|
||||
];
|
||||
|
||||
let src_parallax = params.read::<i16>((index + 1) & 0x1ffff);
|
||||
|
||||
let src_y = params.read::<i16>((index + 2) & 0x1ffff);
|
||||
let src_y = FixedI32::from_bits(src_y as i32);
|
||||
|
||||
let dx = params.read::<i16>((index + 3) & 0x1ffff);
|
||||
let dx = FixedI32::from_bits(dx as i32);
|
||||
|
||||
let dy = params.read::<i16>((index + 4) & 0x1ffff);
|
||||
let dy = FixedI32::from_bits(dy as i32);
|
||||
let src_x = FixedI32::from_bits(data[0] as i16 as i32);
|
||||
let src_parallax = data[1] as i16;
|
||||
let src_y = FixedI32::from_bits(data[2] as i16 as i32);
|
||||
let dx = FixedI32::from_bits(data[3] as i16 as i32);
|
||||
let dy = FixedI32::from_bits(data[4] as i16 as i32);
|
||||
|
||||
AffineParam {
|
||||
src_x,
|
||||
|
@ -994,6 +1086,39 @@ impl AffineParam {
|
|||
src_y,
|
||||
dx,
|
||||
dy,
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
fn save(&self, memory: &MemoryClient, sim: SimId, index: usize) {
|
||||
let new_src_x = self.src_x.to_bits() as u16;
|
||||
if new_src_x != self.data[0] {
|
||||
let address = 0x00020000 + 2 * (index & 0xffff);
|
||||
memory.write(sim, address as u32, &new_src_x);
|
||||
}
|
||||
|
||||
let new_src_parallax = self.src_parallax as u16;
|
||||
if new_src_parallax != self.data[1] {
|
||||
let address = 0x00020000 + 2 * ((index + 1) & 0xffff);
|
||||
memory.write(sim, address as u32, &new_src_parallax);
|
||||
}
|
||||
|
||||
let new_src_y = self.src_y.to_bits() as u16;
|
||||
if new_src_y != self.data[2] {
|
||||
let address = 0x00020000 + 2 * ((index + 2) & 0xffff);
|
||||
memory.write(sim, address as u32, &new_src_y);
|
||||
}
|
||||
|
||||
let new_dx = self.dx.to_bits() as u16;
|
||||
if new_dx != self.data[3] {
|
||||
let address = 0x00020000 + 2 * ((index + 3) & 0xffff);
|
||||
memory.write(sim, address as u32, &new_dx);
|
||||
}
|
||||
|
||||
let new_dy = self.dy.to_bits() as u16;
|
||||
if new_dy != self.data[4] {
|
||||
let address = 0x00020000 + 2 * ((index + 4) & 0xffff);
|
||||
memory.write(sim, address as u32, &new_dy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue