Finish object view

This commit is contained in:
Simon Gellis 2025-02-15 00:28:37 -05:00
parent b5e1711a56
commit 7356287030
3 changed files with 145 additions and 54 deletions

View File

@ -16,7 +16,7 @@ use crate::{
}, },
}; };
use super::utils::{self, CharacterGrid}; use super::utils::{self, CellData, CharacterGrid};
pub struct BgMapWindow { pub struct BgMapWindow {
sim_id: SimId, sim_id: SimId,
@ -94,7 +94,12 @@ impl BgMapWindow {
ui.add(image); ui.add(image);
ui.section("Cell", |ui| { ui.section("Cell", |ui| {
let cell = self.bgmaps.borrow().read::<u16>(self.cell_index); let cell = self.bgmaps.borrow().read::<u16>(self.cell_index);
let (char_index, mut vflip, mut hflip, palette_index) = utils::parse_cell(cell); let CellData {
char_index,
mut vflip,
mut hflip,
palette_index,
} = CellData::parse(cell);
TableBuilder::new(ui) TableBuilder::new(ui)
.column(Column::remainder()) .column(Column::remainder())
.column(Column::remainder()) .column(Column::remainder())
@ -245,7 +250,12 @@ impl BgMapRenderer {
.iter() .iter()
.enumerate() .enumerate()
{ {
let (char_index, vflip, hflip, palette_index) = utils::parse_cell(*cell); let CellData {
char_index,
vflip,
hflip,
palette_index,
} = CellData::parse(*cell);
let char = chardata.range::<u16>(char_index * 8, 8); let char = chardata.range::<u16>(char_index * 8, 8);
let palette = &colors[palette_index]; let palette = &colors[palette_index];
@ -269,7 +279,12 @@ impl BgMapRenderer {
let cell = bgmaps.read::<u16>(index); let cell = bgmaps.read::<u16>(index);
let (char_index, vflip, hflip, palette_index) = utils::parse_cell(cell); let CellData {
char_index,
vflip,
hflip,
palette_index,
} = CellData::parse(cell);
let char = chardata.range::<u16>(char_index * 8, 8); let char = chardata.range::<u16>(char_index * 8, 8);
let palette = if generic_palette { let palette = if generic_palette {
utils::generic_palette(Color32::RED) utils::generic_palette(Color32::RED)

View File

@ -16,7 +16,7 @@ use crate::{
}, },
}; };
use super::utils; use super::utils::{self, Object};
pub struct ObjectWindow { pub struct ObjectWindow {
sim_id: SimId, sim_id: SimId,
@ -31,8 +31,9 @@ pub struct ObjectWindow {
impl ObjectWindow { impl ObjectWindow {
pub fn new(sim_id: SimId, memory: &mut MemoryMonitor, vram: &mut VramProcessor) -> Self { pub fn new(sim_id: SimId, memory: &mut MemoryMonitor, vram: &mut VramProcessor) -> Self {
let renderer = ObjectRenderer::new(sim_id, memory); let renderer = ObjectRenderer::new(sim_id, memory);
let ([object], params) = vram.add(renderer); let ([zoom, full], params) = vram.add(renderer);
let loader = VramTextureLoader::new([("vram://object".into(), object)]); let loader =
VramTextureLoader::new([("vram://zoom".into(), zoom), ("vram://full".into(), full)]);
Self { Self {
sim_id, sim_id,
loader: Arc::new(loader), loader: Arc::new(loader),
@ -59,14 +60,27 @@ impl ObjectWindow {
ui.add(NumberEdit::new(&mut self.index).range(0..1024)); ui.add(NumberEdit::new(&mut self.index).range(0..1024));
}); });
}); });
body.row(row_height, |mut row| {
row.col(|ui| {
ui.label("Address");
}); });
row.col(|ui| {
let address = 0x3e000 + self.index * 8;
let mut address_str = format!("{address:08x}");
ui.add_enabled(
false,
TextEdit::singleline(&mut address_str).horizontal_align(Align::Max),
);
});
});
});
let image = Image::new("vram://zoom")
.maintain_aspect_ratio(true)
.texture_options(TextureOptions::NEAREST);
ui.add(image);
ui.section("Properties", |ui| { ui.section("Properties", |ui| {
let object = self.objects.borrow().read::<[u16; 4]>(self.index); let object = self.objects.borrow().read::<[u16; 4]>(self.index);
let mut x = ((object[0] & 0x3ff) << 6 >> 6) as i16; let mut obj = Object::parse(object);
let mut parallax = ((object[1] & 0x3ff) << 6 >> 6) as i16;
let mut y = ((object[2] & 0x0ff) << 8 >> 8) as i16;
let (mut char_index, mut vflip, mut hflip, palette_index) =
utils::parse_cell(object[3]);
TableBuilder::new(ui) TableBuilder::new(ui)
.column(Column::remainder()) .column(Column::remainder())
.column(Column::remainder()) .column(Column::remainder())
@ -78,7 +92,7 @@ impl ObjectWindow {
row.col(|ui| { row.col(|ui| {
ui.add_enabled( ui.add_enabled(
false, false,
NumberEdit::new(&mut char_index).range(0..2048), NumberEdit::new(&mut obj.data.char_index).range(0..2048),
); );
}); });
}); });
@ -87,7 +101,7 @@ impl ObjectWindow {
ui.label("Palette"); ui.label("Palette");
}); });
row.col(|ui| { row.col(|ui| {
let mut palette = format!("OBJ {}", palette_index); let mut palette = format!("OBJ {}", obj.data.palette_index);
ui.add_enabled( ui.add_enabled(
false, false,
TextEdit::singleline(&mut palette).horizontal_align(Align::Max), TextEdit::singleline(&mut palette).horizontal_align(Align::Max),
@ -99,7 +113,7 @@ impl ObjectWindow {
ui.label("X"); ui.label("X");
}); });
row.col(|ui| { row.col(|ui| {
ui.add_enabled(false, NumberEdit::new(&mut x).range(-512..512)); ui.add_enabled(false, NumberEdit::new(&mut obj.x).range(-512..512));
}); });
}); });
body.row(row_height, |mut row| { body.row(row_height, |mut row| {
@ -107,7 +121,7 @@ impl ObjectWindow {
ui.label("Y"); ui.label("Y");
}); });
row.col(|ui| { row.col(|ui| {
ui.add_enabled(false, NumberEdit::new(&mut y).range(-8..=224)); ui.add_enabled(false, NumberEdit::new(&mut obj.y).range(-8..=224));
}); });
}); });
body.row(row_height, |mut row| { body.row(row_height, |mut row| {
@ -117,17 +131,27 @@ impl ObjectWindow {
row.col(|ui| { row.col(|ui| {
ui.add_enabled( ui.add_enabled(
false, false,
NumberEdit::new(&mut parallax).range(-512..512), NumberEdit::new(&mut obj.parallax).range(-512..512),
); );
}); });
}); });
body.row(row_height, |mut row| { body.row(row_height, |mut row| {
row.col(|ui| { row.col(|ui| {
let checkbox = Checkbox::new(&mut hflip, "H-flip"); let checkbox = Checkbox::new(&mut obj.data.hflip, "H-flip");
ui.add_enabled(false, checkbox); ui.add_enabled(false, checkbox);
}); });
row.col(|ui| { row.col(|ui| {
let checkbox = Checkbox::new(&mut vflip, "V-flip"); let checkbox = Checkbox::new(&mut obj.data.vflip, "V-flip");
ui.add_enabled(false, checkbox);
});
});
body.row(row_height, |mut row| {
row.col(|ui| {
let checkbox = Checkbox::new(&mut obj.lon, "Left");
ui.add_enabled(false, checkbox);
});
row.col(|ui| {
let checkbox = Checkbox::new(&mut obj.ron, "Right");
ui.add_enabled(false, checkbox); ui.add_enabled(false, checkbox);
}); });
}); });
@ -153,7 +177,7 @@ impl ObjectWindow {
} }
fn show_object(&mut self, ui: &mut Ui) { fn show_object(&mut self, ui: &mut Ui) {
let image = Image::new("vram://object") let image = Image::new("vram://full")
.fit_to_original_size(self.scale) .fit_to_original_size(self.scale)
.texture_options(TextureOptions::NEAREST); .texture_options(TextureOptions::NEAREST);
ui.add(image); ui.add(image);
@ -172,7 +196,7 @@ impl AppWindow for ObjectWindow {
fn initial_viewport(&self) -> ViewportBuilder { fn initial_viewport(&self) -> ViewportBuilder {
ViewportBuilder::default() ViewportBuilder::default()
.with_title(format!("Object Data ({})", self.sim_id)) .with_title(format!("Object Data ({})", 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) {
@ -239,50 +263,55 @@ impl ObjectRenderer {
} }
} }
fn render_object(&self, image: &mut VramImage, params: &ObjectParams, eye: Eye) { fn render_object(&self, image: &mut VramImage, params: &ObjectParams, use_pos: bool, eye: Eye) {
let chardata = self.chardata.borrow(); let chardata = self.chardata.borrow();
let objects = self.objects.borrow(); let objects = self.objects.borrow();
let brightness = self.brightness.borrow(); let brightness = self.brightness.borrow();
let palettes = self.palettes.borrow(); let palettes = self.palettes.borrow();
let object: [u16; 4] = objects.read(params.index); let object: [u16; 4] = objects.read(params.index);
let obj = Object::parse(object);
let ron = object[1] & 0x4000 != 0;
let lon = object[1] & 0x8000 != 0;
if match eye { if match eye {
Eye::Left => !lon, Eye::Left => !obj.lon,
Eye::Right => !ron, Eye::Right => !obj.ron,
} { } {
return; return;
} }
let brts = brightness.range::<u8>(0, 8); let brts = brightness.range::<u8>(0, 8);
let (x, y) = if use_pos {
let x = ((object[0] & 0x3ff) << 6 >> 6) as i16; let x = match eye {
let parallax = ((object[1] & 0x3ff) << 6 >> 6) as i16; Eye::Left => obj.x - obj.parallax,
let y = ((object[2] & 0x0ff) << 8 >> 8) as i16; Eye::Right => obj.x + obj.parallax,
};
let (x, color) = match eye { (x, obj.y)
Eye::Left => (x - parallax, params.left_color), } else {
Eye::Right => (x + parallax, params.right_color), (0, 0)
}; };
let (char_index, vflip, hflip, palette_index) = utils::parse_cell(object[3]); let color = match eye {
let char = chardata.range::<u16>(char_index * 8, 8); Eye::Left => params.left_color,
Eye::Right => params.right_color,
};
let char = chardata.range::<u16>(obj.data.char_index * 8, 8);
let palette = if params.generic_palette { let palette = if params.generic_palette {
utils::generic_palette(color) utils::generic_palette(color)
} else { } else {
utils::parse_palette(palettes.read(8 + palette_index * 2), brts, color) utils::parse_palette(palettes.read(8 + obj.data.palette_index * 2), brts, color)
}; };
for row in 0..8 { for row in 0..8 {
let real_y = y + row as i16; let real_y = y + row as i16;
if !(0..384).contains(&real_y) { if !(0..224).contains(&real_y) {
continue; continue;
} }
for (col, pixel) in utils::read_char_row(char, hflip, vflip, row).enumerate() { for (col, pixel) in
utils::read_char_row(char, obj.data.hflip, obj.data.vflip, row).enumerate()
{
let real_x = x + col as i16; let real_x = x + col as i16;
if !(0..224).contains(&real_x) { if !(0..384).contains(&real_x) {
continue; continue;
} }
image.add((real_x as usize, real_y as usize), palette[pixel as usize]); image.add((real_x as usize, real_y as usize), palette[pixel as usize]);
@ -291,17 +320,19 @@ impl ObjectRenderer {
} }
} }
impl VramRenderer<1> for ObjectRenderer { impl VramRenderer<2> for ObjectRenderer {
type Params = ObjectParams; type Params = ObjectParams;
fn sizes(&self) -> [[usize; 2]; 1] { fn sizes(&self) -> [[usize; 2]; 2] {
[[384, 224]] [[8, 8], [384, 224]]
} }
fn render(&mut self, params: &Self::Params, images: &mut [VramImage; 1]) { fn render(&mut self, params: &Self::Params, images: &mut [VramImage; 2]) {
let image = &mut images[0]; images[0].clear();
image.clear(); self.render_object(&mut images[0], params, false, Eye::Left);
self.render_object(image, params, Eye::Left); self.render_object(&mut images[0], params, false, Eye::Right);
self.render_object(image, params, Eye::Right); images[1].clear();
self.render_object(&mut images[1], params, true, Eye::Left);
self.render_object(&mut images[1], params, true, Eye::Right);
} }
} }

View File

@ -28,12 +28,57 @@ pub fn parse_palette(palette: u8, brts: &[u8], color: Color32) -> [Color32; 4] {
] ]
} }
pub fn parse_cell(cell: u16) -> (usize, bool, bool, usize) { pub struct Object {
pub x: i16,
pub lon: bool,
pub ron: bool,
pub parallax: i16,
pub y: i16,
pub data: CellData,
}
impl Object {
pub fn parse(object: [u16; 4]) -> Self {
let x = ((object[0] & 0x3ff) << 6 >> 6) as i16;
let parallax = ((object[1] & 0x3ff) << 6 >> 6) as i16;
let lon = object[1] & 0x8000 != 0;
let ron = object[1] & 0x4000 != 0;
let y = (object[2] & 0x0ff) as i16;
// Y is stored as the bottom 8 bits of an i16,
// so only sign extend if it's out of range.
let y = if y > 224 { y << 8 >> 8 } else { y };
let data = CellData::parse(object[3]);
Self {
x,
lon,
ron,
parallax,
y,
data,
}
}
}
pub struct CellData {
pub palette_index: usize,
pub hflip: bool,
pub vflip: bool,
pub char_index: usize,
}
impl CellData {
pub fn parse(cell: u16) -> Self {
let char_index = (cell & 0x7ff) as usize; let char_index = (cell & 0x7ff) as usize;
let vflip = cell & 0x1000 != 0; let vflip = cell & 0x1000 != 0;
let hflip = cell & 0x2000 != 0; let hflip = cell & 0x2000 != 0;
let palette_index = (cell >> 14) as usize; let palette_index = (cell >> 14) as usize;
(char_index, vflip, hflip, palette_index) Self {
char_index,
vflip,
hflip,
palette_index,
}
}
} }
pub fn read_char_row( pub fn read_char_row(