Skip to content

Commit

Permalink
Avoid rendering both the background and window on the same line
Browse files Browse the repository at this point in the history
  • Loading branch information
ccawley2011 committed Jun 2, 2024
1 parent e7e73ef commit c4ac57e
Showing 1 changed file with 67 additions and 61 deletions.
128 changes: 67 additions & 61 deletions peanut_gb.h
Original file line number Diff line number Diff line change
Expand Up @@ -1390,7 +1390,7 @@ static int compare_sprites(const void *in1, const void *in2)

void __gb_draw_line(struct gb_s *gb)
{
uint8_t pixels[160] = {0};
uint8_t pixels[LCD_WIDTH];

/* If LCD not initialised by front-end, don't render anything. */
if(gb->display.lcd_draw_line == NULL)
Expand Down Expand Up @@ -1418,62 +1418,51 @@ void __gb_draw_line(struct gb_s *gb)
}
}

/* If background is enabled, draw it. */
if(gb->hram_io[IO_LCDC] & LCDC_BG_ENABLE)
/* If window is enabled and active on this line, draw it. */
if(gb->hram_io[IO_LCDC] & LCDC_WINDOW_ENABLE
&& gb->hram_io[IO_LY] >= gb->display.WY
&& gb->hram_io[IO_WX] <= 166)
{
uint8_t bg_y, disp_x, bg_x, idx, py, px, t1, t2;
uint16_t bg_map, tile;

/* Calculate current background line to draw. Constant because
* this function draws only this one line each time it is
* called. */
bg_y = gb->hram_io[IO_LY] + gb->hram_io[IO_SCY];
uint16_t win_line, tile;
uint8_t disp_x, win_x, py, px, idx, t1, t2, end;

/* Get selected background map address for first tile
* corresponding to current line.
* 0x20 (32) is the width of a background tile, and the bit
* shift is to calculate the address. */
bg_map =
((gb->hram_io[IO_LCDC] & LCDC_BG_MAP) ?
VRAM_BMAP_2 : VRAM_BMAP_1)
+ (bg_y >> 3) * 0x20;
/* Calculate Window Map Address. */
win_line = (gb->hram_io[IO_LCDC] & LCDC_WINDOW_MAP) ?
VRAM_BMAP_2 : VRAM_BMAP_1;
win_line += (gb->display.window_clear >> 3) * 0x20;

/* The displays (what the player sees) X coordinate, drawn right
* to left. */
disp_x = LCD_WIDTH - 1;
win_x = disp_x - gb->hram_io[IO_WX] + 7;

/* The X coordinate to begin drawing the background at. */
bg_x = disp_x + gb->hram_io[IO_SCX];

/* Get tile index for current background tile. */
idx = gb->vram[bg_map + (bg_x >> 3)];
/* Y coordinate of tile pixel to draw. */
py = (bg_y & 0x07);
/* X coordinate of tile pixel to draw. */
px = 7 - (bg_x & 0x07);
// look up tile
py = gb->display.window_clear & 0x07;
px = 7 - (win_x & 0x07);
idx = gb->vram[win_line + (win_x >> 3)];

/* Select addressing mode. */
if(gb->hram_io[IO_LCDC] & LCDC_TILE_SELECT)
tile = VRAM_TILES_1 + idx * 0x10;
else
tile = VRAM_TILES_2 + ((idx + 0x80) % 0x100) * 0x10;

tile += 2 * py;

/* fetch first tile */
// fetch first tile
t1 = gb->vram[tile] >> px;
t2 = gb->vram[tile + 1] >> px;

for(; disp_x != 0xFF; disp_x--)
// loop & copy window
end = (gb->hram_io[IO_WX] < 7 ? 0 : gb->hram_io[IO_WX] - 7) - 1;

for(; disp_x != end; disp_x--)
{
uint8_t c;

if(px == 8)
{
/* fetch next tile */
// fetch next tile
px = 0;
bg_x = disp_x + gb->hram_io[IO_SCX];
idx = gb->vram[bg_map + (bg_x >> 3)];
win_x = disp_x - gb->hram_io[IO_WX] + 7;
idx = gb->vram[win_line + (win_x >> 3)];

if(gb->hram_io[IO_LCDC] & LCDC_TILE_SELECT)
tile = VRAM_TILES_1 + idx * 0x10;
Expand All @@ -1485,7 +1474,7 @@ void __gb_draw_line(struct gb_s *gb)
t2 = gb->vram[tile + 1];
}

/* copy background */
// copy window
c = (t1 & 0x1) | ((t2 & 0x1) << 1);
pixels[disp_x] = gb->display.bg_palette[c];
#if PEANUT_GB_12_COLOUR
Expand All @@ -1495,53 +1484,66 @@ void __gb_draw_line(struct gb_s *gb)
t2 = t2 >> 1;
px++;
}

gb->display.window_clear++; // advance window line
}

