Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid rendering both the background and window on the same line #108

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading