pce.rsannotatedpce.rssource151 lines · 4.4 KB · raw
1use crate::{DebugRenderContext, DebugRenderFn};
2use egui::{Context, Grid, Vec2, Window};
3use jgenesis_common::frontend::Color;
4use pce_core::api::PcEngineEmulator;
5
6const VRAM_TEXTURE_WIDTH: usize = 64;
7const VRAM_TEXTURE_HEIGHT: usize = 32;
8
9struct State {
10    palettes_buffer: Vec<Color>,
11    bg_palettes_texture: Option<egui::TextureId>,
12    sprite_palettes_texture: Option<egui::TextureId>,
13    vram_palette: u16,
14    vram_buffer_2d: Box<[[Color; 64]; 2048]>,
15    vram_buffer_1d: Vec<Color>,
16    vram_texture: Option<egui::TextureId>,
17}
18
19impl State {
20    fn new() -> Self {
21        Self {
22            palettes_buffer: vec![Color::default(); 512],
23            bg_palettes_texture: None,
24            sprite_palettes_texture: None,
25            vram_palette: 0,
26            vram_buffer_2d: vec![[Color::default(); 64]; 2048]
27                .into_boxed_slice()
28                .try_into()
29                .unwrap(),
30            vram_buffer_1d: vec![Color::default(); 64 * 2048],
31            vram_texture: None,
32        }
33    }
34}
35
36#[must_use]
37pub fn render_fn() -> Box<DebugRenderFn<PcEngineEmulator>> {
38    let mut state = State::new();
39    Box::new(move |ctx, emulator| render(ctx, emulator, &mut state))
40}
41
42fn render(ctx: DebugRenderContext<'_>, emulator: &mut PcEngineEmulator, state: &mut State) {
43    update_palette_textures(ctx.egui_ui, emulator, state);
44
45    Window::new("BG Palettes").resizable(true).default_width(400.0).show(ctx.egui_ui, |ui| {
46        let size = clamp_palette_image_size(ui.available_size());
47
48        if let Some(bg_palettes_texture) = state.bg_palettes_texture {
49            ui.image((bg_palettes_texture, size));
50        }
51    });
52
53    Window::new("Sprite Palettes").resizable(true).default_width(400.0).show(ctx.egui_ui, |ui| {
54        let size = clamp_palette_image_size(ui.available_size());
55
56        if let Some(sprite_palettes_texture) = state.sprite_palettes_texture {
57            ui.image((sprite_palettes_texture, size));
58        }
59    });
60
61    Window::new("VRAM").resizable(true).show(ctx.egui_ui, |ui| {
62        update_vram_texture(ui, emulator, state);
63
64        ui.spacing_mut().item_spacing = [2.0, 3.0].into();
65
66        Grid::new("pce_vram_grid").show(ui, |ui| {
67            ui.label("BG palette:");
68
69            for palette in 0..16 {
70                ui.radio_value(&mut state.vram_palette, palette, palette.to_string());
71            }
72
73            ui.end_row();
74
75            ui.label("Sprite palette:");
76
77            for palette in 0..16 {
78                ui.radio_value(&mut state.vram_palette, palette | (1 << 4), palette.to_string());
79            }
80
81            ui.end_row();
82        });
83
84        if let Some(vram_texture) = state.vram_texture {
85            let mut size = ui.available_size();
86            if size.y > size.x * 0.5 {
87                size.y = size.x * 0.5;
88            }
89            if size.x > size.y * 2.0 {
90                size.x = size.y * 2.0;
91            }
92
93            ui.image((vram_texture, size));
94        }
95    });
96}
97
98fn clamp_palette_image_size(mut size: Vec2) -> Vec2 {
99    if size.y > size.x {
100        size.y = size.x;
101    }
102
103    if size.x > size.y {
104        size.x = size.y;
105    }
106
107    size
108}
109
110fn update_palette_textures(ctx: &Context, emulator: &mut PcEngineEmulator, state: &mut State) {
111    emulator.dump_palettes(&mut state.palettes_buffer);
112
113    crate::update_egui_texture(
114        ctx,
115        [16, 16],
116        &state.palettes_buffer[..256],
117        &mut state.bg_palettes_texture,
118    );
119
120    crate::update_egui_texture(
121        ctx,
122        [16, 16],
123        &state.palettes_buffer[256..],
124        &mut state.sprite_palettes_texture,
125    );
126}
127
128fn update_vram_texture(ctx: &Context, emulator: &mut PcEngineEmulator, state: &mut State) {
129    const WIDTH: usize = VRAM_TEXTURE_WIDTH;
130
131    emulator.dump_vram(state.vram_palette, state.vram_buffer_2d.as_mut_slice());
132
133    // Copy from 2D buffer to a 1D buffer, 64x32 tiles
134    for (tile_number, tile) in state.vram_buffer_2d.iter().enumerate() {
135        let tile_base_addr = (tile_number / WIDTH) * WIDTH * 8 * 8 + (tile_number % WIDTH) * 8;
136
137        for tile_row in 0..8 {
138            for tile_col in 0..8 {
139                state.vram_buffer_1d[tile_base_addr + tile_row * WIDTH * 8 + tile_col] =
140                    tile[8 * tile_row + tile_col];
141            }
142        }
143    }
144
145    crate::update_egui_texture(
146        ctx,
147        [8 * VRAM_TEXTURE_WIDTH, 8 * VRAM_TEXTURE_HEIGHT],
148        &state.vram_buffer_1d,
149        &mut state.vram_texture,
150    );
151}