Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deferred viewports #306

Merged
merged 9 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ jobs:
name: Lint TetaNES (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
steps:
Expand All @@ -60,7 +61,9 @@ jobs:
fetch-depth: 0
- uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly
# TODO: pin nightly temporarily to fix coreaudio-sys issue with 2024-06-23
# See: https://github.com/RustAudio/coreaudio-sys/issues/104
toolchain: nightly-2024-06-16
components: clippy
- uses: Swatinem/rust-cache@v2
- if: startsWith(matrix.os, 'ubuntu')
Expand All @@ -74,6 +77,7 @@ jobs:
name: Lint TetaNES Core (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
toolchain: [nightly, stable, 1.78]
Expand Down
2 changes: 1 addition & 1 deletion tetanes/src/bin/build_artifacts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ impl Build {
let volume = PathBuf::from("/Volumes").join(&artifact_name);
let app_name = format!("{}.app", self.app_name);
let dmg_name = format!("{artifact_name}-uncompressed.dmg");
let dmg_path = build_dir.join(&dmg_name);
let dmg_path = build_dir.join(dmg_name);
let dmg_name_compressed = format!("{artifact_name}.dmg");
let dmg_path_compressed = build_dir.join(&dmg_name_compressed);
let dmg_path_dist = self.dist_dir.join(&dmg_name_compressed);
Expand Down
15 changes: 7 additions & 8 deletions tetanes/src/nes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use crate::{
nes::{
event::{RendererEvent, RunState, SendNesEvent, UiEvent},
event::{NesEventProxy, RendererEvent, RunState, UiEvent},
input::{Gamepads, InputBindings},
renderer::{FrameRecycle, Resources},
},
Expand All @@ -23,7 +23,7 @@ use thingbuf::mpsc::blocking;
use tracing::{debug, error};
use winit::{
event::Modifiers,
event_loop::{EventLoop, EventLoopBuilder, EventLoopProxy, EventLoopWindowTarget},
event_loop::{EventLoop, EventLoopBuilder, EventLoopWindowTarget},
window::{Window, WindowId},
};

Expand All @@ -44,7 +44,7 @@ pub struct Nes {
/// Set during initialization, then taken and set to `None` when running because
/// `EventLoopProxy` can only be created on the initial `EventLoop` and not on
/// `&EventLoopWindowTarget`.
pub(crate) init_state: Option<(Config, EventLoopProxy<NesEvent>)>,
pub(crate) init_state: Option<(Config, NesEventProxy)>,
/// Initially `Suspended`. `Pending` after `Resume` event received and spanwed. `Running` after
/// resources future completes.
pub(crate) state: State,
Expand Down Expand Up @@ -76,7 +76,7 @@ pub(crate) struct Running {
pub(crate) cfg: Config,
// Only used by wasm currently
#[allow(unused)]
pub(crate) tx: EventLoopProxy<NesEvent>,
pub(crate) tx: NesEventProxy,
pub(crate) emulation: Emulation,
pub(crate) renderer: Renderer,
pub(crate) input_bindings: InputBindings,
Expand Down Expand Up @@ -106,9 +106,8 @@ impl Nes {

/// Create the NES instance.
pub fn new(cfg: Config, event_loop: &EventLoop<NesEvent>) -> Self {
let tx = event_loop.create_proxy();
Self {
init_state: Some((cfg, tx)),
init_state: Some((cfg, NesEventProxy::new(event_loop))),
state: State::Suspended,
}
}
Expand Down Expand Up @@ -140,11 +139,11 @@ impl Nes {
match Renderer::create_painter(window).await {
Ok(painter) => {
painter_tx.send(painter).expect("failed to send painter");
event_tx.nes_event(RendererEvent::ResourcesReady);
event_tx.event(RendererEvent::ResourcesReady);
}
Err(err) => {
error!("failed to create painter: {err:?}");
event_tx.nes_event(UiEvent::Terminate);
event_tx.event(UiEvent::Terminate);
}
}
}
Expand Down
135 changes: 133 additions & 2 deletions tetanes/src/nes/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ pub enum Action {
Debug(Debug),
}

impl PartialOrd for Action {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}

impl Ord for Action {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.as_ref().cmp(other.as_ref())
}
}

impl Action {
pub const BINDABLE: [Self; 111] = [
Self::Ui(Ui::Quit),
Expand Down Expand Up @@ -173,9 +185,10 @@ impl AsRef<str> for Action {
},
Action::Menu(menu) => match menu {
Menu::About => "Toggle About Window",
Menu::Keybinds => "Toggle Keybinds Window",
Menu::Keybinds => "Toggle Keybinds Menu",
Menu::PerfStats => "Toggle Performance Stats Window",
Menu::Preferences => "Toggle Preferences Window",
Menu::PpuViewer => "Toggle PPU Viewer",
Menu::Preferences => "Toggle Preferences Menu",
},
Action::Feature(feature) => match feature {
Feature::ToggleReplayRecording => "Toggle Replay Recording",
Expand Down Expand Up @@ -284,6 +297,124 @@ impl AsRef<str> for Action {
}
}

impl TryFrom<&str> for Action {
type Error = anyhow::Error;

fn try_from(s: &str) -> Result<Self, Self::Error> {
Ok(match s {
"Quit" => Self::Ui(Ui::Quit),
"Toggle Pause" => Self::Ui(Ui::TogglePause),
"Load ROM" => Self::Ui(Ui::LoadRom),
"Unload ROM" => Self::Ui(Ui::UnloadRom),
"Load Replay" => Self::Ui(Ui::LoadReplay),
"Toggle About Window" => Self::Menu(Menu::About),
"Toggle Keybinds Menu" => Self::Menu(Menu::Keybinds),
"Toggle Performance Stats Window" => Self::Menu(Menu::PerfStats),
"Toggle PPU Viewer" => Self::Menu(Menu::PpuViewer),
"Toggle Preferences Menu" => Self::Menu(Menu::Preferences),
"Toggle Replay Recording" => Self::Feature(Feature::ToggleReplayRecording),
"Toggle Audio Recording" => Self::Feature(Feature::ToggleAudioRecording),
"Visual Rewind" => Self::Feature(Feature::VisualRewind),
"Instant Rewind" => Self::Feature(Feature::InstantRewind),
"Take Screenshot" => Self::Feature(Feature::TakeScreenshot),
"Toggle Fullscreen" => Self::Setting(Setting::ToggleFullscreen),
"Toggle Embed Viewports" => Self::Setting(Setting::ToggleEmbedViewports),
"Toggle Always On Top" => Self::Setting(Setting::ToggleAlwaysOnTop),
"Toggle Audio" => Self::Setting(Setting::ToggleAudio),
"Toggle Cycle Accurate" => Self::Setting(Setting::ToggleCycleAccurate),
"Toggle Rewinding" => Self::Setting(Setting::ToggleRewinding),
"Toggle Overscan" => Self::Setting(Setting::ToggleOverscan),
"Toggle Menubar" => Self::Setting(Setting::ToggleMenubar),
"Toggle Messages" => Self::Setting(Setting::ToggleMessages),
"Toggle FPS" => Self::Setting(Setting::ToggleFps),
"Fast Forward" => Self::Setting(Setting::FastForward),
"Increment Scale" => Self::Setting(Setting::IncrementScale),
"Decrement Scale" => Self::Setting(Setting::DecrementScale),
"Increment Speed" => Self::Setting(Setting::IncrementSpeed),
"Decrement Speed" => Self::Setting(Setting::DecrementSpeed),
"Reset" => Self::Deck(DeckAction::Reset(ResetKind::Soft)),
"Power Cycle" => Self::Deck(DeckAction::Reset(ResetKind::Hard)),
"Joypad Left (P1)" => Self::Deck(DeckAction::Joypad((Player::One, JoypadBtn::Left))),
"Joypad Right (P1)" => Self::Deck(DeckAction::Joypad((Player::One, JoypadBtn::Right))),
"Joypad Up (P1)" => Self::Deck(DeckAction::Joypad((Player::One, JoypadBtn::Up))),
"Joypad Down (P1)" => Self::Deck(DeckAction::Joypad((Player::One, JoypadBtn::Down))),
"Joypad A (P1)" => Self::Deck(DeckAction::Joypad((Player::One, JoypadBtn::A))),
"Joypad B (P1)" => Self::Deck(DeckAction::Joypad((Player::One, JoypadBtn::B))),
"Joypad Turbo A (P1)" => {
Self::Deck(DeckAction::Joypad((Player::One, JoypadBtn::TurboA)))
}
"Joypad Turbo B (P1)" => {
Self::Deck(DeckAction::Joypad((Player::One, JoypadBtn::TurboB)))
}
"Joypad Select (P1)" => {
Self::Deck(DeckAction::Joypad((Player::One, JoypadBtn::Select)))
}
"Joypad Start (P1)" => Self::Deck(DeckAction::Joypad((Player::One, JoypadBtn::Start))),
"Toggle Zapper Connected" => Self::Deck(DeckAction::ToggleZapperConnected),
"Zapper Aim" => Self::Deck(DeckAction::ZapperAim((0, 0))),
"Zapper Aim Offscreen (Hold)" => Self::Deck(DeckAction::ZapperAimOffscreen),
"Zapper Trigger" => Self::Deck(DeckAction::ZapperTrigger),
"Disable Four Player Mode" => Self::Deck(DeckAction::FourPlayer(FourPlayer::Disabled)),
"Enable Four Player (FourScore)" => {
Self::Deck(DeckAction::FourPlayer(FourPlayer::FourScore))
}
"Enable Four Player (Satellite)" => {
Self::Deck(DeckAction::FourPlayer(FourPlayer::Satellite))
}
"Set Save Slot 1" => Self::Deck(DeckAction::SetSaveSlot(1)),
"Set Save Slot 2" => Self::Deck(DeckAction::SetSaveSlot(2)),
"Set Save Slot 3" => Self::Deck(DeckAction::SetSaveSlot(3)),
"Set Save Slot 4" => Self::Deck(DeckAction::SetSaveSlot(4)),
"Set Save Slot 5" => Self::Deck(DeckAction::SetSaveSlot(5)),
"Set Save Slot 6" => Self::Deck(DeckAction::SetSaveSlot(6)),
"Set Save Slot 7" => Self::Deck(DeckAction::SetSaveSlot(7)),
"Set Save Slot 8" => Self::Deck(DeckAction::SetSaveSlot(8)),
"Save State" => Self::Deck(DeckAction::SaveState),
"Load State" => Self::Deck(DeckAction::LoadState),
"Toggle Pulse1 Channel" => Self::Deck(DeckAction::ToggleApuChannel(Channel::Pulse1)),
"Toggle Pulse2 Channel" => Self::Deck(DeckAction::ToggleApuChannel(Channel::Pulse2)),
"Toggle Triangle Channel" => {
Self::Deck(DeckAction::ToggleApuChannel(Channel::Triangle))
}
"Toggle Noise Channel" => Self::Deck(DeckAction::ToggleApuChannel(Channel::Noise)),
"Toggle DMC Channel" => Self::Deck(DeckAction::ToggleApuChannel(Channel::Dmc)),
"Toggle Mapper Channel" => Self::Deck(DeckAction::ToggleApuChannel(Channel::Mapper)),
"Set Mapper Rev. to MMC3A" => Self::Deck(DeckAction::MapperRevision(
MapperRevision::Mmc3(Mmc3Revision::A),
)),
"Set Mapper Rev. to MMC3B/C" => Self::Deck(DeckAction::MapperRevision(
MapperRevision::Mmc3(Mmc3Revision::BC),
)),
"Set Mapper Rev. to MC-ACC" => Self::Deck(DeckAction::MapperRevision(
MapperRevision::Mmc3(Mmc3Revision::Acc),
)),
"Set Mapper Rev. to BF909x" => Self::Deck(DeckAction::MapperRevision(
MapperRevision::Bf909(Bf909Revision::Bf909x),
)),
"Set Mapper Rev. to BF9097" => Self::Deck(DeckAction::MapperRevision(
MapperRevision::Bf909(Bf909Revision::Bf9097),
)),
"Set Region to Auto-Detect" => Self::Deck(DeckAction::SetNesRegion(NesRegion::Auto)),
"Set Region to NTSC" => Self::Deck(DeckAction::SetNesRegion(NesRegion::Ntsc)),
"Set Region to PAL" => Self::Deck(DeckAction::SetNesRegion(NesRegion::Pal)),
"Set Region to Dendy" => Self::Deck(DeckAction::SetNesRegion(NesRegion::Dendy)),
"Set Filter to Pixellate" => {
Self::Deck(DeckAction::SetVideoFilter(VideoFilter::Pixellate))
}
"Set Filter to NTSC" => Self::Deck(DeckAction::SetVideoFilter(VideoFilter::Ntsc)),
"Toggle CPU Debugger" => Self::Debug(Debug::Toggle(Debugger::Cpu)),
"Toggle PPU Debugger" => Self::Debug(Debug::Toggle(Debugger::Ppu)),
"Toggle APU Debugger" => Self::Debug(Debug::Toggle(Debugger::Apu)),
"Step Into (CPU Debugger)" => Self::Debug(Debug::Step(DebugStep::Into)),
"Step Out (CPU Debugger)" => Self::Debug(Debug::Step(DebugStep::Out)),
"Step Over (CPU Debugger)" => Self::Debug(Debug::Step(DebugStep::Over)),
"Step Scanline (CPU Debugger)" => Self::Debug(Debug::Step(DebugStep::Scanline)),
"Step Frame (CPU Debugger)" => Self::Debug(Debug::Step(DebugStep::Frame)),
_ => return Err(anyhow::anyhow!("Invalid action string")),
})
}
}

impl From<Ui> for Action {
fn from(state: Ui) -> Self {
Self::Ui(state)
Expand Down
Loading