snes.rsannotatedsnes.rssource285 lines · 9.4 KB · raw
1use crate::{DebugRenderContext, DebugRenderFn, SelectableButton};
2use egui::{CentralPanel, ScrollArea, Vec2};
3use jgenesis_common::frontend::Color;
4use snes_core::api::SnesEmulator;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
7enum Tab {
8    Cgram,
9    #[default]
10    Vram,
11}
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
14enum VramMode {
15    TwoBpp,
16    #[default]
17    FourBpp,
18    EightBpp,
19    Mode7,
20}
21
22const CGRAM_BUFFER_LEN: usize = 256;
23const VRAM_BUFFER_LEN: usize = 256 * 1024;
24
25struct State {
26    tab: Tab,
27    vram_mode: VramMode,
28    vram_palette: u8,
29    cgram_texture: Option<(wgpu::Texture, egui::TextureId)>,
30    cgram_buffer: Box<[Color; CGRAM_BUFFER_LEN]>,
31    vram_2bpp_texture: Option<(wgpu::Texture, egui::TextureId)>,
32    vram_4bpp_texture: Option<(wgpu::Texture, egui::TextureId)>,
33    vram_8bpp_texture: Option<(wgpu::Texture, egui::TextureId)>,
34    vram_mode7_texture: Option<(wgpu::Texture, egui::TextureId)>,
35    vram_buffer: Box<[Color; VRAM_BUFFER_LEN]>,
36}
37
38impl State {
39    fn new() -> Self {
40        Self {
41            tab: Tab::default(),
42            vram_mode: VramMode::default(),
43            vram_palette: 0,
44            cgram_texture: None,
45            cgram_buffer: vec![Color::default(); CGRAM_BUFFER_LEN]
46                .into_boxed_slice()
47                .try_into()
48                .unwrap(),
49            vram_2bpp_texture: None,
50            vram_4bpp_texture: None,
51            vram_8bpp_texture: None,
52            vram_mode7_texture: None,
53            vram_buffer: vec![Color::default(); VRAM_BUFFER_LEN]
54                .into_boxed_slice()
55                .try_into()
56                .unwrap(),
57        }
58    }
59}
60
61#[must_use]
62pub fn render_fn() -> Box<DebugRenderFn<SnesEmulator>> {
63    let mut state = State::new();
64    Box::new(move |ctx, emulator| render(ctx, emulator, &mut state))
65}
66
67fn render(mut ctx: DebugRenderContext<'_>, emulator: &mut SnesEmulator, state: &mut State) {
68    update_cgram_texture(&mut ctx, emulator, state);
69    update_vram_texture(&mut ctx, emulator, state);
70
71    let screen_width = crate::screen_width(ctx.egui_ui);
72
73    CentralPanel::default().show_inside(ctx.egui_ui, |ui| {
74        ui.horizontal(|ui| {
75            ui.add(SelectableButton::new("VRAM", &mut state.tab, Tab::Vram));
76            ui.add(SelectableButton::new("CGRAM", &mut state.tab, Tab::Cgram));
77        });
78
79        ui.add_space(15.0);
80
81        match state.tab {
82            Tab::Cgram => {
83                ui.vertical_centered(|ui| {
84                    let egui_texture = state.cgram_texture.as_ref().unwrap().1;
85                    ui.image((egui_texture, Vec2::new(screen_width * 0.65, screen_width * 0.65)));
86                });
87            }
88            Tab::Vram => {
89                let original_vram_mode = state.vram_mode;
90
91                ui.horizontal(|ui| {
92                    ui.label("Mode:");
93                    ui.add(SelectableButton::new("2bpp", &mut state.vram_mode, VramMode::TwoBpp));
94                    ui.add(SelectableButton::new("4bpp", &mut state.vram_mode, VramMode::FourBpp));
95                    ui.add(SelectableButton::new("8bpp", &mut state.vram_mode, VramMode::EightBpp));
96                    ui.add(SelectableButton::new("Mode 7", &mut state.vram_mode, VramMode::Mode7));
97                });
98
99                ui.add_space(5.0);
100
101                ui.add_enabled_ui(
102                    matches!(state.vram_mode, VramMode::TwoBpp | VramMode::FourBpp),
103                    |ui| {
104                        ui.horizontal(|ui| {
105                            ui.label("Palette:");
106
107                            for bg_palette in 0..8 {
108                                ui.add(SelectableButton::new(
109                                    format!("BG{bg_palette}"),
110                                    &mut state.vram_palette,
111                                    bg_palette,
112                                ));
113                            }
114
115                            for obj_palette in 0..8 {
116                                ui.add_enabled(
117                                    state.vram_mode == VramMode::FourBpp,
118                                    SelectableButton::new(
119                                        format!("OBJ{obj_palette}"),
120                                        &mut state.vram_palette,
121                                        obj_palette + 8,
122                                    ),
123                                );
124                            }
125                        });
126                    },
127                );
128
129                ui.add_space(10.0);
130
131                ScrollArea::vertical().show(ui, |ui| match original_vram_mode {
132                    VramMode::TwoBpp => {
133                        let egui_texture = state.vram_2bpp_texture.as_ref().unwrap().1;
134                        ui.image((egui_texture, Vec2::new(screen_width, screen_width)));
135                    }
136                    VramMode::FourBpp => {
137                        let egui_texture = state.vram_4bpp_texture.as_ref().unwrap().1;
138                        ui.image((egui_texture, Vec2::new(screen_width, screen_width * 0.5)));
139                    }
140                    VramMode::EightBpp => {
141                        let egui_texture = state.vram_8bpp_texture.as_ref().unwrap().1;
142                        ui.image((egui_texture, Vec2::new(screen_width, screen_width)));
143                    }
144                    VramMode::Mode7 => {
145                        let egui_texture = state.vram_mode7_texture.as_ref().unwrap().1;
146                        ui.image((egui_texture, Vec2::new(screen_width, screen_width)));
147                    }
148                });
149            }
150        }
151    });
152}
153
154fn update_cgram_texture(
155    ctx: &mut DebugRenderContext<'_>,
156    emulator: &mut SnesEmulator,
157    state: &mut State,
158) {
159    emulator.copy_cgram(state.cgram_buffer.as_mut());
160
161    if state.cgram_texture.is_none() {
162        let (wgpu_texture, egui_texture) =
163            crate::create_texture("debug_snes_cgram", 16, 16, ctx.device, ctx.renderer);
164        state.cgram_texture = Some((wgpu_texture, egui_texture));
165    }
166
167    let (wgpu_texture, egui_texture) = state.cgram_texture.as_ref().unwrap();
168
169    crate::write_textures(
170        wgpu_texture,
171        *egui_texture,
172        bytemuck::cast_slice(state.cgram_buffer.as_ref()),
173        ctx,
174    );
175}
176
177fn update_vram_texture(
178    ctx: &mut DebugRenderContext<'_>,
179    emulator: &mut SnesEmulator,
180    state: &mut State,
181) {
182    match state.vram_mode {
183        VramMode::TwoBpp => update_vram_2bpp_texture(ctx, emulator, state),
184        VramMode::FourBpp => update_vram_4bpp_texture(ctx, emulator, state),
185        VramMode::EightBpp => update_vram_8bpp_texture(ctx, emulator, state),
186        VramMode::Mode7 => update_vram_mode7_texture(ctx, emulator, state),
187    }
188}
189
190fn update_vram_2bpp_texture(
191    ctx: &mut DebugRenderContext<'_>,
192    emulator: &mut SnesEmulator,
193    state: &mut State,
194) {
195    emulator.copy_vram_2bpp(state.vram_buffer.as_mut(), state.vram_palette, 64);
196
197    if state.vram_2bpp_texture.is_none() {
198        let (wgpu_texture, egui_texture) =
199            crate::create_texture("debug_snes_vram_2bpp", 64 * 8, 64 * 8, ctx.device, ctx.renderer);
200        state.vram_2bpp_texture = Some((wgpu_texture, egui_texture));
201    }
202
203    let (wgpu_texture, egui_texture) = state.vram_2bpp_texture.as_ref().unwrap();
204
205    crate::write_textures(
206        wgpu_texture,
207        *egui_texture,
208        bytemuck::cast_slice(state.vram_buffer.as_ref()),
209        ctx,
210    );
211}
212
213fn update_vram_4bpp_texture(
214    ctx: &mut DebugRenderContext<'_>,
215    emulator: &mut SnesEmulator,
216    state: &mut State,
217) {
218    emulator.copy_vram_4bpp(state.vram_buffer.as_mut(), state.vram_palette, 64);
219
220    if state.vram_4bpp_texture.is_none() {
221        let (wgpu_texture, egui_texture) =
222            crate::create_texture("debug_snes_vram_4bpp", 64 * 8, 32 * 8, ctx.device, ctx.renderer);
223        state.vram_4bpp_texture = Some((wgpu_texture, egui_texture));
224    }
225
226    let (wgpu_texture, egui_texture) = state.vram_4bpp_texture.as_ref().unwrap();
227
228    crate::write_textures(
229        wgpu_texture,
230        *egui_texture,
231        bytemuck::cast_slice(state.vram_buffer.as_ref()),
232        ctx,
233    );
234}
235
236fn update_vram_8bpp_texture(
237    ctx: &mut DebugRenderContext<'_>,
238    emulator: &mut SnesEmulator,
239    state: &mut State,
240) {
241    emulator.copy_vram_8bpp(state.vram_buffer.as_mut(), 32);
242
243    if state.vram_8bpp_texture.is_none() {
244        let (wgpu_texture, egui_texture) =
245            crate::create_texture("debug_snes_vram_8bpp", 32 * 8, 32 * 8, ctx.device, ctx.renderer);
246        state.vram_8bpp_texture = Some((wgpu_texture, egui_texture));
247    }
248
249    let (wgpu_texture, egui_texture) = state.vram_8bpp_texture.as_ref().unwrap();
250
251    crate::write_textures(
252        wgpu_texture,
253        *egui_texture,
254        bytemuck::cast_slice(state.vram_buffer.as_ref()),
255        ctx,
256    );
257}
258
259fn update_vram_mode7_texture(
260    ctx: &mut DebugRenderContext<'_>,
261    emulator: &mut SnesEmulator,
262    state: &mut State,
263) {
264    emulator.copy_vram_mode7(state.vram_buffer.as_mut(), 16);
265
266    if state.vram_mode7_texture.is_none() {
267        let (wgpu_texture, egui_texture) = crate::create_texture(
268            "debug_snes_vram_mode7",
269            16 * 8,
270            16 * 8,
271            ctx.device,
272            ctx.renderer,
273        );
274        state.vram_mode7_texture = Some((wgpu_texture, egui_texture));
275    }
276
277    let (wgpu_texture, egui_texture) = state.vram_mode7_texture.as_ref().unwrap();
278
279    crate::write_textures(
280        wgpu_texture,
281        *egui_texture,
282        bytemuck::cast_slice(state.vram_buffer.as_ref()),
283        ctx,
284    );
285}