From 1fabc50056826ba54ad2a613e5509f3047414cae Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Fri, 28 May 2021 21:05:49 +0200 Subject: Rename source files for flat directory structure --- src/ppu.c | 418 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 418 insertions(+) create mode 100644 src/ppu.c (limited to 'src/ppu.c') diff --git a/src/ppu.c b/src/ppu.c new file mode 100644 index 0000000..f626604 --- /dev/null +++ b/src/ppu.c @@ -0,0 +1,418 @@ +#include "ppu.h" +#include "bd-font.c" + +/* +Copyright (c) 2021 Devine Lu Linvega +Copyright (c) 2021 Andrew Alderwick +Copyright (c) 2021 Adrian "asie" Siekierka +Copyright (c) 2021 Bad Diode + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE. +*/ + +#define FG_FRONT ((u32*)(MEM_VRAM)) +#define BG_FRONT ((u32*)(MEM_VRAM + KB(20))) +#define FG_BACK ((u32*)(MEM_VRAM + KB(44))) +#define BG_BACK ((u32*)(MEM_VRAM + KB(64))) +#define TILE_MAP ((u32*)(MEM_VRAM + KB(40))) +#define FONT_DATA ((u32*)(MEM_VRAM + KB(84))) + +// Keyboard. +#define SPRITE_START_IDX 640 + +static u32 unpack_icon_lut[256] = { + 0x00000000, 0x00000001, 0x00000010, 0x00000011, 0x00000100, + 0x00000101, 0x00000110, 0x00000111, 0x00001000, 0x00001001, + 0x00001010, 0x00001011, 0x00001100, 0x00001101, 0x00001110, + 0x00001111, 0x00010000, 0x00010001, 0x00010010, 0x00010011, + 0x00010100, 0x00010101, 0x00010110, 0x00010111, 0x00011000, + 0x00011001, 0x00011010, 0x00011011, 0x00011100, 0x00011101, + 0x00011110, 0x00011111, 0x00100000, 0x00100001, 0x00100010, + 0x00100011, 0x00100100, 0x00100101, 0x00100110, 0x00100111, + 0x00101000, 0x00101001, 0x00101010, 0x00101011, 0x00101100, + 0x00101101, 0x00101110, 0x00101111, 0x00110000, 0x00110001, + 0x00110010, 0x00110011, 0x00110100, 0x00110101, 0x00110110, + 0x00110111, 0x00111000, 0x00111001, 0x00111010, 0x00111011, + 0x00111100, 0x00111101, 0x00111110, 0x00111111, 0x01000000, + 0x01000001, 0x01000010, 0x01000011, 0x01000100, 0x01000101, + 0x01000110, 0x01000111, 0x01001000, 0x01001001, 0x01001010, + 0x01001011, 0x01001100, 0x01001101, 0x01001110, 0x01001111, + 0x01010000, 0x01010001, 0x01010010, 0x01010011, 0x01010100, + 0x01010101, 0x01010110, 0x01010111, 0x01011000, 0x01011001, + 0x01011010, 0x01011011, 0x01011100, 0x01011101, 0x01011110, + 0x01011111, 0x01100000, 0x01100001, 0x01100010, 0x01100011, + 0x01100100, 0x01100101, 0x01100110, 0x01100111, 0x01101000, + 0x01101001, 0x01101010, 0x01101011, 0x01101100, 0x01101101, + 0x01101110, 0x01101111, 0x01110000, 0x01110001, 0x01110010, + 0x01110011, 0x01110100, 0x01110101, 0x01110110, 0x01110111, + 0x01111000, 0x01111001, 0x01111010, 0x01111011, 0x01111100, + 0x01111101, 0x01111110, 0x01111111, 0x10000000, 0x10000001, + 0x10000010, 0x10000011, 0x10000100, 0x10000101, 0x10000110, + 0x10000111, 0x10001000, 0x10001001, 0x10001010, 0x10001011, + 0x10001100, 0x10001101, 0x10001110, 0x10001111, 0x10010000, + 0x10010001, 0x10010010, 0x10010011, 0x10010100, 0x10010101, + 0x10010110, 0x10010111, 0x10011000, 0x10011001, 0x10011010, + 0x10011011, 0x10011100, 0x10011101, 0x10011110, 0x10011111, + 0x10100000, 0x10100001, 0x10100010, 0x10100011, 0x10100100, + 0x10100101, 0x10100110, 0x10100111, 0x10101000, 0x10101001, + 0x10101010, 0x10101011, 0x10101100, 0x10101101, 0x10101110, + 0x10101111, 0x10110000, 0x10110001, 0x10110010, 0x10110011, + 0x10110100, 0x10110101, 0x10110110, 0x10110111, 0x10111000, + 0x10111001, 0x10111010, 0x10111011, 0x10111100, 0x10111101, + 0x10111110, 0x10111111, 0x11000000, 0x11000001, 0x11000010, + 0x11000011, 0x11000100, 0x11000101, 0x11000110, 0x11000111, + 0x11001000, 0x11001001, 0x11001010, 0x11001011, 0x11001100, + 0x11001101, 0x11001110, 0x11001111, 0x11010000, 0x11010001, + 0x11010010, 0x11010011, 0x11010100, 0x11010101, 0x11010110, + 0x11010111, 0x11011000, 0x11011001, 0x11011010, 0x11011011, + 0x11011100, 0x11011101, 0x11011110, 0x11011111, 0x11100000, + 0x11100001, 0x11100010, 0x11100011, 0x11100100, 0x11100101, + 0x11100110, 0x11100111, 0x11101000, 0x11101001, 0x11101010, + 0x11101011, 0x11101100, 0x11101101, 0x11101110, 0x11101111, + 0x11110000, 0x11110001, 0x11110010, 0x11110011, 0x11110100, + 0x11110101, 0x11110110, 0x11110111, 0x11111000, 0x11111001, + 0x11111010, 0x11111011, 0x11111100, 0x11111101, 0x11111110, + 0x11111111 +}; + +static u32 unpack_icon_lut_flipx[256] = { + 0x00000000, 0x10000000, 0x01000000, 0x11000000, 0x00100000, + 0x10100000, 0x01100000, 0x11100000, 0x00010000, 0x10010000, + 0x01010000, 0x11010000, 0x00110000, 0x10110000, 0x01110000, + 0x11110000, 0x00001000, 0x10001000, 0x01001000, 0x11001000, + 0x00101000, 0x10101000, 0x01101000, 0x11101000, 0x00011000, + 0x10011000, 0x01011000, 0x11011000, 0x00111000, 0x10111000, + 0x01111000, 0x11111000, 0x00000100, 0x10000100, 0x01000100, + 0x11000100, 0x00100100, 0x10100100, 0x01100100, 0x11100100, + 0x00010100, 0x10010100, 0x01010100, 0x11010100, 0x00110100, + 0x10110100, 0x01110100, 0x11110100, 0x00001100, 0x10001100, + 0x01001100, 0x11001100, 0x00101100, 0x10101100, 0x01101100, + 0x11101100, 0x00011100, 0x10011100, 0x01011100, 0x11011100, + 0x00111100, 0x10111100, 0x01111100, 0x11111100, 0x00000010, + 0x10000010, 0x01000010, 0x11000010, 0x00100010, 0x10100010, + 0x01100010, 0x11100010, 0x00010010, 0x10010010, 0x01010010, + 0x11010010, 0x00110010, 0x10110010, 0x01110010, 0x11110010, + 0x00001010, 0x10001010, 0x01001010, 0x11001010, 0x00101010, + 0x10101010, 0x01101010, 0x11101010, 0x00011010, 0x10011010, + 0x01011010, 0x11011010, 0x00111010, 0x10111010, 0x01111010, + 0x11111010, 0x00000110, 0x10000110, 0x01000110, 0x11000110, + 0x00100110, 0x10100110, 0x01100110, 0x11100110, 0x00010110, + 0x10010110, 0x01010110, 0x11010110, 0x00110110, 0x10110110, + 0x01110110, 0x11110110, 0x00001110, 0x10001110, 0x01001110, + 0x11001110, 0x00101110, 0x10101110, 0x01101110, 0x11101110, + 0x00011110, 0x10011110, 0x01011110, 0x11011110, 0x00111110, + 0x10111110, 0x01111110, 0x11111110, 0x00000001, 0x10000001, + 0x01000001, 0x11000001, 0x00100001, 0x10100001, 0x01100001, + 0x11100001, 0x00010001, 0x10010001, 0x01010001, 0x11010001, + 0x00110001, 0x10110001, 0x01110001, 0x11110001, 0x00001001, + 0x10001001, 0x01001001, 0x11001001, 0x00101001, 0x10101001, + 0x01101001, 0x11101001, 0x00011001, 0x10011001, 0x01011001, + 0x11011001, 0x00111001, 0x10111001, 0x01111001, 0x11111001, + 0x00000101, 0x10000101, 0x01000101, 0x11000101, 0x00100101, + 0x10100101, 0x01100101, 0x11100101, 0x00010101, 0x10010101, + 0x01010101, 0x11010101, 0x00110101, 0x10110101, 0x01110101, + 0x11110101, 0x00001101, 0x10001101, 0x01001101, 0x11001101, + 0x00101101, 0x10101101, 0x01101101, 0x11101101, 0x00011101, + 0x10011101, 0x01011101, 0x11011101, 0x00111101, 0x10111101, + 0x01111101, 0x11111101, 0x00000011, 0x10000011, 0x01000011, + 0x11000011, 0x00100011, 0x10100011, 0x01100011, 0x11100011, + 0x00010011, 0x10010011, 0x01010011, 0x11010011, 0x00110011, + 0x10110011, 0x01110011, 0x11110011, 0x00001011, 0x10001011, + 0x01001011, 0x11001011, 0x00101011, 0x10101011, 0x01101011, + 0x11101011, 0x00011011, 0x10011011, 0x01011011, 0x11011011, + 0x00111011, 0x10111011, 0x01111011, 0x11111011, 0x00000111, + 0x10000111, 0x01000111, 0x11000111, 0x00100111, 0x10100111, + 0x01100111, 0x11100111, 0x00010111, 0x10010111, 0x01010111, + 0x11010111, 0x00110111, 0x10110111, 0x01110111, 0x11110111, + 0x00001111, 0x10001111, 0x01001111, 0x11001111, 0x00101111, + 0x10101111, 0x01101111, 0x11101111, 0x00011111, 0x10011111, + 0x01011111, 0x11011111, 0x00111111, 0x10111111, 0x01111111, + 0x11111111 +}; + +static u32 dirty_tiles[21] = {0}; + +void +putcolors(u8 *addr) { + int i; + for(i = 0; i < 4; ++i) { + u8 + r = (*(addr + i / 2) >> (!(i % 2) << 2)) & 0x0f, + g = (*(addr + 2 + i / 2) >> (!(i % 2) << 2)) & 0x0f, + b = (*(addr + 4 + i / 2) >> (!(i % 2) << 2)) & 0x0f; + PAL_BUFFER_BG[i] = rgb15( + (r << 1) | (r >> 3), + (g << 1) | (g >> 3), + (b << 1) | (b >> 3)); + for (size_t j = 0; j < 16; ++j) { + PAL_BUFFER_SPRITES[i * 16 + j] = rgb15( + (r << 1) | (r >> 3), + (g << 1) | (g >> 3), + (b << 1) | (b >> 3)); + } + } +} + +IWRAM_CODE +void +putpixel(u32 *layer, u16 x, u16 y, u8 color) { + if (x >= SCREEN_WIDTH || y >= SCREEN_HEIGHT) return; + size_t tile_x = x / 8; + size_t tile_y = y / 8; + size_t start_col = x % 8; + size_t start_row = y % 8; + size_t pos = (start_row + ((tile_x + tile_y * 32) * 8)); + size_t shift = start_col * 4; + layer[pos] = (layer[pos] & (~(0xF << shift))) | (color << shift); + dirty_tiles[tile_y] |= 1 << tile_x; +} + +IWRAM_CODE +void +puticn(u32 *layer, u16 x, u16 y, u8 *sprite, u8 color, u8 flipx, u8 flipy) { + u8 sprline; + u16 v; + u32 dirtyflag = (1 << (x >> 3)) | (1 << ((x + 7) >> 3)); + + u32 layerpos = ((y & 7) + (((x >> 3) + (y >> 3) * 32) * 8)); + u32 *layerptr = &layer[layerpos]; + u32 shift = (x & 7) << 2; + u32 *lut_expand = flipx ? unpack_icon_lut : unpack_icon_lut_flipx; + + if (flipy) flipy = 7; + + if (x >= SCREEN_WIDTH || y >= SCREEN_HEIGHT) return; + + if (color != 0x05 && color != 0x0a && color != 0x0f) { + u64 mask = ~((u64)0xFFFFFFFF << shift); + + for (v = 0; v < 8; v++, layerptr++) { + if ((y + v) >= SCREEN_HEIGHT) break; + + sprline = sprite[v ^ flipy]; + u64 data = (u64)(lut_expand[sprline] * (color & 3)) << shift; + data |= (u64)(lut_expand[sprline ^ 0xFF] * (color >> 2)) << shift; + + layerptr[0] = (layerptr[0] & mask) | data; + layerptr[8] = (layerptr[8] & (mask >> 32)) | (data >> 32); + + if (((y + v) & 7) == 7) layerptr += (32 - 1) * 8; + } + } else { + for (v = 0; v < 8; v++, layerptr++) { + if ((y + v) >= SCREEN_HEIGHT) break; + + sprline = sprite[v ^ flipy]; + u64 mask = ~((u64)(lut_expand[sprline] * 0xF) << shift); + u64 data = (u64)(lut_expand[sprline] * (color & 3)) << shift; + + layerptr[0] = (layerptr[0] & mask) | data; + layerptr[8] = (layerptr[8] & (mask >> 32)) | (data >> 32); + + if (((y + v) & 7) == 7) layerptr += (32 - 1) * 8; + } + } + + dirty_tiles[y >> 3] |= dirtyflag; + dirty_tiles[(y + 7) >> 3] |= dirtyflag; +} + +IWRAM_CODE +void +putfontchar(u32 *layer, u16 tile_x, u16 tile_y, u8 ch, u8 color) { + u32 pos = (tile_x + tile_y * 32) * 8; + u32 *tile_data = &layer[pos]; + u32 *font_data = &FONT_DATA[8 * ch]; + for (size_t i = 0; i < 8; ++i) { + tile_data[i] = font_data[i] * color; + } + dirty_tiles[tile_y] |= 1 << tile_x; +} + +IWRAM_CODE +void +putchr(u32 *layer, u16 x, u16 y, u8 *sprite, u8 color, + u8 flipx, u8 flipy) { + u8 sprline1, sprline2; + u16 v; + u32 dirtyflag = (1 << (x >> 3)) | (1 << ((x + 7) >> 3)); + + u32 layerpos = ((y & 7) + (((x >> 3) + (y >> 3) * 32) * 8)); + u32 *layerptr = &layer[layerpos]; + u32 shift = (x & 7) << 2; + u32 *lut_expand = flipx ? unpack_icon_lut : unpack_icon_lut_flipx; + + if (flipy) flipy = 7; + + if (x >= SCREEN_WIDTH || y >= SCREEN_HEIGHT) return; + + u64 mask = ~((u64)0xFFFFFFFF << shift); + u32 colconst = (color >> 2) * 0x11111111; + + for (v = 0; v < 8; v++, layerptr++) { + if ((y + v) >= SCREEN_HEIGHT) break; + + sprline1 = sprite[v ^ flipy]; + sprline2 = sprite[(v ^ flipy) | 8]; + + u32 data32 = + (lut_expand[sprline1] * (color & 3)) + + (lut_expand[sprline2] * ((color & 1) << 1)) + + colconst; + u64 data = ((u64) (data32 & 0x33333333)) << shift; + + layerptr[0] = (layerptr[0] & mask) | data; + layerptr[8] = (layerptr[8] & (mask >> 32)) | (data >> 32); + + if (((y + v) & 7) == 7) layerptr += (32 - 1) * 8; + } + + dirty_tiles[y >> 3] |= dirtyflag; + dirty_tiles[(y + 7) >> 3] |= dirtyflag; +} + +IWRAM_CODE +void +flipbuf(Ppu *p) { + Tile *mem_fg = FG_FRONT; + Tile *mem_bg = BG_FRONT; + for (size_t j = 0; j < 20; ++j) { + if (dirty_tiles[j] == 0) { + continue; + } + + size_t k = 1; + for (size_t i = 0; i < 30; ++i, k <<= 1) { + if (dirty_tiles[j] & k) { + Tile *tile_fg = p->fg; + Tile *tile_bg = p->bg; + mem_fg[i + j * 32] = tile_fg[i + j * 32]; + mem_bg[i + j * 32] = tile_bg[i + j * 32]; + } + } + dirty_tiles[j] = 0; + } +} + +typedef struct KeyboardChar { + int x; + int y; + u8 symbol; +} KeyboardChar; + +static u8 cursor_position = 0; + +#define KEYBOARD_ROW_SIZE 12 +#define KEYBOARD_START_TILE_X (30 / 2 - KEYBOARD_ROW_SIZE / 2) +#define KEYBOARD_START_TILE_Y (20 / 2 - 3) + +KeyboardChar keyboard[] = { + {0, 0, '!'}, {0, 0, '?'}, {0, 0, '@'}, {0, 0, '#'}, {0, 0, '$'}, {0, 0, '%'}, {0, 0, '^'}, {0, 0, '&'}, {0, 0, '*'}, {0, 0, '"'}, {0, 0, '\''}, {0, 0, 0x7f}, + {0, 0, '('}, {0, 0, ')'}, {0, 0, '['}, {0, 0, ']'}, {0, 0, '{'}, {0, 0, '}'}, {0, 0, '<'}, {0, 0, '>'}, {0, 0, '+'}, {0, 0, '-'}, {0, 0, '='}, {0, 0, 0x14}, + {0, 0, '0'}, {0, 0, '1'}, {0, 0, '2'}, {0, 0, '3'}, {0, 0, '4'}, {0, 0, '5'}, {0, 0, '6'}, {0, 0, '7'}, {0, 0, '8'}, {0, 0, '9'}, {0, 0, '~'}, {0, 0, 0x18}, + {0, 0, 'a'}, {0, 0, 'b'}, {0, 0, 'c'}, {0, 0, 'd'}, {0, 0, 'e'}, {0, 0, 'f'}, {0, 0, 'g'}, {0, 0, 'h'}, {0, 0, 'i'}, {0, 0, 'j'}, {0, 0, '/'}, {0, 0, 0x19}, + {0, 0, 'k'}, {0, 0, 'l'}, {0, 0, 'm'}, {0, 0, 'n'}, {0, 0, 'o'}, {0, 0, 'p'}, {0, 0, 'q'}, {0, 0, 'r'}, {0, 0, 's'}, {0, 0, 't'}, {0, 0, '\\'}, {0, 0, 0x1b}, + {0, 0, 'u'}, {0, 0, 'v'}, {0, 0, 'w'}, {0, 0, 'x'}, {0, 0, 'y'}, {0, 0, 'z'}, {0, 0, ','}, {0, 0, '.'}, {0, 0, ';'}, {0, 0, ':'}, {0, 0, '_'}, {0, 0, 0x1a}, +}; + +void +toggle_keyboard(void) { + for (size_t i = 0; i < LEN(keyboard); ++i) { + OBJ_ATTR_0(i) ^= OBJ_HIDDEN; + } + OBJ_ATTR_0(127) ^= OBJ_HIDDEN; +} + +void +update_cursor(u8 pos) { + cursor_position = CLAMP(pos, 0, LEN(keyboard) - 1); + OBJ_ATTR_0(127) = (OBJ_ATTR_0(127) & ~0xFF) + | OBJ_Y_COORD(keyboard[cursor_position].y); + OBJ_ATTR_1(127) = (OBJ_ATTR_0(127) & ~0x1FF) + | OBJ_X_COORD(keyboard[cursor_position].x); +} + +int +initppu(Ppu *p, u8 hor, u8 ver, u8 pad) { + p->hor = hor; + p->ver = ver; + p->pad = pad; + p->width = (8 * p->hor + p->pad * 2); + p->height = (8 * p->ver + p->pad * 2); + + // Initialize display mode and bg palette. + DISP_CTRL = DISP_MODE_0 | DISP_BG_0 | DISP_BG_1 | DISP_OBJ; + + // Initialize backgrounds. + u8 cb_fg = 0; + u8 cb_bg = 1; + u8 sb_fg = 20; + u8 sb_bg = 21; + BG_CTRL(0) = BG_CHARBLOCK(cb_fg) | BG_SCREENBLOCK(sb_fg) | BG_PRIORITY(1); + BG_CTRL(1) = BG_CHARBLOCK(cb_bg) | BG_SCREENBLOCK(sb_bg) | BG_PRIORITY(2); + + // Clear front buffer. + p->fg = FG_FRONT; + p->bg = BG_FRONT; + + // Use DMA to clear VRAM. + u32 fill = 0; + dma_fill(p->fg, fill, KB(20), 3); + dma_fill(p->bg, fill, KB(20), 3); + + // Clear back buffer. + p->fg = FG_BACK; + p->bg = BG_BACK; + dma_fill(p->fg, fill, KB(20), 3); + dma_fill(p->bg, fill, KB(20), 3); + + // Initialize default palette. + PAL_BUFFER_BG[0] = COLOR_BLACK; + PAL_BUFFER_BG[1] = COLOR_WHITE; + PAL_BUFFER_BG[2] = COLOR_RED; + PAL_BUFFER_BG[3] = COLOR_BLUE; + for (size_t i = 0; i < 16; ++i) { + PAL_BUFFER_SPRITES[i] = COLOR_BLACK; + PAL_BUFFER_SPRITES[1 * 16] = COLOR_WHITE; + PAL_BUFFER_SPRITES[2 * 16] = COLOR_RED; + PAL_BUFFER_SPRITES[3 * 16] = COLOR_BLUE; + } + + // Initialize background memory map. + u16 *mem_map_fg = SCREENBLOCK_MEM[sb_fg]; + u16 *mem_map_bg = SCREENBLOCK_MEM[sb_bg]; + size_t k = 0; + for (size_t i = 0; i < 32 * 20; ++i, ++k) { + mem_map_fg[i] = k; + mem_map_bg[i] = k + 32 * 4; + } + + // Load font data into VRAM. + unpack_tiles(&bd_font, FONT_DATA, 256); + + // Initialize keyboard sprites. + int tile_x = KEYBOARD_START_TILE_X; + int tile_y = KEYBOARD_START_TILE_Y; + for (size_t i = 0; i < sizeof(keyboard) / sizeof(keyboard[0]); ++i) { + keyboard[i].x = tile_x * 8; + keyboard[i].y = tile_y * 8; + OBJ_ATTR_0(i) = OBJ_SHAPE_SQUARE | OBJ_Y_COORD(keyboard[i].y) | OBJ_HIDDEN; + OBJ_ATTR_1(i) = OBJ_SIZE_SMALL | OBJ_X_COORD(keyboard[i].x); + OBJ_ATTR_2(i) = (SPRITE_START_IDX + keyboard[i].symbol) | OBJ_PAL_BANK(0); + tile_x++; + if (tile_x - KEYBOARD_START_TILE_X >= KEYBOARD_ROW_SIZE) { + tile_x = KEYBOARD_START_TILE_X; + tile_y++; + } + } + OBJ_ATTR_0(127) = OBJ_SHAPE_SQUARE | OBJ_Y_COORD(keyboard[cursor_position].y) | OBJ_HIDDEN; + OBJ_ATTR_1(127) = OBJ_SIZE_SMALL | OBJ_X_COORD(keyboard[cursor_position].x); + OBJ_ATTR_2(127) = (SPRITE_START_IDX + 0xdb) | OBJ_PAL_BANK(3); + + return 1; +} -- cgit v1.2.1