Browse Source

Add sprite 0 hit logic

v2
Nathaniel Walizer 9 months ago
parent
commit
6418936630
4 changed files with 81 additions and 8 deletions
  1. +1
    -1
      src/cart.c
  2. +15
    -4
      src/nes.c
  3. +33
    -1
      src/ppu.c
  4. +32
    -2
      src/ppu.h

+ 1
- 1
src/cart.c View File

@@ -58,7 +58,7 @@ int nes_cart_load_mem(void* data, int size, nes* sys) {
mem->ppu.bank[page] = mem->ppu.pal_bank;
}

nes_PPU_set_mirroring(
nes_ppu_set_mirroring(
&mem->ppu, hdr->flags_6 & ines_Flag_Vert_Mirror
);



+ 15
- 4
src/nes.c View File

@@ -51,13 +51,14 @@ static int nes_hsync(nes* sys) {

sys->ppu.scanline++;
if (nes_ppu_frame_end_line == sys->ppu.scanline) {
sys->ppu.scanline = 0;
sys->ppu.scanline = nes_ppu_prerender_line;
}

switch (sys->ppu.scanline) {
case nes_ppu_prerender_line:
// TODO: Reset PPU Status
// TODO: Get Sprite 0 Hit
sys->core.memory.ppu.status &= ~( ppu_Status_VBlank |
ppu_Status_Hit);
nes_ppu_find_hit_line(&sys->ppu, &sys->core.memory.ppu);
break;

case nes_ppu_postrender_line:
@@ -77,8 +78,18 @@ int nes_loop(nes* sys) {
int dot = 0;

while (0 == status) {
// TODO: Partial scanline if sprite 0 hit
int dots_remaining = nes_ppu_scanline_dots - dot;
if ( sys->ppu.hit_line == sys->ppu.scanline &&
(sys->core.memory.ppu.mask & (ppu_Mask_Sprite | ppu_Mask_Back)) &&
!(sys->core.memory.ppu.status & ppu_Status_Hit)) {
int hit_dot = ((oam_sprite*)sys->core.memory.ppu.oam)->x;
if (dot >= hit_dot) {
// printf("Line %d sprite 0 hit @ %d\n", sys->ppu.hit_line, hit_dot);
sys->core.memory.ppu.status |= ppu_Status_Hit;
} else {
dots_remaining = hit_dot - dot;
}
}
int cpu_cycles = (dots_remaining + 2) / 3;
dot += 3 * f6502_step(&sys->core, cpu_cycles);



+ 33
- 1
src/ppu.c View File

@@ -10,7 +10,7 @@ static const uint8_t mirror_schemes[][4] = {
};


void nes_PPU_set_mirroring(nes_PPU_Memory* mem,
void nes_ppu_set_mirroring(nes_PPU_Memory* mem,
nes_Nametable_Mirroring mirror) {
for (int i = 0; i < 4; ++i) {
mem->bank[nes_PPU_Nametable_Bank_Index + i] =
@@ -18,3 +18,35 @@ void nes_PPU_set_mirroring(nes_PPU_Memory* mem,
}
}

void nes_ppu_find_hit_line(nes_PPU* ppu, nes_PPU_Memory* mem) {
int sprite_bank = !!(mem->ctrl & ppu_Control_Sprite_Bank);
oam_sprite sprite = *(oam_sprite*)mem->oam;
int sprite_height = (mem->ctrl & ppu_Control_Sprite_Size) ?
16 : 8;
int stride = 1;
int y_off = 0;
if (sprite.attr & oam_Attr_Flip_Y) {
stride = -1;
y_off = sprite_height - 1;
sprite_bank = (sprite.index & 1);
sprite.index &= 0xFEU;
}

sprite_bank = (sprite_bank << 2) | (sprite.index >> 6);

const int data_off = ((sprite.index & 0x3FU) << 4) +
((y_off & 8) << 1) + (y_off & 7);
uint8_t* data = mem->bank[sprite_bank] + data_off;

ppu->hit_line = -1;

if (sprite.y + 1 <= nes_ppu_render_h && sprite.y > 0) {
for (int line = 0; line < sprite_height; ++line) {
if (data[0] | data[8]) {
ppu->hit_line = sprite.y + 1 + line + nes_ppu_visible_line;
break;
}
data += stride;
}
}
}

+ 32
- 2
src/ppu.h View File

@@ -4,6 +4,9 @@
#include <stdint.h>


#define nes_ppu_render_w (256U)
#define nes_ppu_render_h (240U)

#define nes_ppu_scanline_dots (341U)
#define nes_ppu_prerender_line (0U)
#define nes_ppu_visible_line (1U)
@@ -11,6 +14,20 @@
#define nes_ppu_vblank_line (242U)
#define nes_ppu_frame_end_line (262U)

typedef struct {
uint8_t y;
uint8_t index;
uint8_t attr;
uint8_t x;
} oam_sprite;

typedef enum {
oam_Attr_Pal_Mask = 0b00000011,
oam_Attr_Background = 0b00100000,
oam_Attr_Flip_X = 0b01000000,
oam_Attr_Flip_Y = 0b10000000,
} oam_Attribute;


typedef enum {
ppu_reg_ctrl = 0,
@@ -35,6 +52,17 @@ typedef enum {
ppu_Control_VBlank = 0b10000000,
} nes_ppu_Control;

typedef enum {
ppu_Mask_Greyscale = 0b00000001,
ppu_Mask_Left_Back = 0b00000010,
ppu_Mask_Left_Sprite = 0b00000100,
ppu_Mask_Back = 0b00001000,
ppu_Mask_Sprite = 0b00010000,
ppu_Mask_More_Red = 0b00100000,
ppu_Mask_More_Green = 0b01000000,
ppu_Mask_More_Blue = 0b10000000,
} nes_ppu_Mask;

typedef enum {
ppu_Status_Open_Bus_Mask = 0b00011111,
ppu_Status_Overflow = 0b00100000,
@@ -96,13 +124,15 @@ typedef enum {
nes_Mirror_Four,
} nes_Nametable_Mirroring;

void nes_PPU_set_mirroring(nes_PPU_Memory* mem,
void nes_ppu_set_mirroring(nes_PPU_Memory* mem,
nes_Nametable_Mirroring mirror);


typedef struct {
int scanline;
int hit_line;
} nes_PPU;

void nes_ppu_find_hit_line(nes_PPU*, nes_PPU_Memory*);


#endif // NESE_PPU_H_

Loading…
Cancel
Save