View hbias worlds
This commit is contained in:
parent
2a4599756c
commit
3cdc0583a6
|
@ -98,8 +98,11 @@ macro_rules! primitive_memory_value_impl {
|
||||||
}
|
}
|
||||||
|
|
||||||
primitive_memory_value_impl!(u8, 1);
|
primitive_memory_value_impl!(u8, 1);
|
||||||
|
primitive_memory_value_impl!(i8, 2);
|
||||||
primitive_memory_value_impl!(u16, 2);
|
primitive_memory_value_impl!(u16, 2);
|
||||||
|
primitive_memory_value_impl!(i16, 2);
|
||||||
primitive_memory_value_impl!(u32, 4);
|
primitive_memory_value_impl!(u32, 4);
|
||||||
|
primitive_memory_value_impl!(i32, 2);
|
||||||
|
|
||||||
impl<const N: usize, T: MemoryValue> MemoryValue for [T; N] {
|
impl<const N: usize, T: MemoryValue> MemoryValue for [T; N] {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -34,10 +34,11 @@ pub trait UiExt {
|
||||||
|
|
||||||
impl UiExt for Ui {
|
impl UiExt for Ui {
|
||||||
fn section(&mut self, title: impl Into<String>, add_contents: impl FnOnce(&mut Ui)) {
|
fn section(&mut self, title: impl Into<String>, add_contents: impl FnOnce(&mut Ui)) {
|
||||||
|
let title: String = title.into();
|
||||||
let mut frame = Frame::group(self.style());
|
let mut frame = Frame::group(self.style());
|
||||||
frame.outer_margin.top += 10.0;
|
frame.outer_margin.top += 10.0;
|
||||||
frame.inner_margin.top += 2.0;
|
frame.inner_margin.top += 2.0;
|
||||||
let res = frame.show(self, add_contents);
|
let res = self.push_id(&title, |ui| frame.show(ui, add_contents));
|
||||||
let text = RichText::new(title).background_color(self.style().visuals.panel_fill);
|
let text = RichText::new(title).background_color(self.style().visuals.panel_fill);
|
||||||
let old_rect = res.response.rect;
|
let old_rect = res.response.rect;
|
||||||
let mut text_rect = old_rect;
|
let mut text_rect = old_rect;
|
||||||
|
@ -133,12 +134,14 @@ impl<'a, T: Number> NumberEdit<'a, T> {
|
||||||
|
|
||||||
impl<T: Number> Widget for NumberEdit<'_, T> {
|
impl<T: Number> Widget for NumberEdit<'_, T> {
|
||||||
fn ui(self, ui: &mut Ui) -> Response {
|
fn ui(self, ui: &mut Ui) -> Response {
|
||||||
|
let id = ui.id();
|
||||||
|
|
||||||
let (last_value, mut str, focus) = ui.memory(|m| {
|
let (last_value, mut str, focus) = ui.memory(|m| {
|
||||||
let (lv, s) = m
|
let (lv, s) = m
|
||||||
.data
|
.data
|
||||||
.get_temp(ui.id())
|
.get_temp(id)
|
||||||
.unwrap_or((*self.value, self.value.to_string()));
|
.unwrap_or((*self.value, self.value.to_string()));
|
||||||
let focus = m.has_focus(ui.id());
|
let focus = m.has_focus(id);
|
||||||
(lv, s, focus)
|
(lv, s, focus)
|
||||||
});
|
});
|
||||||
let mut stale = false;
|
let mut stale = false;
|
||||||
|
@ -174,7 +177,7 @@ impl<T: Number> Widget for NumberEdit<'_, T> {
|
||||||
}
|
}
|
||||||
let text = TextEdit::singleline(&mut str)
|
let text = TextEdit::singleline(&mut str)
|
||||||
.horizontal_align(Align::Max)
|
.horizontal_align(Align::Max)
|
||||||
.id(ui.id())
|
.id(id)
|
||||||
.margin(Margin {
|
.margin(Margin {
|
||||||
left: 4.0,
|
left: 4.0,
|
||||||
right: 20.0,
|
right: 20.0,
|
||||||
|
@ -242,7 +245,7 @@ impl<T: Number> Widget for NumberEdit<'_, T> {
|
||||||
stale = true;
|
stale = true;
|
||||||
}
|
}
|
||||||
if stale {
|
if stale {
|
||||||
ui.memory_mut(|m| m.data.insert_temp(ui.id(), (*self.value, str)));
|
ui.memory_mut(|m| m.data.insert_temp(id, (*self.value, str)));
|
||||||
}
|
}
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,9 @@ pub struct WorldWindow {
|
||||||
sim_id: SimId,
|
sim_id: SimId,
|
||||||
loader: Arc<VramTextureLoader>,
|
loader: Arc<VramTextureLoader>,
|
||||||
worlds: MemoryView,
|
worlds: MemoryView,
|
||||||
|
bgmaps: MemoryView,
|
||||||
index: usize,
|
index: usize,
|
||||||
|
param_index: usize,
|
||||||
generic_palette: bool,
|
generic_palette: bool,
|
||||||
params: VramParams<WorldParams>,
|
params: VramParams<WorldParams>,
|
||||||
scale: f32,
|
scale: f32,
|
||||||
|
@ -45,7 +47,9 @@ impl WorldWindow {
|
||||||
sim_id,
|
sim_id,
|
||||||
loader: Arc::new(loader),
|
loader: Arc::new(loader),
|
||||||
worlds: memory.watch(sim_id, 0x3d800, 0x400),
|
worlds: memory.watch(sim_id, 0x3d800, 0x400),
|
||||||
|
bgmaps: memory.watch(sim_id, 0x00020000, 0x20000),
|
||||||
index: params.index,
|
index: params.index,
|
||||||
|
param_index: 0,
|
||||||
generic_palette: params.generic_palette,
|
generic_palette: params.generic_palette,
|
||||||
params,
|
params,
|
||||||
scale: 1.0,
|
scale: 1.0,
|
||||||
|
@ -262,6 +266,57 @@ impl WorldWindow {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
if world.header.mode == WorldMode::HBias {
|
||||||
|
ui.section("H-bias", |ui| {
|
||||||
|
TableBuilder::new(ui)
|
||||||
|
.column(Column::remainder())
|
||||||
|
.column(Column::remainder())
|
||||||
|
.body(|mut body| {
|
||||||
|
body.row(row_height, |mut row| {
|
||||||
|
row.col(|ui| {
|
||||||
|
ui.label("Index");
|
||||||
|
});
|
||||||
|
row.col(|ui| {
|
||||||
|
ui.add(NumberEdit::new(&mut self.param_index).range(0..32));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
let base = world.param_base + self.param_index * 2;
|
||||||
|
let mut param = HBiasParam::load(&self.bgmaps.borrow(), base);
|
||||||
|
body.row(row_height, |mut row| {
|
||||||
|
row.col(|ui| {
|
||||||
|
ui.label("Address");
|
||||||
|
});
|
||||||
|
row.col(|ui| {
|
||||||
|
let address = 0x00020000 + 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("Left");
|
||||||
|
});
|
||||||
|
row.col(|ui| {
|
||||||
|
ui.add(NumberEdit::new(&mut param.left).range(-4096..4096));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
body.row(row_height, |mut row| {
|
||||||
|
row.col(|ui| {
|
||||||
|
ui.label("Right");
|
||||||
|
});
|
||||||
|
row.col(|ui| {
|
||||||
|
ui.add(NumberEdit::new(&mut param.right).range(-4096..4096));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
self.param_index = 0;
|
||||||
|
}
|
||||||
ui.section("Display", |ui| {
|
ui.section("Display", |ui| {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label("Scale");
|
ui.label("Scale");
|
||||||
|
@ -497,48 +552,44 @@ impl WorldRenderer {
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut chars = CharCache::new(self.chardata.borrow());
|
let chardata = self.chardata.borrow();
|
||||||
let mut cells = CellCache::new(self.bgmaps.borrow());
|
let bgmaps = self.bgmaps.borrow();
|
||||||
|
let mut chars = [CharCache::new(&chardata), CharCache::new(&chardata)];
|
||||||
|
let mut cells = [CellCache::new(&bgmaps), CellCache::new(&bgmaps)];
|
||||||
|
let mut source = SourceCoordCalculator::new(&bgmaps, &world);
|
||||||
|
|
||||||
for y in 0..height {
|
for y in 0..height {
|
||||||
let dy = y + world.dst_y;
|
let dy = y + world.dst_y;
|
||||||
if !(0..224).contains(&dy) {
|
if !(0..224).contains(&dy) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let sy = y + world.src_y;
|
|
||||||
|
|
||||||
// left side
|
|
||||||
for x in 0..world.width {
|
for x in 0..world.width {
|
||||||
let dx = x + world.dst_x - world.dst_parallax;
|
let dx = x + world.dst_x - world.dst_parallax;
|
||||||
if !(0..384).contains(&dx) {
|
if world.header.lon && (0..384).contains(&dx) {
|
||||||
continue;
|
let (sx, sy) = source.left(x, y);
|
||||||
|
|
||||||
|
let cell_index = world.source_cell(sx, sy);
|
||||||
|
let cell = cells[0].get(cell_index);
|
||||||
|
let char = chars[0].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]);
|
||||||
}
|
}
|
||||||
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;
|
let dx = x + world.dst_x + world.dst_parallax;
|
||||||
if !(0..384).contains(&dx) {
|
if world.header.ron && (0..384).contains(&dx) {
|
||||||
continue;
|
let (sx, sy) = source.right(x, y);
|
||||||
}
|
|
||||||
let sx = x + world.src_x + world.src_parallax;
|
|
||||||
|
|
||||||
let cell_index = world.source_cell(sx, sy);
|
let cell_index = world.source_cell(sx, sy);
|
||||||
let cell = cells.get(cell_index);
|
let cell = cells[1].get(cell_index);
|
||||||
let char = chars.get(cell.char_index);
|
let char = chars[1].get(cell.char_index);
|
||||||
let row = (sy & 0x7) as usize;
|
let row = (sy & 0x7) as usize;
|
||||||
let col = (sx & 0x7) as usize;
|
let col = (sx & 0x7) as usize;
|
||||||
let pixel = utils::read_char_pixel(char, cell.hflip, cell.vflip, row, col);
|
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]);
|
image.add((dx as usize, dy as usize), colors[1][pixel as usize]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -556,7 +607,7 @@ impl VramRenderer<1> for WorldRenderer {
|
||||||
|
|
||||||
let worlds = self.worlds.borrow();
|
let worlds = self.worlds.borrow();
|
||||||
let header = WorldHeader::parse(worlds.read(params.index * 16));
|
let header = WorldHeader::parse(worlds.read(params.index * 16));
|
||||||
if header.end || (!header.lon && header.ron) {
|
if header.end || (!header.lon && !header.ron) {
|
||||||
image.clear();
|
image.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -693,13 +744,13 @@ impl Display for WorldMode {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CellCache<'a> {
|
struct CellCache<'a> {
|
||||||
bgmaps: MemoryRef<'a>,
|
bgmaps: &'a MemoryRef<'a>,
|
||||||
index: usize,
|
index: usize,
|
||||||
cell: CellData,
|
cell: CellData,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CellCache<'a> {
|
impl<'a> CellCache<'a> {
|
||||||
fn new(bgmaps: MemoryRef<'a>) -> Self {
|
fn new(bgmaps: &'a MemoryRef<'a>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
bgmaps,
|
bgmaps,
|
||||||
index: 0x10000,
|
index: 0x10000,
|
||||||
|
@ -718,13 +769,13 @@ impl<'a> CellCache<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CharCache<'a> {
|
struct CharCache<'a> {
|
||||||
chardata: MemoryRef<'a>,
|
chardata: &'a MemoryRef<'a>,
|
||||||
index: usize,
|
index: usize,
|
||||||
char: [u16; 8],
|
char: [u16; 8],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CharCache<'a> {
|
impl<'a> CharCache<'a> {
|
||||||
fn new(chardata: MemoryRef<'a>) -> Self {
|
fn new(chardata: &'a MemoryRef<'a>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
chardata,
|
chardata,
|
||||||
index: 2048,
|
index: 2048,
|
||||||
|
@ -740,3 +791,82 @@ impl<'a> CharCache<'a> {
|
||||||
&self.char
|
&self.char
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SourceCoordCalculator<'a> {
|
||||||
|
params: &'a MemoryRef<'a>,
|
||||||
|
world: &'a World,
|
||||||
|
y: i16,
|
||||||
|
param: SourceParam,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> SourceCoordCalculator<'a> {
|
||||||
|
fn new(params: &'a MemoryRef<'a>, world: &'a World) -> Self {
|
||||||
|
Self {
|
||||||
|
params,
|
||||||
|
world,
|
||||||
|
y: -1,
|
||||||
|
param: SourceParam::Normal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn left(&mut self, x: i16, y: i16) -> (i16, i16) {
|
||||||
|
self.update_param(y);
|
||||||
|
match &self.param {
|
||||||
|
SourceParam::HBias(HBiasParam { left, .. }) => {
|
||||||
|
let sx = x + self.world.src_x - self.world.src_parallax + *left;
|
||||||
|
let sy = y + self.world.src_y;
|
||||||
|
(sx, sy)
|
||||||
|
}
|
||||||
|
SourceParam::Normal => {
|
||||||
|
let sx = x + self.world.src_x - self.world.src_parallax;
|
||||||
|
let sy = y + self.world.src_y;
|
||||||
|
(sx, sy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn right(&mut self, x: i16, y: i16) -> (i16, i16) {
|
||||||
|
self.update_param(y);
|
||||||
|
match &self.param {
|
||||||
|
SourceParam::HBias(HBiasParam { right, .. }) => {
|
||||||
|
let sx = x + self.world.src_x + self.world.src_parallax + *right;
|
||||||
|
let sy = y + self.world.src_y;
|
||||||
|
(sx, sy)
|
||||||
|
}
|
||||||
|
SourceParam::Normal => {
|
||||||
|
let sx = x + self.world.src_x + self.world.src_parallax;
|
||||||
|
let sy = y + self.world.src_y;
|
||||||
|
(sx, sy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_param(&mut self, y: i16) {
|
||||||
|
if self.y == y {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if self.world.header.mode == WorldMode::HBias {
|
||||||
|
let base = self.world.param_base + (2 * y as usize);
|
||||||
|
self.param = SourceParam::HBias(HBiasParam::load(self.params, base));
|
||||||
|
}
|
||||||
|
self.y = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SourceParam {
|
||||||
|
Normal,
|
||||||
|
HBias(HBiasParam),
|
||||||
|
}
|
||||||
|
|
||||||
|
struct HBiasParam {
|
||||||
|
left: i16,
|
||||||
|
right: i16,
|
||||||
|
}
|
||||||
|
|
||||||
|
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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue