1 #include "gb.h"
2 #include "random.h"
3 #include <math.h>
4 #include <assert.h>
5
6 #ifndef M_PI
7 #define M_PI 3.14159265358979323846
8 #endif
9
10 enum {
11 PAL01 = 0x00,
12 PAL23 = 0x01,
13 PAL03 = 0x02,
14 PAL12 = 0x03,
15 ATTR_BLK = 0x04,
16 ATTR_LIN = 0x05,
17 ATTR_DIV = 0x06,
18 ATTR_CHR = 0x07,
19 PAL_SET = 0x0A,
20 PAL_TRN = 0x0B,
21 DATA_SND = 0x0F,
22 MLT_REQ = 0x11,
23 CHR_TRN = 0x13,
24 PCT_TRN = 0x14,
25 ATTR_TRN = 0x15,
26 ATTR_SET = 0x16,
27 MASK_EN = 0x17,
28 };
29
30 typedef enum {
31 MASK_DISABLED,
32 MASK_FREEZE,
33 MASK_BLACK,
34 MASK_COLOR_0,
35 } mask_mode_t;
36
37 typedef enum {
38 TRANSFER_LOW_TILES,
39 TRANSFER_HIGH_TILES,
40 TRANSFER_BORDER_DATA,
41 TRANSFER_PALETTES,
42 TRANSFER_ATTRIBUTES,
43 } transfer_dest_t;
44
45 #define SGB_PACKET_SIZE 16
pal_command(GB_gameboy_t * gb,unsigned first,unsigned second)46 static inline void pal_command(GB_gameboy_t *gb, unsigned first, unsigned second)
47 {
48 gb->sgb->effective_palettes[0] = gb->sgb->effective_palettes[4] =
49 gb->sgb->effective_palettes[8] = gb->sgb->effective_palettes[12] =
50 *(uint16_t *)&gb->sgb->command[1];
51
52 for (unsigned i = 0; i < 3; i++) {
53 gb->sgb->effective_palettes[first * 4 + i + 1] = *(uint16_t *)&gb->sgb->command[3 + i * 2];
54 }
55
56 for (unsigned i = 0; i < 3; i++) {
57 gb->sgb->effective_palettes[second * 4 + i + 1] = *(uint16_t *)&gb->sgb->command[9 + i * 2];
58 }
59 }
60
load_attribute_file(GB_gameboy_t * gb,unsigned file_index)61 static inline void load_attribute_file(GB_gameboy_t *gb, unsigned file_index)
62 {
63 if (file_index > 0x2C) return;
64 uint8_t *output = gb->sgb->attribute_map;
65 for (unsigned i = 0; i < 90; i++) {
66 uint8_t byte = gb->sgb->attribute_files[file_index * 90 + i];
67 for (unsigned j = 4; j--;) {
68 *(output++) = byte >> 6;
69 byte <<= 2;
70 }
71 }
72 }
73
74 static const uint16_t built_in_palettes[] =
75 {
76 0x67BF, 0x265B, 0x10B5, 0x2866,
77 0x637B, 0x3AD9, 0x0956, 0x0000,
78 0x7F1F, 0x2A7D, 0x30F3, 0x4CE7,
79 0x57FF, 0x2618, 0x001F, 0x006A,
80 0x5B7F, 0x3F0F, 0x222D, 0x10EB,
81 0x7FBB, 0x2A3C, 0x0015, 0x0900,
82 0x2800, 0x7680, 0x01EF, 0x2FFF,
83 0x73BF, 0x46FF, 0x0110, 0x0066,
84 0x533E, 0x2638, 0x01E5, 0x0000,
85 0x7FFF, 0x2BBF, 0x00DF, 0x2C0A,
86 0x7F1F, 0x463D, 0x74CF, 0x4CA5,
87 0x53FF, 0x03E0, 0x00DF, 0x2800,
88 0x433F, 0x72D2, 0x3045, 0x0822,
89 0x7FFA, 0x2A5F, 0x0014, 0x0003,
90 0x1EED, 0x215C, 0x42FC, 0x0060,
91 0x7FFF, 0x5EF7, 0x39CE, 0x0000,
92 0x4F5F, 0x630E, 0x159F, 0x3126,
93 0x637B, 0x121C, 0x0140, 0x0840,
94 0x66BC, 0x3FFF, 0x7EE0, 0x2C84,
95 0x5FFE, 0x3EBC, 0x0321, 0x0000,
96 0x63FF, 0x36DC, 0x11F6, 0x392A,
97 0x65EF, 0x7DBF, 0x035F, 0x2108,
98 0x2B6C, 0x7FFF, 0x1CD9, 0x0007,
99 0x53FC, 0x1F2F, 0x0E29, 0x0061,
100 0x36BE, 0x7EAF, 0x681A, 0x3C00,
101 0x7BBE, 0x329D, 0x1DE8, 0x0423,
102 0x739F, 0x6A9B, 0x7293, 0x0001,
103 0x5FFF, 0x6732, 0x3DA9, 0x2481,
104 0x577F, 0x3EBC, 0x456F, 0x1880,
105 0x6B57, 0x6E1B, 0x5010, 0x0007,
106 0x0F96, 0x2C97, 0x0045, 0x3200,
107 0x67FF, 0x2F17, 0x2230, 0x1548,
108 };
109
110 static const struct {
111 char name[16];
112 unsigned palette_index;
113 } palette_assignments[] =
114 {
115 {"ZELDA", 5},
116 {"SUPER MARIOLAND", 6},
117 {"MARIOLAND2", 0x14},
118 {"SUPERMARIOLAND3", 2},
119 {"KIRBY DREAM LAND", 0xB},
120 {"HOSHINOKA-BI", 0xB},
121 {"KIRBY'S PINBALL", 3},
122 {"YOSSY NO TAMAGO", 0xC},
123 {"MARIO & YOSHI", 0xC},
124 {"YOSSY NO COOKIE", 4},
125 {"YOSHI'S COOKIE", 4},
126 {"DR.MARIO", 0x12},
127 {"TETRIS", 0x11},
128 {"YAKUMAN", 0x13},
129 {"METROID2", 0x1F},
130 {"KAERUNOTAMENI", 9},
131 {"GOLF", 0x18},
132 {"ALLEY WAY", 0x16},
133 {"BASEBALL", 0xF},
134 {"TENNIS", 0x17},
135 {"F1RACE", 0x1E},
136 {"KID ICARUS", 0xE},
137 {"QIX", 0x19},
138 {"SOLARSTRIKER", 7},
139 {"X", 0x1C},
140 {"GBWARS", 0x15},
141 };
142
command_ready(GB_gameboy_t * gb)143 static void command_ready(GB_gameboy_t *gb)
144 {
145 /* SGB header commands are used to send the contents of the header to the SNES CPU.
146 A header command looks like this:
147 Command ID: 0b1111xxx1, where xxx is the packet index. (e.g. F1 for [0x104, 0x112), F3 for [0x112, 0x120))
148 Checksum: Simple one byte sum for the following content bytes
149 0xE content bytes. The last command, FB, is padded with zeros, so information past the header is not sent. */
150
151 if ((gb->sgb->command[0] & 0xF1) == 0xF1) {
152 if (gb->boot_rom_finished) return;
153
154 uint8_t checksum = 0;
155 for (unsigned i = 2; i < 0x10; i++) {
156 checksum += gb->sgb->command[i];
157 }
158 if (checksum != gb->sgb->command[1]) {
159 GB_log(gb, "Failed checksum for SGB header command, disabling SGB features\n");
160 gb->sgb->disable_commands = true;
161 return;
162 }
163 unsigned index = (gb->sgb->command[0] >> 1) & 7;
164 if (index > 5) {
165 return;
166 }
167 memcpy(&gb->sgb->received_header[index * 14], &gb->sgb->command[2], 14);
168 if (gb->sgb->command[0] == 0xfb) {
169 if (gb->sgb->received_header[0x42] != 3 || gb->sgb->received_header[0x47] != 0x33) {
170 gb->sgb->disable_commands = true;
171 for (unsigned i = 0; i < sizeof(palette_assignments) / sizeof(palette_assignments[0]); i++) {
172 if (memcmp(palette_assignments[i].name, &gb->sgb->received_header[0x30], sizeof(palette_assignments[i].name)) == 0) {
173 gb->sgb->effective_palettes[0] = LE16(built_in_palettes[palette_assignments[i].palette_index * 4 - 4]);
174 gb->sgb->effective_palettes[1] = LE16(built_in_palettes[palette_assignments[i].palette_index * 4 + 1 - 4]);
175 gb->sgb->effective_palettes[2] = LE16(built_in_palettes[palette_assignments[i].palette_index * 4 + 2 - 4]);
176 gb->sgb->effective_palettes[3] = LE16(built_in_palettes[palette_assignments[i].palette_index * 4 + 3 - 4]);
177 break;
178 }
179 }
180 }
181 }
182 return;
183 }
184
185 /* Ignore malformed commands (0 length)*/
186 if ((gb->sgb->command[0] & 7) == 0) return;
187
188 switch (gb->sgb->command[0] >> 3) {
189 case PAL01:
190 pal_command(gb, 0, 1);
191 break;
192 case PAL23:
193 pal_command(gb, 2, 3);
194 break;
195 case PAL03:
196 pal_command(gb, 0, 3);
197 break;
198 case PAL12:
199 pal_command(gb, 1, 2);
200 break;
201 case ATTR_BLK: {
202 struct {
203 uint8_t count;
204 struct {
205 uint8_t control;
206 uint8_t palettes;
207 uint8_t left, top, right, bottom;
208 } data[];
209 } *command = (void *)(gb->sgb->command + 1);
210 if (command->count > 0x12) return;
211
212 for (unsigned i = 0; i < command->count; i++) {
213 bool inside = command->data[i].control & 1;
214 bool middle = command->data[i].control & 2;
215 bool outside = command->data[i].control & 4;
216 uint8_t inside_palette = command->data[i].palettes & 0x3;
217 uint8_t middle_palette = (command->data[i].palettes >> 2) & 0x3;
218 uint8_t outside_palette = (command->data[i].palettes >> 4) & 0x3;
219
220 if (inside && !middle && !outside) {
221 middle = true;
222 middle_palette = inside_palette;
223 }
224 else if (outside && !middle && !inside) {
225 middle = true;
226 middle_palette = outside_palette;
227 }
228
229 command->data[i].left &= 0x1F;
230 command->data[i].top &= 0x1F;
231 command->data[i].right &= 0x1F;
232 command->data[i].bottom &= 0x1F;
233
234 for (unsigned y = 0; y < 18; y++) {
235 for (unsigned x = 0; x < 20; x++) {
236 if (x < command->data[i].left || x > command->data[i].right ||
237 y < command->data[i].top || y > command->data[i].bottom) {
238 if (outside) {
239 gb->sgb->attribute_map[x + 20 * y] = outside_palette;
240 }
241 }
242 else if (x > command->data[i].left && x < command->data[i].right &&
243 y > command->data[i].top && y < command->data[i].bottom) {
244 if (inside) {
245 gb->sgb->attribute_map[x + 20 * y] = inside_palette;
246 }
247 }
248 else if (middle) {
249 gb->sgb->attribute_map[x + 20 * y] = middle_palette;
250 }
251 }
252 }
253 }
254 break;
255 }
256 case ATTR_CHR: {
257 struct __attribute__((packed)) {
258 uint8_t x, y;
259 uint16_t length;
260 uint8_t direction;
261 uint8_t data[];
262 } *command = (void *)(gb->sgb->command + 1);
263
264 uint16_t count = command->length;
265 #ifdef GB_BIG_ENDIAN
266 count = __builtin_bswap16(count);
267 #endif
268 uint8_t x = command->x;
269 uint8_t y = command->y;
270 if (x >= 20 || y >= 18) {
271 /* TODO: Verify with the SFC BIOS */
272 break;
273 }
274
275 for (unsigned i = 0; i < count; i++) {
276 uint8_t palette = (command->data[i / 4] >> (((~i) & 3) << 1)) & 3;
277 gb->sgb->attribute_map[x + 20 * y] = palette;
278 if (command->direction) {
279 y++;
280 if (y == 18) {
281 x++;
282 y = 0;
283 if (x == 20) {
284 break;
285 }
286 }
287 }
288 else {
289 x++;
290 if (x == 20) {
291 y++;
292 x = 0;
293 if (y == 18) {
294 break;
295 }
296 }
297 }
298 }
299
300 break;
301 }
302 case ATTR_LIN: {
303 struct {
304 uint8_t count;
305 uint8_t data[];
306 } *command = (void *)(gb->sgb->command + 1);
307 if (command->count > sizeof(gb->sgb->command) - 2) return;
308
309 for (unsigned i = 0; i < command->count; i++) {
310 bool horizontal = command->data[i] & 0x80;
311 uint8_t palette = (command->data[i] >> 5) & 0x3;
312 uint8_t line = (command->data[i]) & 0x1F;
313
314 if (horizontal) {
315 if (line > 18) continue;
316 for (unsigned x = 0; x < 20; x++) {
317 gb->sgb->attribute_map[x + 20 * line] = palette;
318 }
319 }
320 else {
321 if (line > 20) continue;
322 for (unsigned y = 0; y < 18; y++) {
323 gb->sgb->attribute_map[line + 20 * y] = palette;
324 }
325 }
326 }
327 break;
328 }
329 case ATTR_DIV: {
330 uint8_t high_palette = gb->sgb->command[1] & 3;
331 uint8_t low_palette = (gb->sgb->command[1] >> 2) & 3;
332 uint8_t middle_palette = (gb->sgb->command[1] >> 4) & 3;
333 bool horizontal = gb->sgb->command[1] & 0x40;
334 uint8_t line = gb->sgb->command[2] & 0x1F;
335
336 for (unsigned y = 0; y < 18; y++) {
337 for (unsigned x = 0; x < 20; x++) {
338 if ((horizontal? y : x) < line) {
339 gb->sgb->attribute_map[x + 20 * y] = low_palette;
340 }
341 else if ((horizontal? y : x) == line) {
342 gb->sgb->attribute_map[x + 20 * y] = middle_palette;
343 }
344 else {
345 gb->sgb->attribute_map[x + 20 * y] = high_palette;
346 }
347 }
348 }
349
350 break;
351 }
352 case PAL_SET:
353 memcpy(&gb->sgb->effective_palettes[0],
354 &gb->sgb->ram_palettes[4 * (gb->sgb->command[1] + (gb->sgb->command[2] & 1) * 0x100)],
355 8);
356 memcpy(&gb->sgb->effective_palettes[4],
357 &gb->sgb->ram_palettes[4 * (gb->sgb->command[3] + (gb->sgb->command[4] & 1) * 0x100)],
358 8);
359 memcpy(&gb->sgb->effective_palettes[8],
360 &gb->sgb->ram_palettes[4 * (gb->sgb->command[5] + (gb->sgb->command[6] & 1) * 0x100)],
361 8);
362 memcpy(&gb->sgb->effective_palettes[12],
363 &gb->sgb->ram_palettes[4 * (gb->sgb->command[7] + (gb->sgb->command[8] & 1) * 0x100)],
364 8);
365
366 gb->sgb->effective_palettes[12] = gb->sgb->effective_palettes[8] =
367 gb->sgb->effective_palettes[4] = gb->sgb->effective_palettes[0];
368
369 if (gb->sgb->command[9] & 0x80) {
370 load_attribute_file(gb, gb->sgb->command[9] & 0x3F);
371 }
372
373 if (gb->sgb->command[9] & 0x40) {
374 gb->sgb->mask_mode = MASK_DISABLED;
375 }
376 break;
377 case PAL_TRN:
378 gb->sgb->vram_transfer_countdown = 3;
379 gb->sgb->transfer_dest = TRANSFER_PALETTES;
380 break;
381 case DATA_SND:
382 // Not supported, but used by almost all SGB games for hot patching, so let's mute the warning for this
383 break;
384 case MLT_REQ:
385 gb->sgb->player_count = (gb->sgb->command[1] & 3) + 1; /* Todo: When breaking save state comaptibility,
386 fix this to be 0 based. */
387 if (gb->sgb->player_count == 3) {
388 gb->sgb->player_count++;
389 }
390 gb->sgb->current_player &= (gb->sgb->player_count - 1);
391 break;
392 case CHR_TRN:
393 gb->sgb->vram_transfer_countdown = 3;
394 gb->sgb->transfer_dest = (gb->sgb->command[1] & 1)? TRANSFER_HIGH_TILES : TRANSFER_LOW_TILES;
395 break;
396 case PCT_TRN:
397 gb->sgb->vram_transfer_countdown = 3;
398 gb->sgb->transfer_dest = TRANSFER_BORDER_DATA;
399 break;
400 case ATTR_TRN:
401 gb->sgb->vram_transfer_countdown = 3;
402 gb->sgb->transfer_dest = TRANSFER_ATTRIBUTES;
403 break;
404 case ATTR_SET:
405 load_attribute_file(gb, gb->sgb->command[1] & 0x3F);
406
407 if (gb->sgb->command[1] & 0x40) {
408 gb->sgb->mask_mode = MASK_DISABLED;
409 }
410 break;
411 case MASK_EN:
412 gb->sgb->mask_mode = gb->sgb->command[1] & 3;
413 break;
414 default:
415 if ((gb->sgb->command[0] >> 3) == 8 &&
416 (gb->sgb->command[1] & ~0x80) == 0 &&
417 (gb->sgb->command[2] & ~0x80) == 0) {
418 /* Mute/dummy sound commands, ignore this command as it's used by many games at startup */
419 break;
420 }
421 GB_log(gb, "Unimplemented SGB command %x: ", gb->sgb->command[0] >> 3);
422 for (unsigned i = 0; i < gb->sgb->command_write_index / 8; i++) {
423 GB_log(gb, "%02x ", gb->sgb->command[i]);
424 }
425 GB_log(gb, "\n");
426 }
427 }
428
GB_sgb_write(GB_gameboy_t * gb,uint8_t value)429 void GB_sgb_write(GB_gameboy_t *gb, uint8_t value)
430 {
431 if (!GB_is_sgb(gb)) return;
432 if (!GB_is_hle_sgb(gb)) {
433 /* Notify via callback */
434 return;
435 }
436 if (gb->sgb->disable_commands) return;
437
438 uint16_t command_size = (gb->sgb->command[0] & 7 ?: 1) * SGB_PACKET_SIZE * 8;
439 if ((gb->sgb->command[0] & 0xF1) == 0xF1) {
440 command_size = SGB_PACKET_SIZE * 8;
441 }
442
443 if ((value & 0x20) != 0 && (gb->io_registers[GB_IO_JOYP] & 0x20) == 0) {
444 if ((gb->sgb->player_count & 1) == 0) {
445 gb->sgb->current_player++;
446 gb->sgb->current_player &= (gb->sgb->player_count - 1);
447 }
448 }
449
450 switch ((value >> 4) & 3) {
451 case 3:
452 gb->sgb->ready_for_pulse = true;
453 break;
454
455 case 2: // Zero
456 if (!gb->sgb->ready_for_pulse || !gb->sgb->ready_for_write) return;
457 if (gb->sgb->ready_for_stop) {
458 if (gb->sgb->command_write_index == command_size) {
459 command_ready(gb);
460 gb->sgb->command_write_index = 0;
461 memset(gb->sgb->command, 0, sizeof(gb->sgb->command));
462 }
463 gb->sgb->ready_for_pulse = false;
464 gb->sgb->ready_for_write = false;
465 gb->sgb->ready_for_stop = false;
466 }
467 else {
468 if (gb->sgb->command_write_index < sizeof(gb->sgb->command) * 8) {
469 gb->sgb->command_write_index++;
470 gb->sgb->ready_for_pulse = false;
471 if (((gb->sgb->command_write_index) & (SGB_PACKET_SIZE * 8 - 1)) == 0) {
472 gb->sgb->ready_for_stop = true;
473 }
474 }
475 }
476 break;
477 case 1: // One
478 if (!gb->sgb->ready_for_pulse || !gb->sgb->ready_for_write) return;
479 if (gb->sgb->ready_for_stop) {
480 GB_log(gb, "Corrupt SGB command.\n");
481 gb->sgb->ready_for_pulse = false;
482 gb->sgb->ready_for_write = false;
483 gb->sgb->command_write_index = 0;
484 memset(gb->sgb->command, 0, sizeof(gb->sgb->command));
485 }
486 else {
487 if (gb->sgb->command_write_index < sizeof(gb->sgb->command) * 8) {
488 gb->sgb->command[gb->sgb->command_write_index / 8] |= 1 << (gb->sgb->command_write_index & 7);
489 gb->sgb->command_write_index++;
490 gb->sgb->ready_for_pulse = false;
491 if (((gb->sgb->command_write_index) & (SGB_PACKET_SIZE * 8 - 1)) == 0) {
492 gb->sgb->ready_for_stop = true;
493 }
494 }
495 }
496 break;
497
498 case 0:
499 if (!gb->sgb->ready_for_pulse) return;
500 gb->sgb->ready_for_write = true;
501 gb->sgb->ready_for_pulse = false;
502 if (((gb->sgb->command_write_index) & (SGB_PACKET_SIZE * 8 - 1)) != 0 ||
503 gb->sgb->command_write_index == 0 ||
504 gb->sgb->ready_for_stop) {
505 gb->sgb->command_write_index = 0;
506 memset(gb->sgb->command, 0, sizeof(gb->sgb->command));
507 gb->sgb->ready_for_stop = false;
508 }
509 break;
510
511 default:
512 break;
513 }
514 }
515
convert_rgb15(GB_gameboy_t * gb,uint16_t color)516 static uint32_t convert_rgb15(GB_gameboy_t *gb, uint16_t color)
517 {
518 return GB_convert_rgb15(gb, color, false);
519 }
520
convert_rgb15_with_fade(GB_gameboy_t * gb,uint16_t color,uint8_t fade)521 static uint32_t convert_rgb15_with_fade(GB_gameboy_t *gb, uint16_t color, uint8_t fade)
522 {
523 uint8_t r = ((color) & 0x1F) - fade;
524 uint8_t g = ((color >> 5) & 0x1F) - fade;
525 uint8_t b = ((color >> 10) & 0x1F) - fade;
526
527 if (r >= 0x20) r = 0;
528 if (g >= 0x20) g = 0;
529 if (b >= 0x20) b = 0;
530
531 color = r | (g << 5) | (b << 10);
532
533 return GB_convert_rgb15(gb, color, false);
534 }
535
render_boot_animation(GB_gameboy_t * gb)536 static void render_boot_animation (GB_gameboy_t *gb)
537 {
538 #include "graphics/sgb_animation_logo.inc"
539 uint32_t *output = gb->screen;
540 if (gb->border_mode != GB_BORDER_NEVER) {
541 output += 48 + 40 * 256;
542 }
543 uint8_t *input = animation_logo;
544 unsigned fade_blue = 0;
545 unsigned fade_red = 0;
546 if (gb->sgb->intro_animation < 80 - 32) {
547 fade_blue = 32;
548 }
549 else if (gb->sgb->intro_animation < 80) {
550 fade_blue = 80 - gb->sgb->intro_animation;
551 }
552 else if (gb->sgb->intro_animation > GB_SGB_INTRO_ANIMATION_LENGTH - 32) {
553 fade_red = fade_blue = gb->sgb->intro_animation - GB_SGB_INTRO_ANIMATION_LENGTH + 32;
554 }
555 uint32_t colors[] = {
556 convert_rgb15(gb, 0),
557 convert_rgb15_with_fade(gb, 0x14A5, fade_blue),
558 convert_rgb15_with_fade(gb, 0x54E0, fade_blue),
559 convert_rgb15_with_fade(gb, 0x0019, fade_red),
560 convert_rgb15(gb, 0x0011),
561 convert_rgb15(gb, 0x0009),
562 };
563 unsigned y_min = (144 - animation_logo_height) / 2;
564 unsigned y_max = y_min + animation_logo_height;
565 for (unsigned y = 0; y < 144; y++) {
566 for (unsigned x = 0; x < 160; x++) {
567 if (y < y_min || y >= y_max) {
568 *(output++) = colors[0];
569 }
570 else {
571 uint8_t color = *input;
572 if (color >= 3) {
573 if (color == gb->sgb->intro_animation / 2 - 3) {
574 color = 5;
575 }
576 else if (color == gb->sgb->intro_animation / 2 - 4) {
577 color = 4;
578 }
579 else if (color < gb->sgb->intro_animation / 2 - 4) {
580 color = 3;
581 }
582 else {
583 color = 0;
584 }
585 }
586 *(output++) = colors[color];
587 input++;
588 }
589 }
590 if (gb->border_mode != GB_BORDER_NEVER) {
591 output += 256 - 160;
592 }
593 }
594 }
595
596 static void render_jingle(GB_gameboy_t *gb, size_t count);
GB_sgb_render(GB_gameboy_t * gb)597 void GB_sgb_render(GB_gameboy_t *gb)
598 {
599 if (gb->apu_output.sample_rate) {
600 render_jingle(gb, gb->apu_output.sample_rate / GB_get_usual_frame_rate(gb));
601 }
602
603 if (gb->sgb->intro_animation < GB_SGB_INTRO_ANIMATION_LENGTH) gb->sgb->intro_animation++;
604
605 if (gb->sgb->vram_transfer_countdown) {
606 if (--gb->sgb->vram_transfer_countdown == 0) {
607 unsigned size = 0;
608 uint16_t *data = NULL;
609
610 switch (gb->sgb->transfer_dest) {
611 case TRANSFER_LOW_TILES:
612 size = 0x100;
613 data = (uint16_t *)gb->sgb->pending_border.tiles;
614 break;
615 case TRANSFER_HIGH_TILES:
616 size = 0x100;
617 data = (uint16_t *)gb->sgb->pending_border.tiles + 0x800;
618 break;
619 case TRANSFER_PALETTES:
620 size = 0x100;
621 data = gb->sgb->ram_palettes;
622 break;
623 case TRANSFER_BORDER_DATA:
624 size = 0x88;
625 data = gb->sgb->pending_border.raw_data;
626 break;
627 case TRANSFER_ATTRIBUTES:
628 size = 0xFE;
629 data = (uint16_t *)gb->sgb->attribute_files;
630 break;
631 default:
632 return; // Corrupt state?
633 }
634
635 for (unsigned tile = 0; tile < size; tile++) {
636 unsigned tile_x = (tile % 20) * 8;
637 unsigned tile_y = (tile / 20) * 8;
638 for (unsigned y = 0; y < 0x8; y++) {
639 static const uint16_t pixel_to_bits[4] = {0x0000, 0x0080, 0x8000, 0x8080};
640 *data = 0;
641 for (unsigned x = 0; x < 8; x++) {
642 *data |= pixel_to_bits[gb->sgb->screen_buffer[(tile_x + x) + (tile_y + y) * 160] & 3] >> x;
643 }
644 #ifdef GB_BIG_ENDIAN
645 *data = __builtin_bswap16(*data);
646 #endif
647 data++;
648 }
649 }
650 if (gb->sgb->transfer_dest == TRANSFER_BORDER_DATA) {
651 gb->sgb->border_animation = 105; // Measured on an SGB2, but might be off by ±2
652 }
653 }
654 }
655
656 if (!gb->screen || !gb->rgb_encode_callback || gb->disable_rendering) {
657 if (gb->sgb->border_animation > 32) {
658 gb->sgb->border_animation--;
659 }
660 else if (gb->sgb->border_animation != 0) {
661 gb->sgb->border_animation--;
662 }
663 if (gb->sgb->border_animation == 32) {
664 memcpy(&gb->sgb->border, &gb->sgb->pending_border, sizeof(gb->sgb->border));
665 }
666 return;
667 }
668
669 uint32_t colors[4 * 4];
670 for (unsigned i = 0; i < 4 * 4; i++) {
671 colors[i] = convert_rgb15(gb, LE16(gb->sgb->effective_palettes[i]));
672 }
673
674 if (gb->sgb->mask_mode != MASK_FREEZE) {
675 memcpy(gb->sgb->effective_screen_buffer,
676 gb->sgb->screen_buffer,
677 sizeof(gb->sgb->effective_screen_buffer));
678 }
679
680 if (gb->sgb->intro_animation < GB_SGB_INTRO_ANIMATION_LENGTH) {
681 render_boot_animation(gb);
682 }
683 else {
684 uint32_t *output = gb->screen;
685 if (gb->border_mode != GB_BORDER_NEVER) {
686 output += 48 + 40 * 256;
687 }
688 uint8_t *input = gb->sgb->effective_screen_buffer;
689 switch ((mask_mode_t) gb->sgb->mask_mode) {
690 case MASK_DISABLED:
691 case MASK_FREEZE: {
692 for (unsigned y = 0; y < 144; y++) {
693 for (unsigned x = 0; x < 160; x++) {
694 uint8_t palette = gb->sgb->attribute_map[x / 8 + y / 8 * 20] & 3;
695 *(output++) = colors[(*(input++) & 3) + palette * 4];
696 }
697 if (gb->border_mode != GB_BORDER_NEVER) {
698 output += 256 - 160;
699 }
700 }
701 break;
702 }
703 case MASK_BLACK:
704 {
705 uint32_t black = convert_rgb15(gb, 0);
706 for (unsigned y = 0; y < 144; y++) {
707 for (unsigned x = 0; x < 160; x++) {
708 *(output++) = black;
709 }
710 if (gb->border_mode != GB_BORDER_NEVER) {
711 output += 256 - 160;
712 }
713 }
714 break;
715 }
716 case MASK_COLOR_0:
717 {
718 for (unsigned y = 0; y < 144; y++) {
719 for (unsigned x = 0; x < 160; x++) {
720 *(output++) = colors[0];
721 }
722 if (gb->border_mode != GB_BORDER_NEVER) {
723 output += 256 - 160;
724 }
725 }
726 break;
727 }
728 }
729 }
730
731 uint32_t border_colors[16 * 4];
732 if (gb->sgb->border_animation == 0 || gb->sgb->border_animation > 64 || gb->sgb->intro_animation < GB_SGB_INTRO_ANIMATION_LENGTH) {
733 if (gb->sgb->border_animation != 0) {
734 gb->sgb->border_animation--;
735 }
736 for (unsigned i = 0; i < 16 * 4; i++) {
737 border_colors[i] = convert_rgb15(gb, LE16(gb->sgb->border.palette[i]));
738 }
739 }
740 else if (gb->sgb->border_animation > 32) {
741 gb->sgb->border_animation--;
742 for (unsigned i = 0; i < 16 * 4; i++) {
743 border_colors[i] = convert_rgb15_with_fade(gb, LE16(gb->sgb->border.palette[i]), 64 - gb->sgb->border_animation);
744 }
745 }
746 else {
747 gb->sgb->border_animation--;
748 for (unsigned i = 0; i < 16 * 4; i++) {
749 border_colors[i] = convert_rgb15_with_fade(gb, LE16(gb->sgb->border.palette[i]), gb->sgb->border_animation);
750 }
751 }
752
753
754 if (gb->sgb->border_animation == 32) {
755 memcpy(&gb->sgb->border, &gb->sgb->pending_border, sizeof(gb->sgb->border));
756 }
757
758 for (unsigned tile_y = 0; tile_y < 28; tile_y++) {
759 for (unsigned tile_x = 0; tile_x < 32; tile_x++) {
760 bool gb_area = false;
761 if (tile_x >= 6 && tile_x < 26 && tile_y >= 5 && tile_y < 23) {
762 gb_area = true;
763 }
764 else if (gb->border_mode == GB_BORDER_NEVER) {
765 continue;
766 }
767 uint16_t tile = LE16(gb->sgb->border.map[tile_x + tile_y * 32]);
768 if (tile & 0x300) continue; // Unused tile
769 uint8_t flip_x = (tile & 0x4000)? 0:7;
770 uint8_t flip_y = (tile & 0x8000)? 7:0;
771 uint8_t palette = (tile >> 10) & 3;
772 for (unsigned y = 0; y < 8; y++) {
773 unsigned base = (tile & 0xFF) * 32 + (y ^ flip_y) * 2;
774 for (unsigned x = 0; x < 8; x++) {
775 uint8_t bit = 1 << (x ^ flip_x);
776 uint8_t color = ((gb->sgb->border.tiles[base] & bit) ? 1: 0) |
777 ((gb->sgb->border.tiles[base + 1] & bit) ? 2: 0) |
778 ((gb->sgb->border.tiles[base + 16] & bit) ? 4: 0) |
779 ((gb->sgb->border.tiles[base + 17] & bit) ? 8: 0);
780
781 uint32_t *output = gb->screen;
782 if (gb->border_mode == GB_BORDER_NEVER) {
783 output += (tile_x - 6) * 8 + x + ((tile_y - 5) * 8 + y) * 160;
784 }
785 else {
786 output += tile_x * 8 + x + (tile_y * 8 + y) * 256;
787 }
788 if (color == 0) {
789 if (gb_area) continue;
790 *output = colors[0];
791 }
792 else {
793 *output = border_colors[color + palette * 16];
794 }
795 }
796 }
797 }
798 }
799 }
800
GB_sgb_load_default_data(GB_gameboy_t * gb)801 void GB_sgb_load_default_data(GB_gameboy_t *gb)
802 {
803
804 #include "graphics/sgb_border.inc"
805
806 #ifdef GB_BIG_ENDIAN
807 for (unsigned i = 0; i < sizeof(tilemap) / 2; i++) {
808 gb->sgb->border.map[i] = LE16(tilemap[i]);
809 }
810 for (unsigned i = 0; i < sizeof(palette) / 2; i++) {
811 gb->sgb->border.palette[i] = LE16(palette[i]);
812 }
813 #else
814 memcpy(gb->sgb->border.map, tilemap, sizeof(tilemap));
815 memcpy(gb->sgb->border.palette, palette, sizeof(palette));
816 #endif
817 memcpy(gb->sgb->border.tiles, tiles, sizeof(tiles));
818
819 if (gb->model != GB_MODEL_SGB2) {
820 /* Delete the "2" */
821 gb->sgb->border.map[25 * 32 + 25] = gb->sgb->border.map[25 * 32 + 26] =
822 gb->sgb->border.map[26 * 32 + 25] = gb->sgb->border.map[26 * 32 + 26] =
823 gb->sgb->border.map[27 * 32 + 25] = gb->sgb->border.map[27 * 32 + 26] =
824 gb->sgb->border.map[0];
825
826 /* Re-center */
827 memmove(&gb->sgb->border.map[25 * 32 + 1], &gb->sgb->border.map[25 * 32], (32 * 3 - 1) * sizeof(gb->sgb->border.map[0]));
828 }
829 gb->sgb->effective_palettes[0] = LE16(built_in_palettes[0]);
830 gb->sgb->effective_palettes[1] = LE16(built_in_palettes[1]);
831 gb->sgb->effective_palettes[2] = LE16(built_in_palettes[2]);
832 gb->sgb->effective_palettes[3] = LE16(built_in_palettes[3]);
833 }
834
fm_synth(double phase)835 static double fm_synth(double phase)
836 {
837 return (sin(phase * M_PI * 2) +
838 sin(phase * M_PI * 2 + sin(phase * M_PI * 2)) +
839 sin(phase * M_PI * 2 + sin(phase * M_PI * 3)) +
840 sin(phase * M_PI * 2 + sin(phase * M_PI * 4))) / 4;
841 }
842
fm_sweep(double phase)843 static double fm_sweep(double phase)
844 {
845 double ret = 0;
846 for (unsigned i = 0; i < 8; i++) {
847 ret += sin((phase * M_PI * 2 + sin(phase * M_PI * 8) / 4) * pow(1.25, i)) * (8 - i) / 36;
848 }
849 return ret;
850 }
random_double(void)851 static double random_double(void)
852 {
853 return ((signed)(GB_random32() % 0x10001) - 0x8000) / (double) 0x8000;
854 }
855
render_jingle(GB_gameboy_t * gb,size_t count)856 static void render_jingle(GB_gameboy_t *gb, size_t count)
857 {
858 const double frequencies[7] = {
859 466.16, // Bb4
860 587.33, // D5
861 698.46, // F5
862 830.61, // Ab5
863 1046.50, // C6
864 1244.51, // Eb6
865 1567.98, // G6
866 };
867
868 assert(gb->apu_output.sample_callback);
869
870 if (gb->sgb->intro_animation < 0) {
871 GB_sample_t sample = {0, 0};
872 for (unsigned i = 0; i < count; i++) {
873 gb->apu_output.sample_callback(gb, &sample);
874 }
875 return;
876 }
877
878 if (gb->sgb->intro_animation >= GB_SGB_INTRO_ANIMATION_LENGTH) return;
879
880 signed jingle_stage = (gb->sgb->intro_animation - 64) / 3;
881 double sweep_cutoff_ratio = 2000.0 * pow(2, gb->sgb->intro_animation / 20.0) / gb->apu_output.sample_rate;
882 double sweep_phase_shift = 1000.0 * pow(2, gb->sgb->intro_animation / 40.0) / gb->apu_output.sample_rate;
883 if (sweep_cutoff_ratio > 1) {
884 sweep_cutoff_ratio = 1;
885 }
886
887 GB_sample_t stereo;
888 for (unsigned i = 0; i < count; i++) {
889 double sample = 0;
890 for (signed f = 0; f < 7 && f < jingle_stage; f++) {
891 sample += fm_synth(gb->sgb_intro_jingle_phases[f]) *
892 (0.75 * pow(0.5, jingle_stage - f) + 0.25) / 5.0;
893 gb->sgb_intro_jingle_phases[f] += frequencies[f] / gb->apu_output.sample_rate;
894 }
895 if (gb->sgb->intro_animation > 100) {
896 sample *= pow((GB_SGB_INTRO_ANIMATION_LENGTH - gb->sgb->intro_animation) / (GB_SGB_INTRO_ANIMATION_LENGTH - 100.0), 3);
897 }
898
899 if (gb->sgb->intro_animation < 120) {
900 double next = fm_sweep(gb->sgb_intro_sweep_phase) * 0.3 + random_double() * 0.7;
901 gb->sgb_intro_sweep_phase += sweep_phase_shift;
902
903 gb->sgb_intro_sweep_previous_sample = next * (sweep_cutoff_ratio) +
904 gb->sgb_intro_sweep_previous_sample * (1 - sweep_cutoff_ratio);
905 sample += gb->sgb_intro_sweep_previous_sample * pow((120 - gb->sgb->intro_animation) / 120.0, 2) * 0.8;
906 }
907
908 stereo.left = stereo.right = sample * 0x7000;
909 gb->apu_output.sample_callback(gb, &stereo);
910 }
911
912 return;
913 }
914
915