Added support for window in Genesis
This commit is contained in:
parent
8c58903f73
commit
ec461a61c0
|
@ -285,7 +285,6 @@ impl Ym7101Memory {
|
|||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum ColourMode {
|
||||
Unmasked,
|
||||
Normal,
|
||||
Shadow,
|
||||
Highlight,
|
||||
|
@ -305,11 +304,11 @@ pub struct Ym7101State {
|
|||
pub mode_2: u8,
|
||||
pub mode_3: u8,
|
||||
pub mode_4: u8,
|
||||
pub window_pos: (u8, u8),
|
||||
pub h_int_lines: u8,
|
||||
pub screen_size: (usize, usize),
|
||||
pub scroll_size: (usize, usize),
|
||||
pub window_offset: (usize, usize),
|
||||
pub window_pos: ((usize, usize), (usize, usize)),
|
||||
pub window_values: (u8, u8),
|
||||
pub background: u8,
|
||||
pub scroll_a_addr: usize,
|
||||
pub scroll_b_addr: usize,
|
||||
|
@ -333,11 +332,11 @@ impl Ym7101State {
|
|||
mode_2: 0,
|
||||
mode_3: 0,
|
||||
mode_4: 0,
|
||||
window_pos: (0, 0),
|
||||
h_int_lines: 0,
|
||||
screen_size: (0, 0),
|
||||
scroll_size: (0, 0),
|
||||
window_offset: (0, 0),
|
||||
window_pos: ((0, 0), (0, 0)),
|
||||
window_values: (0, 0),
|
||||
background: 0,
|
||||
scroll_a_addr: 0,
|
||||
scroll_b_addr: 0,
|
||||
|
@ -352,26 +351,6 @@ impl Ym7101State {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn update_screen_size(&mut self) {
|
||||
let h_cells = if (self.mode_4 & MODE4_BF_H_CELL_MODE) == 0 { 32 } else { 40 };
|
||||
let v_cells = if (self.mode_2 & MODE2_BF_V_CELL_MODE) == 0 { 28 } else { 30 };
|
||||
self.screen_size = (h_cells, v_cells);
|
||||
}
|
||||
|
||||
pub fn update_window_offset(&mut self) {
|
||||
let win_h = ((self.window_pos.0 & 0x1F) << 1) as usize;
|
||||
let win_v = (self.window_pos.1 & 0x1F) as usize;
|
||||
let right = (self.window_pos.0 & 0x80) != 0;
|
||||
let down = (self.window_pos.1 & 0x80) != 0;
|
||||
|
||||
self.window_offset = match (right, down) {
|
||||
(false, false) => (win_h, win_v),
|
||||
(true, false) => (win_h - self.screen_size.0, win_v),
|
||||
(false, true) => (win_h, win_v - self.screen_size.1),
|
||||
(true, true) => (win_h - self.screen_size.0, win_v - self.screen_size.1),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn hsync_int_enabled(&self) -> bool {
|
||||
(self.mode_1 & MODE1_BF_HSYNC_INTERRUPT) != 0
|
||||
|
@ -387,10 +366,32 @@ impl Ym7101State {
|
|||
(self.mode_3 & MODE3_BF_EXTERNAL_INTERRUPT) != 0
|
||||
}
|
||||
|
||||
pub fn get_palette_colour(&self, palette: u8, colour: u8, mode: ColourMode) -> u32 {
|
||||
if colour == 0 && mode != ColourMode::Unmasked {
|
||||
return MASK_COLOUR;
|
||||
pub fn update_screen_size(&mut self) {
|
||||
let h_cells = if (self.mode_4 & MODE4_BF_H_CELL_MODE) == 0 { 32 } else { 40 };
|
||||
let v_cells = if (self.mode_2 & MODE2_BF_V_CELL_MODE) == 0 { 28 } else { 30 };
|
||||
self.screen_size = (h_cells, v_cells);
|
||||
}
|
||||
|
||||
pub fn update_window_position(&mut self) {
|
||||
let win_h = ((self.window_values.0 & 0x1F) << 1) as usize;
|
||||
let win_v = (self.window_values.1 & 0x1F) as usize;
|
||||
let right = (self.window_values.0 & 0x80) != 0;
|
||||
let down = (self.window_values.1 & 0x80) != 0;
|
||||
|
||||
self.window_pos = match (right, down) {
|
||||
(false, false) => ((0, 0), (win_h, win_v)),
|
||||
(true, false) => ((win_h, 0), (self.screen_size.0, win_v)),
|
||||
(false, true) => ((0, win_v), (win_h, self.screen_size.1)),
|
||||
(true, true) => ((win_h, win_v), (self.screen_size.0, self.screen_size.1)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_inside_window(&mut self, x: usize, y: usize) -> bool {
|
||||
x >= self.window_pos.0.0 && x <= self.window_pos.1.0 && y >= self.window_pos.0.1 && y <= self.window_pos.1.1
|
||||
}
|
||||
|
||||
|
||||
pub fn get_palette_colour(&self, palette: u8, colour: u8, mode: ColourMode) -> u32 {
|
||||
let shift_enabled = (self.mode_4 & MODE4_BF_SHADOW_HIGHLIGHT) != 0;
|
||||
let rgb = self.memory.read_beu16(Memory::Cram, (((palette * 16) + colour) * 2) as usize);
|
||||
if !shift_enabled || mode == ColourMode::Normal {
|
||||
|
@ -461,26 +462,25 @@ impl Ym7101State {
|
|||
(sprites, lines)
|
||||
}
|
||||
|
||||
pub fn get_pattern_pixel(&self, pattern_word: u16, x: usize, y: usize) -> u32 {
|
||||
pub fn get_pattern_pixel(&self, pattern_word: u16, x: usize, y: usize) -> (u8, u8) {
|
||||
let pattern_addr = (pattern_word & 0x07FF) << 5;
|
||||
let palette = ((pattern_word & 0x6000) >> 13) as u8;
|
||||
let h_rev = (pattern_word & 0x0800) != 0;
|
||||
let v_rev = (pattern_word & 0x1000) != 0;
|
||||
let mode = if (pattern_word & 0x8000) != 0 { ColourMode::Shadow } else { ColourMode::Normal };
|
||||
|
||||
let offset = pattern_addr as usize + (if !v_rev { y } else { 7 - y }) as usize * 4 + (if !h_rev { x / 2 } else { 3 - (x / 2) }) as usize;
|
||||
let second = x % 2 == 1;
|
||||
let value = if (!h_rev && !second) || (h_rev && second) {
|
||||
self.get_palette_colour(palette, self.memory.vram[offset] >> 4, mode)
|
||||
(palette, self.memory.vram[offset] >> 4)
|
||||
} else {
|
||||
self.get_palette_colour(palette, self.memory.vram[offset] & 0x0f, mode)
|
||||
(palette, self.memory.vram[offset] & 0x0f)
|
||||
};
|
||||
|
||||
value
|
||||
}
|
||||
|
||||
pub fn draw_frame(&mut self, frame: &mut Frame) {
|
||||
let bg_colour = self.get_palette_colour((self.background & 0x30) >> 4, self.background & 0x0f, ColourMode::Unmasked);
|
||||
let bg_colour = ((self.background & 0x30) >> 4, self.background & 0x0f);
|
||||
let (sprites, sprites_per_line) = self.build_sprites_lists();
|
||||
|
||||
for y in 0..(self.screen_size.1 * 8) {
|
||||
|
@ -503,7 +503,18 @@ impl Ym7101State {
|
|||
let priority_b = (pattern_b_word & 0x8000) != 0;
|
||||
let pixel_b = self.get_pattern_pixel(pattern_b_word, pixel_b_x % 8, pixel_b_y % 8);
|
||||
|
||||
let mut pixel_sprite = MASK_COLOUR;
|
||||
let pixel_win = if self.window_addr != 0 && self.is_inside_window(x, y) {
|
||||
let pixel_win_x = x - self.window_pos.0.0 * 8;
|
||||
let pixel_win_y = y - self.window_pos.0.1 * 8;
|
||||
let pattern_win_addr = self.get_pattern_addr(self.window_addr, pixel_win_x / 8, pixel_win_y / 8);
|
||||
let pattern_win_word = self.memory.read_beu16(Memory::Vram, pattern_win_addr);
|
||||
//let priority_win = (pattern_win_word & 0x8000) != 0;
|
||||
self.get_pattern_pixel(pattern_win_word, pixel_win_x % 8, pixel_win_y % 8)
|
||||
} else {
|
||||
(0, 0)
|
||||
};
|
||||
|
||||
let mut pixel_sprite = (0, 0);
|
||||
let mut priority_sprite = false;
|
||||
for sprite_num in sprites_per_line[y].iter() {
|
||||
let offset_x = x as i16 - sprites[*sprite_num].pos.0;
|
||||
|
@ -514,7 +525,7 @@ impl Ym7101State {
|
|||
priority_sprite = (pattern & 0x8000) != 0;
|
||||
|
||||
pixel_sprite = self.get_pattern_pixel(pattern, offset_x as usize % 8, offset_y as usize % 8);
|
||||
if pixel_sprite != MASK_COLOUR {
|
||||
if pixel_sprite.1 != 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -522,20 +533,28 @@ impl Ym7101State {
|
|||
|
||||
let pixels = match (priority_sprite, priority_a, priority_b) {
|
||||
(false, false, true) =>
|
||||
[ pixel_b, pixel_sprite, pixel_a, bg_colour, 0x000000 ],
|
||||
[ pixel_win, pixel_b, pixel_sprite, pixel_a, bg_colour ],
|
||||
(true, false, true) =>
|
||||
[ pixel_sprite, pixel_b, pixel_a, bg_colour, 0x000000 ],
|
||||
[ pixel_win, pixel_sprite, pixel_b, pixel_a, bg_colour ],
|
||||
(false, true, false) =>
|
||||
[ pixel_a, pixel_sprite, pixel_b, bg_colour, 0x000000 ],
|
||||
[ pixel_win, pixel_a, pixel_sprite, pixel_b, bg_colour ],
|
||||
(false, true, true) =>
|
||||
[ pixel_a, pixel_b, pixel_sprite, bg_colour, 0x000000 ],
|
||||
[ pixel_win, pixel_a, pixel_b, pixel_sprite, bg_colour ],
|
||||
_ =>
|
||||
[ pixel_sprite, pixel_a, pixel_b, bg_colour, 0x000000 ],
|
||||
[ pixel_win, pixel_sprite, pixel_a, pixel_b, bg_colour ],
|
||||
};
|
||||
|
||||
for pixel in pixels {
|
||||
if pixel != MASK_COLOUR {
|
||||
frame.set_pixel(x as u32, y as u32, pixel);
|
||||
for i in 0..pixels.len() {
|
||||
if pixels[i].1 != 0 || i == pixels.len() - 1 {
|
||||
let mode = if pixels[i] == (3, 14) {
|
||||
ColourMode::Highlight
|
||||
} else if (!priority_a && !priority_b) || pixels[i] == (3, 15) {
|
||||
ColourMode::Shadow
|
||||
} else {
|
||||
ColourMode::Normal
|
||||
};
|
||||
|
||||
frame.set_pixel(x as u32, y as u32, self.get_palette_colour(pixels[i].0, pixels[i].1, mode));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -859,12 +878,12 @@ impl Ym7101 {
|
|||
self.state.scroll_size = (h, v);
|
||||
},
|
||||
REG_WINDOW_H_POS => {
|
||||
self.state.window_pos.0 = data;
|
||||
self.state.update_window_offset();
|
||||
self.state.window_values.0 = data;
|
||||
self.state.update_window_position();
|
||||
},
|
||||
REG_WINDOW_V_POS => {
|
||||
self.state.window_pos.1 = data;
|
||||
self.state.update_window_offset();
|
||||
self.state.window_values.1 = data;
|
||||
self.state.update_window_position();
|
||||
},
|
||||
REG_DMA_COUNTER_LOW => {
|
||||
self.state.memory.transfer_count = (self.state.memory.transfer_count & 0xFF00) | data as u32;
|
||||
|
|
10
todo.txt
10
todo.txt
|
@ -2,14 +2,6 @@
|
|||
* I need some better function for dealing with memory, like a function that copies data with a loop, or allows offset reading of
|
||||
a fixed piece of data..., the trick is what function are the most common. You can use generics
|
||||
|
||||
* should you modify the drawing to always draw line by line and combine all layers at once. It's more complicated and would be
|
||||
slower because some things would need to be calculated multiple times, but it'd be more accurate
|
||||
|
||||
* you need to refactor the ym7101 stuff
|
||||
* can you make vram/cram/vsram be Addressables that can be accessed the same way? Would this add too much overhead?
|
||||
* you can directly use a MemoryBlock, and separate out the dma
|
||||
* it's not working so well because of the &mut needed by .read()
|
||||
|
||||
* there is an issue with Mortal Kombat 2 where it will crash randomly at the start of a fight. The code is actually swapping
|
||||
stacks a bunch of times, and at some point, the stack is corrupted or something and it `rts`s to the wrong address...
|
||||
|
||||
|
@ -66,8 +58,6 @@ Debugger:
|
|||
Genesis/Mega Drive:
|
||||
|
||||
* there's a bug when Sonic 2 goes to the demo screen, it's all corrupted (could it be a dma copy error)
|
||||
* the line hscroll mode needs to draw an extra cell in order to cover up the foreground on the left and bottom edges of the screen
|
||||
* some games seem to be missing a row of cells at the top (Ghostbuster's dialog borders seem cut off)
|
||||
* fix sprite/cell priorities so that they're drawn correctly
|
||||
* implement highlight and shadow mode, which is also related to the priority
|
||||
* in some games the controller doesn't seem to work at all (Earthworm Jim, and Mortal Kombat)
|
||||
|
|
Loading…
Reference in New Issue