Skip to content

Commit 1180dee

Browse files
committed
Render background tiles row by row
1 parent fafd6cf commit 1180dee

File tree

3 files changed

+113
-71
lines changed

3 files changed

+113
-71
lines changed

3ds/source/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ bool handle_inputs(void) {
5858
if (is_key_active(KEY_SELECT, kDown, kHeld)) state |= CONTROLLER_SELECT;
5959
if (is_key_active(KEY_B, kDown, kHeld) || is_key_active(KEY_X, kDown, kHeld)) state |= CONTROLLER_B;
6060
if (is_key_active(KEY_A, kDown, kHeld) || is_key_active(KEY_Y, kDown, kHeld)) state |= CONTROLLER_A;
61-
if (is_key_active(KEY_L, kDown, kHeld) || is_key_active(KEY_R, kDown, kHeld)) return true;
61+
if (is_key_active(KEY_L, kDown, kHeld) && is_key_active(KEY_R, kDown, kHeld)) return true;
6262

6363
update_controller1(state);
6464
return false;

out/lib/ppu.c

Lines changed: 56 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,10 @@ void set_pixel(size_t x, size_t y, uint8_t palette_color) {
185185
size_t index = (y * SCREEN_WIDTH + x) * 3;
186186

187187
if (index < SCREEN_WIDTH * SCREEN_HEIGHT * 3) {
188-
uint8_t r = COLOR_PALETTE[palette_color * 3];
189-
uint8_t g = COLOR_PALETTE[palette_color * 3 + 1];
190-
uint8_t b = COLOR_PALETTE[palette_color * 3 + 2];
188+
size_t palette_offset = palette_color * 3;
189+
uint8_t r = COLOR_PALETTE[palette_offset];
190+
uint8_t g = COLOR_PALETTE[palette_offset + 1];
191+
uint8_t b = COLOR_PALETTE[palette_offset + 2];
191192

192193
frame[index] = r;
193194
frame[index + 1] = g;
@@ -199,8 +200,8 @@ size_t get_background_palette_index(size_t tile_col, size_t tile_row, size_t nam
199200
size_t attr_table_index = (tile_row / 4) * 8 + (tile_col / 4);
200201
// the attribute table is stored after the nametable (960 bytes)
201202
size_t attr_table_byte = nametable[nametable_offset + 960 + attr_table_index];
202-
size_t block_x = (tile_col % 4) / 2;
203-
size_t block_y = (tile_row % 4) / 2;
203+
size_t block_x = (tile_col & 3) / 2;
204+
size_t block_y = (tile_row & 3) / 2;
204205
size_t shift = block_y * 4 + block_x * 2;
205206

206207
return ((attr_table_byte >> shift) & 0b11) * BYTES_PER_PALETTE;
@@ -224,7 +225,7 @@ Tile* get_cached_background_tile(size_t n, size_t bank_offset, size_t palette_of
224225
uint8_t plane1 = chr_rom[bank_offset + n * 16 + tile_y];
225226
uint8_t plane2 = chr_rom[bank_offset + n * 16 + tile_y + 8];
226227

227-
for (size_t tile_x = 0; tile_x < 8; tile_x++) {
228+
for (int tile_x = 7; tile_x >= 0; tile_x--) {
228229
uint8_t bit0 = plane1 & 1;
229230
uint8_t bit1 = plane2 & 1;
230231
uint8_t color_index = (uint8_t)((bit1 << 1) | bit0);
@@ -248,7 +249,7 @@ Tile* get_cached_background_tile(size_t n, size_t bank_offset, size_t palette_of
248249
uint8_t g = COLOR_PALETTE[palette_offset + 1];
249250
uint8_t b = COLOR_PALETTE[palette_offset + 2];
250251

251-
size_t tile_offset = (tile_y * 8 + tile_x);
252+
size_t tile_offset = tile_y * 8 + (size_t)tile_x;
252253
size_t tile_offset_times_3 = tile_offset * 3;
253254

254255
tile->pixels[tile_offset_times_3] = r;
@@ -282,53 +283,73 @@ void draw_background_tile(
282283

283284
Tile *tile = get_cached_background_tile(n, bank_offset, palette_idx);
284285

286+
// copy the tile, row by row
285287
for (size_t tile_y = 0; tile_y < 8; tile_y++) {
286-
for (size_t tile_x = 0; tile_x < 8; tile_x++) {
287-
size_t tile_offset = (tile_y * 8 + tile_x);
288-
int nametable_x = (int)x + ((int)(7 - (int)tile_x));
289-
290-
if (nametable_x >= min_x && nametable_x < max_x) {
291-
size_t screen_x = (size_t)(shift_x + nametable_x);
292-
size_t screen_y = y + tile_y;
293-
294-
memcpy(&frame[(screen_y * SCREEN_WIDTH + screen_x) * 3], &tile->pixels[tile_offset * 3], 3);
295-
opaque_bg_mask[screen_y * SCREEN_WIDTH + screen_x] = tile->opaque_mask[tile_offset];
288+
int screen_x = (int)x + shift_x;
289+
size_t screen_y = y + tile_y;
290+
291+
if ((int)x >= min_x && (int)(x + 7) < max_x) {
292+
size_t tile_offset = tile_y * 8;
293+
size_t frame_offset = screen_y * SCREEN_WIDTH + (size_t)screen_x;
294+
295+
memcpy(&frame[frame_offset * 3], &tile->pixels[tile_offset * 3], 8 * 3);
296+
memcpy(&opaque_bg_mask[frame_offset], &tile->opaque_mask[tile_offset], 8);
297+
} else {
298+
// clipping
299+
for (size_t tile_x = 0; tile_x < 8; tile_x++) {
300+
size_t tile_offset = tile_y * 8 + tile_x;
301+
int nametable_x = (int)x + (int)tile_x;
302+
303+
if (nametable_x >= min_x && nametable_x < max_x) {
304+
size_t screen_x = (size_t)(shift_x + nametable_x);
305+
size_t frame_offset = screen_y * SCREEN_WIDTH + screen_x;
306+
307+
memcpy(&frame[frame_offset * 3], &tile->pixels[tile_offset * 3], 3);
308+
opaque_bg_mask[frame_offset] = tile->opaque_mask[tile_offset];
309+
}
296310
}
297311
}
298312
}
299313
}
300314

301-
bool show_status_bar() {
315+
inline bool show_status_bar() {
302316
return ram[Sprite0HitDetectFlag];
303317
}
304318

305319
void render_status_bar(size_t bank_offset) {
306-
// the status bar spans the top 4 rows
307-
for (size_t i = 0; i < 4 * TILES_PER_ROW; i++) {
308-
uint8_t tile_x = i % TILES_PER_ROW;
309-
uint8_t tile_y = (uint8_t)(i / TILES_PER_ROW);
310-
uint8_t tile = nametable[i];
311-
size_t palette_index = get_background_palette_index(tile_x, tile_y, 0);
312-
313-
draw_background_tile(tile, tile_x * 8, tile_y * 8, bank_offset, palette_index, 0, 0, SCREEN_WIDTH);
320+
for (size_t tile_y = 0; tile_y < 4; ++tile_y) {
321+
for (size_t tile_x = 0; tile_x < TILES_PER_ROW; ++tile_x) {
322+
size_t i = tile_y * TILES_PER_ROW + tile_x;
323+
324+
uint8_t tile = nametable[i];
325+
size_t palette_index = get_background_palette_index(tile_x, tile_y, 0);
326+
327+
size_t screen_x = tile_x * 8;
328+
size_t screen_y = tile_y * 8;
329+
330+
draw_background_tile(tile, screen_x, screen_y, bank_offset, palette_index, 0, 0, SCREEN_WIDTH);
331+
}
314332
}
315333
}
316334

317335
void render_nametable(size_t nametable_offset, size_t bank_offset, int shift_x, int min_x, int max_x, size_t min_tile_y) {
318336
bool draw_leftmost_tile = ppu_mask & 0b10;
319337

320-
for (size_t i = min_tile_y * TILES_PER_ROW; i < TILES_PER_ROW * TILES_PER_COLUMN; i++) {
321-
uint8_t tile_x = i % TILES_PER_ROW;
322-
uint8_t tile_y = (uint8_t)(i / TILES_PER_ROW);
338+
for (size_t tile_y = min_tile_y; tile_y < TILES_PER_COLUMN; ++tile_y) {
339+
for (size_t tile_x = 0; tile_x < TILES_PER_ROW; ++tile_x) {
340+
if (!draw_leftmost_tile && tile_x == 0) {
341+
continue;
342+
}
323343

324-
if (!draw_leftmost_tile && tile_x == 0) {
325-
continue;
326-
}
344+
size_t i = tile_y * TILES_PER_ROW + tile_x;
345+
uint8_t tile = nametable[nametable_offset + i];
346+
size_t palette_index = get_background_palette_index(tile_x, tile_y, nametable_offset);
327347

328-
uint8_t tile = nametable[nametable_offset + i];
329-
size_t palette_index = get_background_palette_index(tile_x, tile_y, nametable_offset);
348+
size_t screen_x = tile_x << 3;
349+
size_t screen_y = tile_y << 3;
330350

331-
draw_background_tile(tile, tile_x * 8, tile_y * 8, bank_offset, palette_index, shift_x, min_x, max_x);
351+
draw_background_tile(tile, screen_x, screen_y, bank_offset, palette_index, shift_x, min_x, max_x);
352+
}
332353
}
333354
}
334355

src/c/ppu.c

Lines changed: 56 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,10 @@ void set_pixel(size_t x, size_t y, uint8_t palette_color) {
185185
size_t index = (y * SCREEN_WIDTH + x) * 3;
186186

187187
if (index < SCREEN_WIDTH * SCREEN_HEIGHT * 3) {
188-
uint8_t r = COLOR_PALETTE[palette_color * 3];
189-
uint8_t g = COLOR_PALETTE[palette_color * 3 + 1];
190-
uint8_t b = COLOR_PALETTE[palette_color * 3 + 2];
188+
size_t palette_offset = palette_color * 3;
189+
uint8_t r = COLOR_PALETTE[palette_offset];
190+
uint8_t g = COLOR_PALETTE[palette_offset + 1];
191+
uint8_t b = COLOR_PALETTE[palette_offset + 2];
191192

192193
frame[index] = r;
193194
frame[index + 1] = g;
@@ -199,8 +200,8 @@ size_t get_background_palette_index(size_t tile_col, size_t tile_row, size_t nam
199200
size_t attr_table_index = (tile_row / 4) * 8 + (tile_col / 4);
200201
// the attribute table is stored after the nametable (960 bytes)
201202
size_t attr_table_byte = nametable[nametable_offset + 960 + attr_table_index];
202-
size_t block_x = (tile_col % 4) / 2;
203-
size_t block_y = (tile_row % 4) / 2;
203+
size_t block_x = (tile_col & 3) / 2;
204+
size_t block_y = (tile_row & 3) / 2;
204205
size_t shift = block_y * 4 + block_x * 2;
205206

206207
return ((attr_table_byte >> shift) & 0b11) * BYTES_PER_PALETTE;
@@ -224,7 +225,7 @@ Tile* get_cached_background_tile(size_t n, size_t bank_offset, size_t palette_of
224225
uint8_t plane1 = chr_rom[bank_offset + n * 16 + tile_y];
225226
uint8_t plane2 = chr_rom[bank_offset + n * 16 + tile_y + 8];
226227

227-
for (size_t tile_x = 0; tile_x < 8; tile_x++) {
228+
for (int tile_x = 7; tile_x >= 0; tile_x--) {
228229
uint8_t bit0 = plane1 & 1;
229230
uint8_t bit1 = plane2 & 1;
230231
uint8_t color_index = (uint8_t)((bit1 << 1) | bit0);
@@ -248,7 +249,7 @@ Tile* get_cached_background_tile(size_t n, size_t bank_offset, size_t palette_of
248249
uint8_t g = COLOR_PALETTE[palette_offset + 1];
249250
uint8_t b = COLOR_PALETTE[palette_offset + 2];
250251

251-
size_t tile_offset = (tile_y * 8 + tile_x);
252+
size_t tile_offset = tile_y * 8 + (size_t)tile_x;
252253
size_t tile_offset_times_3 = tile_offset * 3;
253254

254255
tile->pixels[tile_offset_times_3] = r;
@@ -282,53 +283,73 @@ void draw_background_tile(
282283

283284
Tile *tile = get_cached_background_tile(n, bank_offset, palette_idx);
284285

286+
// copy the tile, row by row
285287
for (size_t tile_y = 0; tile_y < 8; tile_y++) {
286-
for (size_t tile_x = 0; tile_x < 8; tile_x++) {
287-
size_t tile_offset = (tile_y * 8 + tile_x);
288-
int nametable_x = (int)x + ((int)(7 - (int)tile_x));
289-
290-
if (nametable_x >= min_x && nametable_x < max_x) {
291-
size_t screen_x = (size_t)(shift_x + nametable_x);
292-
size_t screen_y = y + tile_y;
293-
294-
memcpy(&frame[(screen_y * SCREEN_WIDTH + screen_x) * 3], &tile->pixels[tile_offset * 3], 3);
295-
opaque_bg_mask[screen_y * SCREEN_WIDTH + screen_x] = tile->opaque_mask[tile_offset];
288+
int screen_x = (int)x + shift_x;
289+
size_t screen_y = y + tile_y;
290+
291+
if ((int)x >= min_x && (int)(x + 7) < max_x) {
292+
size_t tile_offset = tile_y * 8;
293+
size_t frame_offset = screen_y * SCREEN_WIDTH + (size_t)screen_x;
294+
295+
memcpy(&frame[frame_offset * 3], &tile->pixels[tile_offset * 3], 8 * 3);
296+
memcpy(&opaque_bg_mask[frame_offset], &tile->opaque_mask[tile_offset], 8);
297+
} else {
298+
// clipping
299+
for (size_t tile_x = 0; tile_x < 8; tile_x++) {
300+
size_t tile_offset = tile_y * 8 + tile_x;
301+
int nametable_x = (int)x + (int)tile_x;
302+
303+
if (nametable_x >= min_x && nametable_x < max_x) {
304+
size_t screen_x = (size_t)(shift_x + nametable_x);
305+
size_t frame_offset = screen_y * SCREEN_WIDTH + screen_x;
306+
307+
memcpy(&frame[frame_offset * 3], &tile->pixels[tile_offset * 3], 3);
308+
opaque_bg_mask[frame_offset] = tile->opaque_mask[tile_offset];
309+
}
296310
}
297311
}
298312
}
299313
}
300314

301-
bool show_status_bar() {
315+
inline bool show_status_bar() {
302316
return ram[Sprite0HitDetectFlag];
303317
}
304318

305319
void render_status_bar(size_t bank_offset) {
306-
// the status bar spans the top 4 rows
307-
for (size_t i = 0; i < 4 * TILES_PER_ROW; i++) {
308-
uint8_t tile_x = i % TILES_PER_ROW;
309-
uint8_t tile_y = (uint8_t)(i / TILES_PER_ROW);
310-
uint8_t tile = nametable[i];
311-
size_t palette_index = get_background_palette_index(tile_x, tile_y, 0);
312-
313-
draw_background_tile(tile, tile_x * 8, tile_y * 8, bank_offset, palette_index, 0, 0, SCREEN_WIDTH);
320+
for (size_t tile_y = 0; tile_y < 4; ++tile_y) {
321+
for (size_t tile_x = 0; tile_x < TILES_PER_ROW; ++tile_x) {
322+
size_t i = tile_y * TILES_PER_ROW + tile_x;
323+
324+
uint8_t tile = nametable[i];
325+
size_t palette_index = get_background_palette_index(tile_x, tile_y, 0);
326+
327+
size_t screen_x = tile_x * 8;
328+
size_t screen_y = tile_y * 8;
329+
330+
draw_background_tile(tile, screen_x, screen_y, bank_offset, palette_index, 0, 0, SCREEN_WIDTH);
331+
}
314332
}
315333
}
316334

317335
void render_nametable(size_t nametable_offset, size_t bank_offset, int shift_x, int min_x, int max_x, size_t min_tile_y) {
318336
bool draw_leftmost_tile = ppu_mask & 0b10;
319337

320-
for (size_t i = min_tile_y * TILES_PER_ROW; i < TILES_PER_ROW * TILES_PER_COLUMN; i++) {
321-
uint8_t tile_x = i % TILES_PER_ROW;
322-
uint8_t tile_y = (uint8_t)(i / TILES_PER_ROW);
338+
for (size_t tile_y = min_tile_y; tile_y < TILES_PER_COLUMN; ++tile_y) {
339+
for (size_t tile_x = 0; tile_x < TILES_PER_ROW; ++tile_x) {
340+
if (!draw_leftmost_tile && tile_x == 0) {
341+
continue;
342+
}
323343

324-
if (!draw_leftmost_tile && tile_x == 0) {
325-
continue;
326-
}
344+
size_t i = tile_y * TILES_PER_ROW + tile_x;
345+
uint8_t tile = nametable[nametable_offset + i];
346+
size_t palette_index = get_background_palette_index(tile_x, tile_y, nametable_offset);
327347

328-
uint8_t tile = nametable[nametable_offset + i];
329-
size_t palette_index = get_background_palette_index(tile_x, tile_y, nametable_offset);
348+
size_t screen_x = tile_x << 3;
349+
size_t screen_y = tile_y << 3;
330350

331-
draw_background_tile(tile, tile_x * 8, tile_y * 8, bank_offset, palette_index, shift_x, min_x, max_x);
351+
draw_background_tile(tile, screen_x, screen_y, bank_offset, palette_index, shift_x, min_x, max_x);
352+
}
332353
}
333354
}
334355

0 commit comments

Comments
 (0)