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