VIP inspection tooling #4

Merged
SonicSwordcane merged 34 commits from vram into main 2025-02-24 04:01:18 +00:00
1 changed files with 147 additions and 22 deletions
Showing only changes of commit 2c71c20f20 - Show all commits

View File

@ -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);
}
}
}