diff --git a/common/src/video.rs b/common/src/video.rs index bdb2cbc..e31c8fb 100644 --- a/common/src/video.rs +++ b/common/src/video.rs @@ -4,7 +4,14 @@ use egui_multiwin::egui; /// The types of algorithms for scaling up the image #[derive( - PartialEq, strum::Display, strum::EnumIter, serde::Serialize, serde::Deserialize, Clone, Copy, + PartialEq, + strum::Display, + strum::EnumIter, + serde::Serialize, + serde::Deserialize, + Clone, + Copy, + Debug, )] pub enum ScalingAlgorithm { ///The Scale2x algorithm, based on EPX (Eric's pixel expansion) @@ -15,6 +22,17 @@ pub enum ScalingAlgorithm { Eagle, } +impl ScalingAlgorithm { + /// Get the scaling factor + pub fn scale_factor(&self) -> f32 { + match self { + ScalingAlgorithm::Scale2x => 2.0, + ScalingAlgorithm::Scale3x => 3.0, + ScalingAlgorithm::Eagle => 2.0, + } + } +} + /// A 24bpp pixel. #[derive(Copy, Clone, std::cmp::PartialEq, Default)] pub struct Pixel { diff --git a/nes/rust/src/controller.rs b/nes/rust/src/controller.rs index 0870091..8b582bb 100644 --- a/nes/rust/src/controller.rs +++ b/nes/rust/src/controller.rs @@ -397,7 +397,14 @@ pub trait NesControllerTrait { /// Dump data from the controller. No side effects. fn dump_data(&self) -> u8; /// Read data from the controller. - fn read_data(&mut self) -> u8; + fn read_data( + &mut self, + screen: &common_emulator::video::RgbImage, + ppux: u16, + ppuy: u16, + x: u16, + y: u16, + ) -> u8; /// Return the data for all button states fn button_data(&self) -> ButtonCombination; } @@ -569,10 +576,17 @@ impl NesControllerTrait for FourScore { } #[doc = " Read data from the controller."] - fn read_data(&mut self) -> u8 { + fn read_data( + &mut self, + screen: &common_emulator::video::RgbImage, + ppux: u16, + ppuy: u16, + x: u16, + y: u16, + ) -> u8 { match self.clock_counter { - 0..=7 => self.controllers[0].read_data(), - 8..=15 => self.controllers[1].read_data(), + 0..=7 => self.controllers[0].read_data(screen, ppux, ppuy, x, y), + 8..=15 => self.controllers[1].read_data(screen, ppux, ppuy, x, y), 16..=17 => 0, 18 => 0xFF, 19..=23 => 0, @@ -621,7 +635,14 @@ impl NesControllerTrait for DummyController { } #[doc = " Read data from the controller."] - fn read_data(&mut self) -> u8 { + fn read_data( + &mut self, + screen: &common_emulator::video::RgbImage, + ppux: u16, + ppuy: u16, + x: u16, + y: u16, + ) -> u8 { 0xff } } @@ -677,12 +698,30 @@ impl NesControllerTrait for Zapper { fn dump_data(&self) -> u8 { let d3 = self.combo[0].buttons[BUTTON_COMBO_LIGHT].is_some(); let d4 = self.combo[0].buttons[BUTTON_COMBO_FIRE].is_some(); - 0xE7 | if d3 { 1 << 3 } else { 0 } | if !d4 { 1 << 4 } else { 0 } + 0xE7 | if !d4 { 1 << 4 } else { 0 } } #[doc = " Read data from the controller."] - fn read_data(&mut self) -> u8 { - self.dump_data() + fn read_data( + &mut self, + screen: &common_emulator::video::RgbImage, + ppux: u16, + ppuy: u16, + x: u16, + y: u16, + ) -> u8 { + let mut d = self.dump_data(); + if x < 256 && y < 240 { + let color = screen.get_pixel(egui::Vec2 { + x: x as f32, + y: y as f32, + }); + if color[0] > 200 && color[1] > 200 && color[2] > 200 { + println!("Detect color at {},{} {},{}", ppux, ppuy, x, y); + d |= 1 << 3; + } + } + d } } @@ -854,7 +893,14 @@ impl NesControllerTrait for StandardController { data | 0x1e } - fn read_data(&mut self) -> u8 { + fn read_data( + &mut self, + screen: &common_emulator::video::RgbImage, + ppux: u16, + ppuy: u16, + x: u16, + y: u16, + ) -> u8 { self.dump_data() } } diff --git a/nes/rust/src/motherboard.rs b/nes/rust/src/motherboard.rs index 3a6d415..32c8c49 100644 --- a/nes/rust/src/motherboard.rs +++ b/nes/rust/src/motherboard.rs @@ -36,6 +36,10 @@ pub struct NesMotherboard { controllers: [NesController; 2], /// The speed ratio applied to the emulator pub speed_ratio: f32, + ///zapper x coord + x: u16, + ///zapper y coord + y: u16, } impl NesMotherboard { @@ -67,6 +71,8 @@ impl NesMotherboard { last_ppu_coordinates: (0, 0), controllers: [NesController::default(), NesController::default()], speed_ratio: 1.0, + x: 65535, + y: 65535, } } @@ -211,6 +217,12 @@ impl NesMotherboard { } } + /// Set the zapper coordinates + pub fn set_zapper_coords(&mut self, x: u16, y: u16) { + self.x = x; + self.y = y; + } + /// Return a reference to the cartridge if it exists pub fn cartridge(&self) -> Option<&NesCartridge> { self.cart.as_ref() @@ -363,12 +375,24 @@ impl NesMotherboard { self.last_cpu_data = response; } 0x4016 => { - let d = self.controllers[0].read_data() & 0x1f; + let d = self.controllers[0].read_data( + per.ppu.get_frame(), + per.ppu.column(), + per.ppu.row(), + self.x, + self.y, + ) & 0x1f; response = (d ^ 0x1f) | (self.last_cpu_data & 0xe0); self.last_cpu_data = response; } 0x4017 => { - let d = self.controllers[1].read_data() & 0x1f; + let d = self.controllers[1].read_data( + per.ppu.get_frame(), + per.ppu.column(), + per.ppu.row(), + self.x, + self.y, + ) & 0x1f; response = (d ^ 0x1f) | (self.last_cpu_data & 0xe0); self.last_cpu_data = response; } diff --git a/nes/rust/src/ppu.rs b/nes/rust/src/ppu.rs index 9604ed8..56ec409 100644 --- a/nes/rust/src/ppu.rs +++ b/nes/rust/src/ppu.rs @@ -729,7 +729,7 @@ impl NesPpu { /// Returns true when sprites should be fetched. fn should_fetch_sprites(&self) -> bool { - (self.registers[1] & PPU_REGISTER1_DRAW_BACKGROUND) != 0 + (self.registers[1] & (PPU_REGISTER1_DRAW_BACKGROUND | PPU_REGISTER1_DRAW_SPRITES)) != 0 } /// Returns true when sprites should be evaulated. @@ -1470,7 +1470,7 @@ impl NesPpu { } /// Returns a reference to the frame data stored in the ppu. - pub fn get_frame(&mut self) -> &RgbImage { + pub fn get_frame(&self) -> &RgbImage { &self.frame_data } diff --git a/nes/rust/src/windows/main.rs b/nes/rust/src/windows/main.rs index ca6c52e..21bdea3 100644 --- a/nes/rust/src/windows/main.rs +++ b/nes/rust/src/windows/main.rs @@ -955,16 +955,17 @@ impl TrackedWindow for MainNesWindow { }) .sense(egui::Sense::click_and_drag()), ); - if r.clicked() || r.dragged() { + if (r.clicked() || r.dragged()) && !self.mouse { self.mouse = true; self.mouse_miss = false; - self.mouse_delay = 10; - } else if r.clicked_by(egui::PointerButton::Secondary) - || r.dragged_by(egui::PointerButton::Secondary) + self.mouse_delay = 15; + } else if (r.clicked_by(egui::PointerButton::Secondary) + || r.dragged_by(egui::PointerButton::Secondary)) + && !self.mouse { self.mouse = true; self.mouse_miss = true; - self.mouse_delay = 10; + self.mouse_delay = 15; } if r.hovered() { if let Some(pos) = r.hover_pos() { @@ -974,12 +975,21 @@ impl TrackedWindow for MainNesWindow { c.cpu_peripherals.ppu.bg_debug = Some(((coord.x / zoom) as u8, (coord.y / zoom) as u8)); } + let scale_factor = c + .local + .configuration + .scaler + .map(|s| s.scale_factor()) + .or(Some(1.0)) + .unwrap(); + let zcoord = coord / (zoom * scale_factor); + c.mb.set_zapper_coords(zcoord.x as u16, zcoord.y as u16); let pixel = c.local.image.get_pixel(coord / zoom); self.mouse_vision = !self.mouse_miss - && pixel.r() > 10 - && pixel.g() > 10 - && pixel.b() > 10; + && pixel.r() > 100 + && pixel.g() > 100 + && pixel.b() > 100; //println!("Hover at {:?}", pos - r.rect.left_top()); } else {