diff options
author | Bad Diode <bd@badd10de.dev> | 2021-05-19 16:29:20 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2021-05-19 16:29:20 +0200 |
commit | 9911609e8fff312c406e3407a519b39db79bdb97 (patch) | |
tree | bbef38c5eaac06e6658ec93c2e07c571166a836d /src | |
parent | 60684bb15f5c68eb8248673da48cc4469537ffc9 (diff) | |
download | uxngba-9911609e8fff312c406e3407a519b39db79bdb97.tar.gz uxngba-9911609e8fff312c406e3407a519b39db79bdb97.zip |
Implement double buffering drawing
Diffstat (limited to 'src')
-rw-r--r-- | src/main.c | 33 | ||||
-rw-r--r-- | src/text.h | 31 | ||||
-rw-r--r-- | src/uxn/devices/ppu.c | 70 |
3 files changed, 96 insertions, 38 deletions
@@ -2,7 +2,6 @@ | |||
2 | 2 | ||
3 | #include "common.h" | 3 | #include "common.h" |
4 | #include "bitmap.h" | 4 | #include "bitmap.h" |
5 | #include "text.h" | ||
6 | // #include "small-font.c" | 5 | // #include "small-font.c" |
7 | #include "bd-font.c" | 6 | #include "bd-font.c" |
8 | 7 | ||
@@ -15,6 +14,7 @@ | |||
15 | #include "uxn/roms/dvd.c" | 14 | #include "uxn/roms/dvd.c" |
16 | // #include "uxn/roms/automata.c" | 15 | // #include "uxn/roms/automata.c" |
17 | // #include "uxn/roms/life.c" | 16 | // #include "uxn/roms/life.c" |
17 | #include "text.h" | ||
18 | 18 | ||
19 | /* | 19 | /* |
20 | Copyright (c) 2021 Bad Diode | 20 | Copyright (c) 2021 Bad Diode |
@@ -68,7 +68,7 @@ system_talk(Device *d, Uint8 b0, Uint8 w) | |||
68 | 68 | ||
69 | void | 69 | void |
70 | screen_talk(Device *d, Uint8 b0, Uint8 w) { | 70 | screen_talk(Device *d, Uint8 b0, Uint8 w) { |
71 | profile_start(); | 71 | // profile_start(); |
72 | if(w && b0 == 0xe) { | 72 | if(w && b0 == 0xe) { |
73 | Uint16 x = mempeek16(d->dat, 0x8); | 73 | Uint16 x = mempeek16(d->dat, 0x8); |
74 | Uint16 y = mempeek16(d->dat, 0xa); | 74 | Uint16 y = mempeek16(d->dat, 0xa); |
@@ -84,8 +84,8 @@ screen_talk(Device *d, Uint8 b0, Uint8 w) { | |||
84 | } | 84 | } |
85 | reqdraw = 1; | 85 | reqdraw = 1; |
86 | } | 86 | } |
87 | int cycles = profile_stop(); | 87 | // int cycles = profile_stop(); |
88 | drawing_cycles += cycles; | 88 | // drawing_cycles += cycles; |
89 | } | 89 | } |
90 | 90 | ||
91 | void | 91 | void |
@@ -122,32 +122,33 @@ int main(void) { | |||
122 | irq_init(); | 122 | irq_init(); |
123 | irs_set(IRQ_VBLANK, irs_stub); | 123 | irs_set(IRQ_VBLANK, irs_stub); |
124 | 124 | ||
125 | |||
126 | // Initialize VM. | ||
127 | Uxn u = {0}; | ||
128 | init_uxn(&u); | ||
129 | evaluxn(&u, 0x0100); | ||
130 | |||
125 | // Initialize text engine. | 131 | // Initialize text engine. |
126 | txt_init_bitmap( | 132 | txt_init_hybrid( |
127 | TXT_MODE_HYBRID, | 133 | TXT_MODE_HYBRID, |
128 | (Font){ | 134 | (Font){ |
129 | .data = bd_font, | 135 | .data = bd_font, |
130 | .char_height = 8, | 136 | .char_height = 8, |
131 | .char_width = 8, | 137 | .char_width = 8, |
132 | }); | 138 | }, &ppu.fg); |
133 | txt_position(0,0); | ||
134 | |||
135 | // Initialize VM. | ||
136 | Uxn u = {0}; | ||
137 | init_uxn(&u); | ||
138 | txt_clear_screen(); | ||
139 | evaluxn(&u, 0x0100); | ||
140 | 139 | ||
141 | // Main loop. | 140 | // Main loop. |
142 | int frame_counter = 0; | 141 | int frame_counter = 0; |
143 | while(true) { | 142 | while(true) { |
144 | bios_vblank_wait(); | 143 | bios_vblank_wait(); |
145 | poll_keys(); | 144 | poll_keys(); |
145 | profile_start(); | ||
146 | evaluxn(&u, mempeek16(devscreen->dat, 0)); | 146 | evaluxn(&u, mempeek16(devscreen->dat, 0)); |
147 | flipbuf(&ppu); | ||
148 | int eval_cycles = profile_stop(); | ||
147 | txt_position(0,0); | 149 | txt_position(0,0); |
148 | txt_clear_screen(); | 150 | txt_printf("FRAME: %d \n", frame_counter); |
149 | txt_printf("FRAME: %d\n", frame_counter); | 151 | txt_printf("EVAL: %d \n", eval_cycles); |
150 | txt_printf("DRAWING: %d\n", drawing_cycles); | ||
151 | drawing_cycles = 0; | 152 | drawing_cycles = 0; |
152 | frame_counter++; | 153 | frame_counter++; |
153 | } | 154 | } |
@@ -131,9 +131,9 @@ txt_putc_hybrid(char c) { | |||
131 | unpack_tiles(packed_char, &tile, 1); | 131 | unpack_tiles(packed_char, &tile, 1); |
132 | int x = text_engine.cursor_x; | 132 | int x = text_engine.cursor_x; |
133 | int y = text_engine.cursor_y; | 133 | int y = text_engine.cursor_y; |
134 | // DEBUG: should be on the text struct. | 134 | Tile *buf = text_engine.memory; |
135 | Tile *buf = &TILE_MEM[0]; | ||
136 | buf[x + y * 30] = tile; | 135 | buf[x + y * 30] = tile; |
136 | dirty_tiles[y][x] = 1; | ||
137 | text_engine.cursor_x += 1; | 137 | text_engine.cursor_x += 1; |
138 | if (text_engine.cursor_x >= 30) { | 138 | if (text_engine.cursor_x >= 30) { |
139 | text_engine.cursor_x = 0; | 139 | text_engine.cursor_x = 0; |
@@ -222,6 +222,33 @@ txt_init_bitmap(TextMode mode, Font font) { | |||
222 | text_engine.mode = mode; | 222 | text_engine.mode = mode; |
223 | } | 223 | } |
224 | 224 | ||
225 | void | ||
226 | txt_init_hybrid(TextMode mode, Font font, u32 *buf) { | ||
227 | // If font_map is NULL, initialize the standard 0-255 character map. | ||
228 | if (font.char_map == NULL) { | ||
229 | for (size_t i = 0; i < 256; ++i) { | ||
230 | default_char_map[i] = i; | ||
231 | } | ||
232 | font.char_map = &default_char_map; | ||
233 | } | ||
234 | |||
235 | // Initialize default values if set to zero. | ||
236 | if (font.char_width == 0) { | ||
237 | font.char_width = 8; | ||
238 | } | ||
239 | if (font.char_height == 0) { | ||
240 | font.char_height = 8; | ||
241 | } | ||
242 | if (font.color == 0) { | ||
243 | font.color = COLOR_WHITE; | ||
244 | } | ||
245 | |||
246 | // Prepare text engine. | ||
247 | text_engine.font = font; | ||
248 | text_engine.mode = mode; | ||
249 | text_engine.memory = *buf; | ||
250 | } | ||
251 | |||
225 | // Print text to the screen with formatting. | 252 | // Print text to the screen with formatting. |
226 | void | 253 | void |
227 | txt_printf(char *msg, ...) { | 254 | txt_printf(char *msg, ...) { |
diff --git a/src/uxn/devices/ppu.c b/src/uxn/devices/ppu.c index 836b7f0..d9208a5 100644 --- a/src/uxn/devices/ppu.c +++ b/src/uxn/devices/ppu.c | |||
@@ -32,6 +32,10 @@ static Uint8 font[][8] = { | |||
32 | {0x00, 0x7c, 0x82, 0x80, 0xf0, 0x80, 0x82, 0x7c}, | 32 | {0x00, 0x7c, 0x82, 0x80, 0xf0, 0x80, 0x82, 0x7c}, |
33 | {0x00, 0x7c, 0x82, 0x80, 0xf0, 0x80, 0x80, 0x80}}; | 33 | {0x00, 0x7c, 0x82, 0x80, 0xf0, 0x80, 0x80, 0x80}}; |
34 | 34 | ||
35 | u32 *backbuffer_bg0; | ||
36 | u32 *backbuffer_bg1; | ||
37 | static u8 dirty_tiles[20][30] = {0}; | ||
38 | |||
35 | void | 39 | void |
36 | putcolors(Ppu *p, Uint8 *addr) { | 40 | putcolors(Ppu *p, Uint8 *addr) { |
37 | int i; | 41 | int i; |
@@ -49,31 +53,38 @@ putcolors(Ppu *p, Uint8 *addr) { | |||
49 | 53 | ||
50 | void | 54 | void |
51 | putpixel(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 color) { | 55 | putpixel(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 color) { |
52 | if(x >= 30 * 8 || y >= 20 * 8) | ||
53 | return; | ||
54 | |||
55 | Uint32 pos = ((y & 7) + (((x >> 3) + (y >> 3) * 30) * 8)); | 56 | Uint32 pos = ((y & 7) + (((x >> 3) + (y >> 3) * 30) * 8)); |
56 | Uint32 shift = (x & 7) << 2; | 57 | Uint32 shift = (x & 7) << 2; |
57 | layer[pos] = (layer[pos] & (~(0xF << shift))) | (color << shift); | 58 | layer[pos] = (layer[pos] & (~(0xF << shift))) | (color << shift); |
59 | dirty_tiles[y >> 3][x >> 3] = 1; | ||
58 | } | 60 | } |
59 | 61 | ||
60 | void | 62 | void |
61 | puticn(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, Uint8 flipx, Uint8 flipy) { | 63 | puticn(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, |
64 | Uint8 flipx, Uint8 flipy) { | ||
62 | Uint16 v, h; | 65 | Uint16 v, h; |
63 | for(v = 0; v < 8; v++) | 66 | for(v = 0; v < 8; v++) { |
64 | for(h = 0; h < 8; h++) { | 67 | for(h = 0; h < 8; h++) { |
65 | Uint8 ch1 = ((sprite[v] >> (7 - h)) & 0x1); | 68 | Uint8 ch1 = ((sprite[v] >> (7 - h)) & 0x1); |
66 | if(ch1 == 1 || (color != 0x05 && color != 0x0a && color != 0x0f)) | 69 | // if(ch1 == 1 || (color != 0x05 && color != 0x0a && color != 0x0f)) |
67 | putpixel(p, | 70 | // putpixel(p, |
68 | layer, | 71 | // layer, |
69 | x + (flipx ? 7 - h : h), | 72 | // x + (flipx ? 7 - h : h), |
70 | y + (flipy ? 7 - v : v), | 73 | // y + (flipy ? 7 - v : v), |
71 | ch1 ? color % 4 : color / 4); | 74 | // ch1 ? color % 4 : color / 4); |
75 | // TODO: Add flip options directly to the screenblock? | ||
76 | putpixel(p, | ||
77 | layer, | ||
78 | x + h, | ||
79 | y + v, | ||
80 | ch1 ? color & 0x3 : color >> 2); | ||
72 | } | 81 | } |
82 | } | ||
73 | } | 83 | } |
74 | 84 | ||
75 | void | 85 | void |
76 | putchr(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, Uint8 flipx, Uint8 flipy) { | 86 | putchr(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, |
87 | Uint8 flipx, Uint8 flipy) { | ||
77 | Uint16 v, h; | 88 | Uint16 v, h; |
78 | for(v = 0; v < 8; v++) | 89 | for(v = 0; v < 8; v++) |
79 | for(h = 0; h < 8; h++) { | 90 | for(h = 0; h < 8; h++) { |
@@ -87,6 +98,23 @@ putchr(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, Ui | |||
87 | } | 98 | } |
88 | } | 99 | } |
89 | 100 | ||
101 | void | ||
102 | flipbuf(Ppu *p) { | ||
103 | Tile *mem_fg = &TILE_MEM[0]; | ||
104 | Tile *mem_bg = &TILE_MEM[2]; | ||
105 | for (size_t j = 0; j < 20; ++j) { | ||
106 | for (size_t i = 0; i < 30; ++i) { | ||
107 | if (dirty_tiles[j][i] != 0) { | ||
108 | Tile *tile_fg = p->fg; | ||
109 | Tile *tile_bg = p->bg; | ||
110 | mem_fg[i + j * 30] = tile_fg[i + j * 30]; | ||
111 | mem_bg[i + j * 30] = tile_bg[i + j * 30]; | ||
112 | dirty_tiles[j][i] = 0; | ||
113 | } | ||
114 | } | ||
115 | } | ||
116 | } | ||
117 | |||
90 | int | 118 | int |
91 | initppu(Ppu *p, Uint8 hor, Uint8 ver, Uint8 pad) { | 119 | initppu(Ppu *p, Uint8 hor, Uint8 ver, Uint8 pad) { |
92 | p->hor = hor; | 120 | p->hor = hor; |
@@ -100,15 +128,19 @@ initppu(Ppu *p, Uint8 hor, Uint8 ver, Uint8 pad) { | |||
100 | 128 | ||
101 | // Initialize backgrounds. | 129 | // Initialize backgrounds. |
102 | u8 cb_fg = 0; | 130 | u8 cb_fg = 0; |
103 | u8 sb_fg = 10; | ||
104 | u8 cb_bg = 2; | 131 | u8 cb_bg = 2; |
105 | u8 sb_bg = 26; | 132 | u8 sb_idx = 10; |
106 | BG_CTRL(0) = BG_CHARBLOCK(cb_fg) | BG_SCREENBLOCK(sb_fg) | BG_PRIORITY(1); | 133 | BG_CTRL(0) = BG_CHARBLOCK(cb_fg) | BG_SCREENBLOCK(sb_idx) | BG_PRIORITY(1); |
107 | BG_CTRL(1) = BG_CHARBLOCK(cb_bg) | BG_SCREENBLOCK(sb_bg) | BG_PRIORITY(2); | 134 | BG_CTRL(1) = BG_CHARBLOCK(cb_bg) | BG_SCREENBLOCK(sb_idx) | BG_PRIORITY(2); |
135 | |||
136 | backbuffer_bg0 = malloc(30 * 20 * sizeof(Tile)); | ||
137 | backbuffer_bg1 = malloc(30 * 20 * sizeof(Tile)); | ||
108 | 138 | ||
109 | // Clear tile memory. | 139 | // Clear tile memory. |
110 | p->fg = &TILE_MEM[cb_fg]; | 140 | p->fg = &TILE_MEM[cb_fg]; |
111 | p->bg = &TILE_MEM[cb_bg]; | 141 | p->bg = &TILE_MEM[cb_bg]; |
142 | p->fg = backbuffer_bg0; | ||
143 | p->bg = backbuffer_bg1; | ||
112 | for (size_t i = 0; i < 30 * 20 * 8; ++i) { | 144 | for (size_t i = 0; i < 30 * 20 * 8; ++i) { |
113 | p->fg[i] = 0; | 145 | p->fg[i] = 0; |
114 | p->bg[i] = 0; | 146 | p->bg[i] = 0; |
@@ -121,13 +153,11 @@ initppu(Ppu *p, Uint8 hor, Uint8 ver, Uint8 pad) { | |||
121 | PAL_BUFFER_BG[3] = COLOR_BLUE; | 153 | PAL_BUFFER_BG[3] = COLOR_BLUE; |
122 | 154 | ||
123 | // Initialize memory map. | 155 | // Initialize memory map. |
124 | u16 *fg_mem = SCREENBLOCK_MEM[sb_fg]; | 156 | u16 *mem_map = SCREENBLOCK_MEM[sb_idx]; |
125 | u16 *bg_mem = SCREENBLOCK_MEM[sb_bg]; | ||
126 | size_t k = 0; | 157 | size_t k = 0; |
127 | for (size_t j = 0; j < 20; ++j) { | 158 | for (size_t j = 0; j < 20; ++j) { |
128 | for (size_t i = 0; i < 30; ++i, ++k) { | 159 | for (size_t i = 0; i < 30; ++i, ++k) { |
129 | fg_mem[i + j * 32] = k; | 160 | mem_map[i + j * 32] = k; |
130 | bg_mem[i + j * 32] = k; | ||
131 | } | 161 | } |
132 | } | 162 | } |
133 | 163 | ||