/* draw window */
if(gb->hram_io[IO_LCDC] & LCDC_WINDOW_ENABLE
&& gb->hram_io[IO_LY] >= gb->display.WY
&& gb->hram_io[IO_WX] <= 166)
/* If background is enabled but not covered by the window, draw it. */
else if(gb->hram_io[IO_LCDC] & LCDC_BG_ENABLE)
{
uint16_t win_line, tile;
uint8_t disp_x, win_x, py, px, idx, t1, t2, end;
uint8_t bg_y, disp_x, bg_x, idx, py, px, t1, t2;
uint16_t bg_map, tile;

/* Calculate Window Map Address. */
win_line = (gb->hram_io[IO_LCDC] & LCDC_WINDOW_MAP) ?
VRAM_BMAP_2 : VRAM_BMAP_1;
win_line += (gb->display.window_clear >> 3) * 0x20;
/* Calculate current background line to draw. Constant because
* this function draws only this one line each time it is
* called. */
bg_y = gb->hram_io[IO_LY] + gb->hram_io[IO_SCY];

/* Get selected background map address for first tile
* corresponding to current line.
* 0x20 (32) is the width of a background tile, and the bit
* shift is to calculate the address. */
bg_map =
((gb->hram_io[IO_LCDC] & LCDC_BG_MAP) ?
VRAM_BMAP_2 : VRAM_BMAP_1)
+ (bg_y >> 3) * 0x20;

/* The displays (what the player sees) X coordinate, drawn right
* to left. */
disp_x = LCD_WIDTH - 1;
win_x = disp_x - gb->hram_io[IO_WX] + 7;

// look up tile
py = gb->display.window_clear & 0x07;
px = 7 - (win_x & 0x07);
idx = gb->vram[win_line + (win_x >> 3)];
/* The X coordinate to begin drawing the background at. */
bg_x = disp_x + gb->hram_io[IO_SCX];

/* Get tile index for current background tile. */
idx = gb->vram[bg_map + (bg_x >> 3)];
/* Y coordinate of tile pixel to draw. */
py = (bg_y & 0x07);
/* X coordinate of tile pixel to draw. */
px = 7 - (bg_x & 0x07);

/* Select addressing mode. */
if(gb->hram_io[IO_LCDC] & LCDC_TILE_SELECT)
tile = VRAM_TILES_1 + idx * 0x10;
else
tile = VRAM_TILES_2 + ((idx + 0x80) % 0x100) * 0x10;

tile += 2 * py;

// fetch first tile
/* fetch first tile */
t1 = gb->vram[tile] >> px;
t2 = gb->vram[tile + 1] >> px;

// loop & copy window
end = (gb->hram_io[IO_WX] < 7 ? 0 : gb->hram_io[IO_WX] - 7) - 1;

for(; disp_x != end; disp_x--)
for(; disp_x != 0xFF; disp_x--)
{
uint8_t c;

if(px == 8)
{
// fetch next tile
/* fetch next tile */
px = 0;
win_x = disp_x - gb->hram_io[IO_WX] + 7;
idx = gb->vram[win_line + (win_x >> 3)];
bg_x = disp_x + gb->hram_io[IO_SCX];
idx = gb->vram[bg_map + (bg_x >> 3)];

if(gb->hram_io[IO_LCDC] & LCDC_TILE_SELECT)
tile = VRAM_TILES_1 + idx * 0x10;
Expand All @@ -1553,7 +1555,7 @@ void __gb_draw_line(struct gb_s *gb)
t2 = gb->vram[tile + 1];
}

// copy window
/* copy background */
c = (t1 & 0x1) | ((t2 & 0x1) << 1);
pixels[disp_x] = gb->display.bg_palette[c];
#if PEANUT_GB_12_COLOUR
Expand All @@ -1563,8 +1565,12 @@ void __gb_draw_line(struct gb_s *gb)
t2 = t2 >> 1;
px++;
}
}

gb->display.window_clear++; // advance window line
/* If no pixels have been written yet, clear the buffer. */
else
{
memset(pixels, 0, LCD_WIDTH);
}

// draw sprites
Expand Down

0 comments on commit c4ac57e

Please sign in to comment.