Split WASM and native versions, and move iced support code to native
This commit is contained in:
497
src/ppu.rs
497
src/ppu.rs
@@ -1,11 +1,6 @@
|
||||
use std::fmt;
|
||||
|
||||
use bytes::{Bytes, BytesMut};
|
||||
use iced::{
|
||||
Point, Size,
|
||||
advanced::graphics::geometry::Renderer,
|
||||
widget::canvas::{Fill, Frame},
|
||||
};
|
||||
|
||||
use crate::mem::{Mapped, PpuMem, Value};
|
||||
|
||||
@@ -16,12 +11,6 @@ pub struct Color {
|
||||
pub b: u8,
|
||||
}
|
||||
|
||||
impl Into<Fill> for Color {
|
||||
fn into(self) -> Fill {
|
||||
iced::Color::from_rgb8(self.r, self.g, self.b).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Color {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "#{:02X}{:02X}{:02X}", self.r, self.g, self.b)
|
||||
@@ -66,6 +55,10 @@ impl<const W: usize, const H: usize> RenderBuffer<W, H> {
|
||||
Bytes::copy_from_slice(&self.raw_rgba)
|
||||
}
|
||||
|
||||
pub fn raw_image(&self) -> &[u8] {
|
||||
&self.raw_rgba
|
||||
}
|
||||
|
||||
pub fn assert_eq(&self, other: &Self) {
|
||||
// if self.buffer != other.buffer {
|
||||
for y in 0..H {
|
||||
@@ -1126,238 +1119,6 @@ impl PPU {
|
||||
pub fn oam_edit_ver(&self) -> usize {
|
||||
self.oam.edit_ver
|
||||
}
|
||||
|
||||
pub fn render_name_table<R: Renderer>(&self, mem: &Mapped, frame: &mut Frame<R>) {
|
||||
for y in 0..60 {
|
||||
for x in 0..64 {
|
||||
let row = y % 30;
|
||||
let col = x % 32;
|
||||
let off = 0x2000 + 0x400 * (y / 30 * 2 + x / 32);
|
||||
let name = mem.peek_ppu((off + col + row * 32) as u16).unwrap() as u16 * 16
|
||||
+ if self.background.second_pattern {
|
||||
0x1000
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let attr = mem
|
||||
.peek_ppu((col / 4 + row / 4 * 8 + 0x3C0 + off) as u16)
|
||||
.unwrap();
|
||||
// attr << (((col & 1) << 1) | ((row & 1) << 0)) * 2
|
||||
// let h_off = ((self.pixel - 1) / 16) % 2;
|
||||
// let v_off = (self.scanline / 16) % 2;
|
||||
// let off = v_off * 4 + h_off * 2;
|
||||
let palette = (attr >> (((col & 2) << 0) | ((row & 2) << 1))) & 0x3;
|
||||
for y_off in 0..8 {
|
||||
let low = mem.peek_ppu(name + y_off).unwrap();
|
||||
let high = mem.peek_ppu(name + y_off + 8).unwrap();
|
||||
for bit in 0..8 {
|
||||
frame.fill_rectangle(
|
||||
Point::new(
|
||||
x as f32 * 8. + 8. - bit as f32,
|
||||
y as f32 * 8. + y_off as f32,
|
||||
),
|
||||
Size::new(1., 1.),
|
||||
match (low & (1 << bit) != 0, high & (1 << bit) != 0) {
|
||||
(false, false) => self.palette.color(0),
|
||||
(true, false) => self.palette.color(1 + 4 * palette),
|
||||
(false, true) => self.palette.color(2 + 4 * palette),
|
||||
(true, true) => self.palette.color(3 + 4 * palette),
|
||||
// (false, false) => Color { r: 0, g: 0, b: 0 },
|
||||
// (true, false) => Color {
|
||||
// r: 64,
|
||||
// g: 64,
|
||||
// b: 64,
|
||||
// },
|
||||
// (false, true) => Color {
|
||||
// r: 128,
|
||||
// g: 128,
|
||||
// b: 128,
|
||||
// },
|
||||
// (true, true) => Color {
|
||||
// r: 255,
|
||||
// g: 255,
|
||||
// b: 255,
|
||||
// },
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
// for
|
||||
// let pat = mem.peek();
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn name_cursor_info(&self, mem: &Mapped, cursor: Point) -> Option<String> {
|
||||
let x = (cursor.x / 8.) as usize;
|
||||
let y = (cursor.y / 8.) as usize;
|
||||
if x < 64 && y < 60 {
|
||||
let row = y % 30;
|
||||
let col = x % 32;
|
||||
let off = 0x2000 + 0x400 * (y / 30 * 2 + x / 32);
|
||||
let name = mem.peek_ppu((off + col + row * 32) as u16).unwrap() as usize;
|
||||
let attr = mem
|
||||
.peek_ppu((col / 4 + row / 4 * 8 + 0x3C0 + off) as u16)
|
||||
.unwrap();
|
||||
Some(format!(
|
||||
"Row, Column: {}, {}
|
||||
X, Y: {}, {}
|
||||
Tilemap address: ${:04X}
|
||||
|
||||
Tile Index: ${:02X}
|
||||
Tile Address (PPU): ${:04X}
|
||||
Tile Address (CHR): ${:04X}
|
||||
|
||||
Palette Index {}
|
||||
Palette Address ${:04X}
|
||||
|
||||
Attribute Address ${:04X}
|
||||
Attribute data: ${:02X}
|
||||
",
|
||||
row,
|
||||
col,
|
||||
col * 8,
|
||||
row * 8,
|
||||
off + col + row * 32,
|
||||
name,
|
||||
name * 16
|
||||
+ if self.background.second_pattern {
|
||||
0x1000
|
||||
} else {
|
||||
0
|
||||
},
|
||||
name * 16
|
||||
+ if self.background.second_pattern {
|
||||
0x1000
|
||||
} else {
|
||||
0
|
||||
},
|
||||
(attr >> (((col & 1) << 1) | ((row & 1) << 2))) & 0x3,
|
||||
((attr >> (((col & 1) << 1) | ((row & 1) << 2))) & 0x3) as usize * 4 + 0x3F00,
|
||||
col / 4 + row / 4 * 8 + 0x3C0 + off,
|
||||
attr,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_pattern_tables<R: Renderer>(&self, mem: &Mapped, frame: &mut Frame<R>) {
|
||||
for y in 0..16 {
|
||||
for x in 0..16 {
|
||||
let name = (y * 16 + x) * 16;
|
||||
for y_off in 0..8 {
|
||||
let low = mem.peek_ppu(name + y_off).unwrap();
|
||||
let high = mem.peek_ppu(name + y_off + 8).unwrap();
|
||||
for bit in 0..8 {
|
||||
frame.fill_rectangle(
|
||||
Point::new(
|
||||
x as f32 * 8. + 8. - bit as f32,
|
||||
y as f32 * 8. + y_off as f32,
|
||||
),
|
||||
Size::new(1., 1.),
|
||||
match (low & (1 << bit) != 0, high & (1 << bit) != 0) {
|
||||
(false, false) => Color { r: 0, g: 0, b: 0 },
|
||||
(true, false) => Color {
|
||||
r: 64,
|
||||
g: 64,
|
||||
b: 64,
|
||||
},
|
||||
(false, true) => Color {
|
||||
r: 128,
|
||||
g: 128,
|
||||
b: 128,
|
||||
},
|
||||
(true, true) => Color {
|
||||
r: 255,
|
||||
g: 255,
|
||||
b: 255,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for y in 0..16 {
|
||||
for x in 0..16 {
|
||||
let name = (y * 16 + x) * 16;
|
||||
for y_off in 0..8 {
|
||||
let low = mem.peek_ppu(name + y_off + 0x1000).unwrap();
|
||||
let high = mem.peek_ppu(name + y_off + 8 + 0x1000).unwrap();
|
||||
for bit in 0..8 {
|
||||
frame.fill_rectangle(
|
||||
Point::new(
|
||||
x as f32 * 8. + 8. - bit as f32,
|
||||
y as f32 * 8. + y_off as f32 + 130.,
|
||||
),
|
||||
Size::new(1., 1.),
|
||||
match (low & (1 << bit) != 0, high & (1 << bit) != 0) {
|
||||
(false, false) => Color { r: 0, g: 0, b: 0 },
|
||||
(true, false) => Color {
|
||||
r: 64,
|
||||
g: 64,
|
||||
b: 64,
|
||||
},
|
||||
(false, true) => Color {
|
||||
r: 128,
|
||||
g: 128,
|
||||
b: 128,
|
||||
},
|
||||
(true, true) => Color {
|
||||
r: 255,
|
||||
g: 255,
|
||||
b: 255,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
// for
|
||||
// let pat = mem.peek();
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn pattern_cursor_info(&self, cursor: Point) -> Option<String> {
|
||||
let x = (cursor.x / 8.) as usize;
|
||||
let y = (cursor.y / 8.) as usize;
|
||||
if x < 16 && y < 32 {
|
||||
Some(format!(
|
||||
"Tile address (PPU): {:04X}\nTile address (CHR): {:04X}\nIndex: {:02X}",
|
||||
(y * 16 + x) * 16,
|
||||
(y * 16 + x) * 16,
|
||||
((y % 16) * 16 + x),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_palette<R: Renderer>(&self, frame: &mut Frame<R>) {
|
||||
for y in 0..8 {
|
||||
for x in 0..4 {
|
||||
frame.fill_rectangle(
|
||||
Point::new(x as f32 * 10., y as f32 * 10.),
|
||||
Size::new(10., 10.),
|
||||
self.palette.colors[(self.palette.ram[x + y * 4] & 0x3F) as usize],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn palette_cursor_info(&self, cursor: Point) -> Option<String> {
|
||||
let x = (cursor.x / 10.) as usize;
|
||||
let y = (cursor.y / 10.) as usize;
|
||||
if x < 4 && y < 8 {
|
||||
Some(format!(
|
||||
"Index: {:02X}\nValue: {:02X}\nColor code: {}",
|
||||
x + y * 4,
|
||||
self.palette.ram[x + y * 4] & 0x3F,
|
||||
self.palette.colors[(self.palette.ram[x + y * 4] & 0x3F) as usize],
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -1414,3 +1175,253 @@ mod tests {
|
||||
assert_eq!(ppu.background.w, false);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "iced")]
|
||||
mod ppu_iced {
|
||||
use super::*;
|
||||
use iced::{
|
||||
Point, Size,
|
||||
advanced::graphics::geometry::Renderer,
|
||||
widget::canvas::{Fill, Frame},
|
||||
};
|
||||
|
||||
impl Into<Fill> for Color {
|
||||
fn into(self) -> Fill {
|
||||
iced::Color::from_rgb8(self.r, self.g, self.b).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl PPU {
|
||||
pub fn render_name_table<R: Renderer>(&self, mem: &Mapped, frame: &mut Frame<R>) {
|
||||
for y in 0..60 {
|
||||
for x in 0..64 {
|
||||
let row = y % 30;
|
||||
let col = x % 32;
|
||||
let off = 0x2000 + 0x400 * (y / 30 * 2 + x / 32);
|
||||
let name = mem.peek_ppu((off + col + row * 32) as u16).unwrap() as u16 * 16
|
||||
+ if self.background.second_pattern {
|
||||
0x1000
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let attr = mem
|
||||
.peek_ppu((col / 4 + row / 4 * 8 + 0x3C0 + off) as u16)
|
||||
.unwrap();
|
||||
// attr << (((col & 1) << 1) | ((row & 1) << 0)) * 2
|
||||
// let h_off = ((self.pixel - 1) / 16) % 2;
|
||||
// let v_off = (self.scanline / 16) % 2;
|
||||
// let off = v_off * 4 + h_off * 2;
|
||||
let palette = (attr >> (((col & 2) << 0) | ((row & 2) << 1))) & 0x3;
|
||||
for y_off in 0..8 {
|
||||
let low = mem.peek_ppu(name + y_off).unwrap();
|
||||
let high = mem.peek_ppu(name + y_off + 8).unwrap();
|
||||
for bit in 0..8 {
|
||||
frame.fill_rectangle(
|
||||
Point::new(
|
||||
x as f32 * 8. + 8. - bit as f32,
|
||||
y as f32 * 8. + y_off as f32,
|
||||
),
|
||||
Size::new(1., 1.),
|
||||
match (low & (1 << bit) != 0, high & (1 << bit) != 0) {
|
||||
(false, false) => self.palette.color(0),
|
||||
(true, false) => self.palette.color(1 + 4 * palette),
|
||||
(false, true) => self.palette.color(2 + 4 * palette),
|
||||
(true, true) => self.palette.color(3 + 4 * palette),
|
||||
// (false, false) => Color { r: 0, g: 0, b: 0 },
|
||||
// (true, false) => Color {
|
||||
// r: 64,
|
||||
// g: 64,
|
||||
// b: 64,
|
||||
// },
|
||||
// (false, true) => Color {
|
||||
// r: 128,
|
||||
// g: 128,
|
||||
// b: 128,
|
||||
// },
|
||||
// (true, true) => Color {
|
||||
// r: 255,
|
||||
// g: 255,
|
||||
// b: 255,
|
||||
// },
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
// for
|
||||
// let pat = mem.peek();
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn name_cursor_info(&self, mem: &Mapped, cursor: Point) -> Option<String> {
|
||||
let x = (cursor.x / 8.) as usize;
|
||||
let y = (cursor.y / 8.) as usize;
|
||||
if x < 64 && y < 60 {
|
||||
let row = y % 30;
|
||||
let col = x % 32;
|
||||
let off = 0x2000 + 0x400 * (y / 30 * 2 + x / 32);
|
||||
let name = mem.peek_ppu((off + col + row * 32) as u16).unwrap() as usize;
|
||||
let attr = mem
|
||||
.peek_ppu((col / 4 + row / 4 * 8 + 0x3C0 + off) as u16)
|
||||
.unwrap();
|
||||
Some(format!(
|
||||
"Row, Column: {}, {}
|
||||
X, Y: {}, {}
|
||||
Tilemap address: ${:04X}
|
||||
|
||||
Tile Index: ${:02X}
|
||||
Tile Address (PPU): ${:04X}
|
||||
Tile Address (CHR): ${:04X}
|
||||
|
||||
Palette Index {}
|
||||
Palette Address ${:04X}
|
||||
|
||||
Attribute Address ${:04X}
|
||||
Attribute data: ${:02X}
|
||||
",
|
||||
row,
|
||||
col,
|
||||
col * 8,
|
||||
row * 8,
|
||||
off + col + row * 32,
|
||||
name,
|
||||
name * 16
|
||||
+ if self.background.second_pattern {
|
||||
0x1000
|
||||
} else {
|
||||
0
|
||||
},
|
||||
name * 16
|
||||
+ if self.background.second_pattern {
|
||||
0x1000
|
||||
} else {
|
||||
0
|
||||
},
|
||||
(attr >> (((col & 1) << 1) | ((row & 1) << 2))) & 0x3,
|
||||
((attr >> (((col & 1) << 1) | ((row & 1) << 2))) & 0x3) as usize * 4 + 0x3F00,
|
||||
col / 4 + row / 4 * 8 + 0x3C0 + off,
|
||||
attr,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_pattern_tables<R: Renderer>(&self, mem: &Mapped, frame: &mut Frame<R>) {
|
||||
for y in 0..16 {
|
||||
for x in 0..16 {
|
||||
let name = (y * 16 + x) * 16;
|
||||
for y_off in 0..8 {
|
||||
let low = mem.peek_ppu(name + y_off).unwrap();
|
||||
let high = mem.peek_ppu(name + y_off + 8).unwrap();
|
||||
for bit in 0..8 {
|
||||
frame.fill_rectangle(
|
||||
Point::new(
|
||||
x as f32 * 8. + 8. - bit as f32,
|
||||
y as f32 * 8. + y_off as f32,
|
||||
),
|
||||
Size::new(1., 1.),
|
||||
match (low & (1 << bit) != 0, high & (1 << bit) != 0) {
|
||||
(false, false) => Color { r: 0, g: 0, b: 0 },
|
||||
(true, false) => Color {
|
||||
r: 64,
|
||||
g: 64,
|
||||
b: 64,
|
||||
},
|
||||
(false, true) => Color {
|
||||
r: 128,
|
||||
g: 128,
|
||||
b: 128,
|
||||
},
|
||||
(true, true) => Color {
|
||||
r: 255,
|
||||
g: 255,
|
||||
b: 255,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for y in 0..16 {
|
||||
for x in 0..16 {
|
||||
let name = (y * 16 + x) * 16;
|
||||
for y_off in 0..8 {
|
||||
let low = mem.peek_ppu(name + y_off + 0x1000).unwrap();
|
||||
let high = mem.peek_ppu(name + y_off + 8 + 0x1000).unwrap();
|
||||
for bit in 0..8 {
|
||||
frame.fill_rectangle(
|
||||
Point::new(
|
||||
x as f32 * 8. + 8. - bit as f32,
|
||||
y as f32 * 8. + y_off as f32 + 130.,
|
||||
),
|
||||
Size::new(1., 1.),
|
||||
match (low & (1 << bit) != 0, high & (1 << bit) != 0) {
|
||||
(false, false) => Color { r: 0, g: 0, b: 0 },
|
||||
(true, false) => Color {
|
||||
r: 64,
|
||||
g: 64,
|
||||
b: 64,
|
||||
},
|
||||
(false, true) => Color {
|
||||
r: 128,
|
||||
g: 128,
|
||||
b: 128,
|
||||
},
|
||||
(true, true) => Color {
|
||||
r: 255,
|
||||
g: 255,
|
||||
b: 255,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
// for
|
||||
// let pat = mem.peek();
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn pattern_cursor_info(&self, cursor: Point) -> Option<String> {
|
||||
let x = (cursor.x / 8.) as usize;
|
||||
let y = (cursor.y / 8.) as usize;
|
||||
if x < 16 && y < 32 {
|
||||
Some(format!(
|
||||
"Tile address (PPU): {:04X}\nTile address (CHR): {:04X}\nIndex: {:02X}",
|
||||
(y * 16 + x) * 16,
|
||||
(y * 16 + x) * 16,
|
||||
((y % 16) * 16 + x),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_palette<R: Renderer>(&self, frame: &mut Frame<R>) {
|
||||
for y in 0..8 {
|
||||
for x in 0..4 {
|
||||
frame.fill_rectangle(
|
||||
Point::new(x as f32 * 10., y as f32 * 10.),
|
||||
Size::new(10., 10.),
|
||||
self.palette.colors[(self.palette.ram[x + y * 4] & 0x3F) as usize],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn palette_cursor_info(&self, cursor: Point) -> Option<String> {
|
||||
let x = (cursor.x / 10.) as usize;
|
||||
let y = (cursor.y / 10.) as usize;
|
||||
if x < 4 && y < 8 {
|
||||
Some(format!(
|
||||
"Index: {:02X}\nValue: {:02X}\nColor code: {}",
|
||||
x + y * 4,
|
||||
self.palette.ram[x + y * 4] & 0x3F,
|
||||
self.palette.colors[(self.palette.ram[x + y * 4] & 0x3F) as usize],
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user