Mercurial > repos > blastem
comparison blastem.c @ 2072:cc13c100b027
Merge Sega CD branch now that it sort of works
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 30 Jan 2022 22:29:29 -0800 |
parents | 7c1760b5b3e5 |
children | 3f29e2726522 |
comparison
equal
deleted
inserted
replaced
2052:3748a2a8a4b7 | 2072:cc13c100b027 |
---|---|
28 #include "arena.h" | 28 #include "arena.h" |
29 #include "config.h" | 29 #include "config.h" |
30 #include "bindings.h" | 30 #include "bindings.h" |
31 #include "menu.h" | 31 #include "menu.h" |
32 #include "zip.h" | 32 #include "zip.h" |
33 #include "cue.h" | |
33 #include "event_log.h" | 34 #include "event_log.h" |
34 #ifndef DISABLE_NUKLEAR | 35 #ifndef DISABLE_NUKLEAR |
35 #include "nuklear_ui/blastem_nuklear.h" | 36 #include "nuklear_ui/blastem_nuklear.h" |
36 #endif | 37 #endif |
37 | 38 |
89 | 90 |
90 size_t filesize = 512 * 1024; | 91 size_t filesize = 512 * 1024; |
91 size_t readsize = 0; | 92 size_t readsize = 0; |
92 uint16_t *dst, *buf; | 93 uint16_t *dst, *buf; |
93 dst = buf = malloc(filesize); | 94 dst = buf = malloc(filesize); |
94 | 95 |
95 | 96 |
96 size_t read; | 97 size_t read; |
97 do { | 98 do { |
98 if ((readsize + SMD_BLOCK_SIZE > filesize)) { | 99 if ((readsize + SMD_BLOCK_SIZE > filesize)) { |
99 filesize *= 2; | 100 filesize *= 2; |
105 dst = process_smd_block(dst, block, read); | 106 dst = process_smd_block(dst, block, read); |
106 readsize += read; | 107 readsize += read; |
107 } | 108 } |
108 } while(read > 0); | 109 } while(read > 0); |
109 romclose(f); | 110 romclose(f); |
110 | 111 |
111 *buffer = buf; | 112 *buffer = buf; |
112 | 113 |
113 return readsize; | 114 return readsize; |
114 } | 115 } |
115 | 116 |
116 uint8_t is_smd_format(const char *filename, uint8_t *header) | 117 uint8_t is_smd_format(const char *filename, uint8_t *header) |
117 { | 118 { |
130 } | 131 } |
131 } | 132 } |
132 return 0; | 133 return 0; |
133 } | 134 } |
134 | 135 |
135 uint32_t load_rom_zip(const char *filename, void **dst) | 136 uint32_t load_media_zip(const char *filename, system_media *dst) |
136 { | 137 { |
137 static const char *valid_exts[] = {"bin", "md", "gen", "sms", "rom", "smd"}; | 138 static const char *valid_exts[] = {"bin", "md", "gen", "sms", "rom", "smd"}; |
138 const uint32_t num_exts = sizeof(valid_exts)/sizeof(*valid_exts); | 139 const uint32_t num_exts = sizeof(valid_exts)/sizeof(*valid_exts); |
139 zip_file *z = zip_open(filename); | 140 zip_file *z = zip_open(filename); |
140 if (!z) { | 141 if (!z) { |
141 return 0; | 142 return 0; |
142 } | 143 } |
143 | 144 |
144 for (uint32_t i = 0; i < z->num_entries; i++) | 145 for (uint32_t i = 0; i < z->num_entries; i++) |
145 { | 146 { |
146 char *ext = path_extension(z->entries[i].name); | 147 char *ext = path_extension(z->entries[i].name); |
147 if (!ext) { | 148 if (!ext) { |
148 continue; | 149 continue; |
149 } | 150 } |
150 for (uint32_t j = 0; j < num_exts; j++) | 151 for (uint32_t j = 0; j < num_exts; j++) |
151 { | 152 { |
152 if (!strcasecmp(ext, valid_exts[j])) { | 153 if (!strcasecmp(ext, valid_exts[j])) { |
153 size_t out_size = nearest_pow2(z->entries[i].size); | 154 size_t out_size = nearest_pow2(z->entries[i].size); |
154 *dst = zip_read(z, i, &out_size); | 155 dst->buffer = zip_read(z, i, &out_size); |
155 if (*dst) { | 156 if (dst->buffer) { |
156 if (is_smd_format(z->entries[i].name, *dst)) { | 157 if (is_smd_format(z->entries[i].name, dst->buffer)) { |
157 size_t offset; | 158 size_t offset; |
158 for (offset = 0; offset + SMD_BLOCK_SIZE + SMD_HEADER_SIZE <= out_size; offset += SMD_BLOCK_SIZE) | 159 for (offset = 0; offset + SMD_BLOCK_SIZE + SMD_HEADER_SIZE <= out_size; offset += SMD_BLOCK_SIZE) |
159 { | 160 { |
160 uint8_t tmp[SMD_BLOCK_SIZE]; | 161 uint8_t tmp[SMD_BLOCK_SIZE]; |
161 uint8_t *u8dst = *dst; | 162 uint8_t *u8dst = dst->buffer; |
162 memcpy(tmp, u8dst + offset + SMD_HEADER_SIZE, SMD_BLOCK_SIZE); | 163 memcpy(tmp, u8dst + offset + SMD_HEADER_SIZE, SMD_BLOCK_SIZE); |
163 process_smd_block((void *)(u8dst + offset), tmp, SMD_BLOCK_SIZE); | 164 process_smd_block((void *)(u8dst + offset), tmp, SMD_BLOCK_SIZE); |
164 } | 165 } |
165 out_size = offset; | 166 out_size = offset; |
166 } | 167 } |
167 free(ext); | 168 dst->extension = ext; |
169 dst->dir = path_dirname(filename); | |
170 dst->name = basename_no_extension(filename); | |
171 dst->size = out_size; | |
168 zip_close(z); | 172 zip_close(z); |
169 return out_size; | 173 return out_size; |
170 } | 174 } |
171 } | 175 } |
172 } | 176 } |
174 } | 178 } |
175 zip_close(z); | 179 zip_close(z); |
176 return 0; | 180 return 0; |
177 } | 181 } |
178 | 182 |
179 uint32_t load_rom(const char * filename, void **dst, system_type *stype) | 183 uint32_t load_media(const char * filename, system_media *dst, system_type *stype) |
180 { | 184 { |
181 uint8_t header[10]; | 185 uint8_t header[10]; |
182 char *ext = path_extension(filename); | 186 char *ext = path_extension(filename); |
183 if (ext && !strcasecmp(ext, "zip")) { | 187 if (ext && !strcasecmp(ext, "zip")) { |
184 free(ext); | 188 free(ext); |
185 return load_rom_zip(filename, dst); | 189 return load_media_zip(filename, dst); |
186 } | 190 } |
187 free(ext); | 191 free(ext); |
188 ROMFILE f = romopen(filename, "rb"); | 192 ROMFILE f = romopen(filename, "rb"); |
189 if (!f) { | 193 if (!f) { |
190 return 0; | 194 return 0; |
191 } | 195 } |
192 if (sizeof(header) != romread(header, 1, sizeof(header), f)) { | 196 if (sizeof(header) != romread(header, 1, sizeof(header), f)) { |
193 fatal_error("Error reading from %s\n", filename); | 197 fatal_error("Error reading from %s\n", filename); |
194 } | 198 } |
195 | 199 |
200 uint32_t ret = 0; | |
196 if (is_smd_format(filename, header)) { | 201 if (is_smd_format(filename, header)) { |
197 if (stype) { | 202 if (stype) { |
198 *stype = SYSTEM_GENESIS; | 203 *stype = SYSTEM_GENESIS; |
199 } | 204 } |
200 return load_smd_rom(f, dst); | 205 ret = load_smd_rom(f, &dst->buffer); |
201 } | 206 } |
202 | 207 |
203 size_t filesize = 512 * 1024; | 208 if (!ret) { |
204 size_t readsize = sizeof(header); | 209 size_t filesize = 512 * 1024; |
205 | 210 size_t readsize = sizeof(header); |
206 char *buf = malloc(filesize); | 211 |
207 memcpy(buf, header, readsize); | 212 char *buf = malloc(filesize); |
208 | 213 memcpy(buf, header, readsize); |
209 size_t read; | 214 |
210 do { | 215 size_t read; |
211 read = romread(buf + readsize, 1, filesize - readsize, f); | 216 do { |
212 if (read > 0) { | 217 read = romread(buf + readsize, 1, filesize - readsize, f); |
213 readsize += read; | 218 if (read > 0) { |
214 if (readsize == filesize) { | 219 readsize += read; |
215 int one_more = romgetc(f); | 220 if (readsize == filesize) { |
216 if (one_more >= 0) { | 221 int one_more = romgetc(f); |
217 filesize *= 2; | 222 if (one_more >= 0) { |
218 buf = realloc(buf, filesize); | 223 filesize *= 2; |
219 buf[readsize++] = one_more; | 224 buf = realloc(buf, filesize); |
220 } else { | 225 buf[readsize++] = one_more; |
221 read = 0; | 226 } else { |
222 } | 227 read = 0; |
223 } | 228 } |
224 } | 229 } |
225 } while (read > 0); | 230 } |
226 | 231 } while (read > 0); |
227 *dst = buf; | 232 dst->buffer = buf; |
228 | 233 ret = (uint32_t)readsize; |
234 } | |
235 dst->dir = path_dirname(filename); | |
236 dst->name = basename_no_extension(filename); | |
237 dst->extension = path_extension(filename); | |
238 dst->size = ret; | |
229 romclose(f); | 239 romclose(f); |
230 return readsize; | 240 if (!strcasecmp(dst->extension, "cue")) { |
241 if (parse_cue(dst)) { | |
242 if (stype) { | |
243 *stype = SYSTEM_SEGACD; | |
244 } | |
245 } | |
246 } | |
247 | |
248 return ret; | |
231 } | 249 } |
232 | 250 |
233 | 251 |
234 | 252 |
235 int break_on_sync = 0; | 253 int break_on_sync = 0; |
387 reload_media(); | 405 reload_media(); |
388 cart.chain = &lock_on; | 406 cart.chain = &lock_on; |
389 free(lock_on.dir); | 407 free(lock_on.dir); |
390 free(lock_on.name); | 408 free(lock_on.name); |
391 free(lock_on.extension); | 409 free(lock_on.extension); |
392 lock_on.dir = path_dirname(lock_on_path); | 410 load_media(lock_on_path, &lock_on, NULL); |
393 lock_on.name = basename_no_extension(lock_on_path); | |
394 lock_on.extension = path_extension(lock_on_path); | |
395 lock_on.size = load_rom(lock_on_path, &lock_on.buffer, NULL); | |
396 } | 411 } |
397 | 412 |
398 static uint32_t opts = 0; | 413 static uint32_t opts = 0; |
399 static uint8_t force_region = 0; | 414 static uint8_t force_region = 0; |
400 void init_system_with_media(const char *path, system_type force_stype) | 415 void init_system_with_media(const char *path, system_type force_stype) |
409 game_system->free_context(game_system); | 424 game_system->free_context(game_system); |
410 } else if(current_system) { | 425 } else if(current_system) { |
411 //start a new arena and save old one in suspended system context | 426 //start a new arena and save old one in suspended system context |
412 current_system->arena = start_new_arena(); | 427 current_system->arena = start_new_arena(); |
413 } | 428 } |
414 system_type stype = SYSTEM_UNKNOWN; | |
415 if (!(cart.size = load_rom(path, &cart.buffer, &stype))) { | |
416 fatal_error("Failed to open %s for reading\n", path); | |
417 } | |
418 free(cart.dir); | 429 free(cart.dir); |
419 free(cart.name); | 430 free(cart.name); |
420 free(cart.extension); | 431 free(cart.extension); |
421 cart.dir = path_dirname(path); | 432 system_type stype = SYSTEM_UNKNOWN; |
422 cart.name = basename_no_extension(path); | 433 if (!(cart.size = load_media(path, &cart, &stype))) { |
423 cart.extension = path_extension(path); | 434 fatal_error("Failed to open %s for reading\n", path); |
435 } | |
436 | |
424 if (force_stype != SYSTEM_UNKNOWN) { | 437 if (force_stype != SYSTEM_UNKNOWN) { |
425 stype = force_stype; | 438 stype = force_stype; |
426 } | 439 } |
427 if (stype == SYSTEM_UNKNOWN) { | 440 if (stype == SYSTEM_UNKNOWN) { |
428 stype = detect_system_type(&cart); | 441 stype = detect_system_type(&cart); |
570 case 'o': { | 583 case 'o': { |
571 i++; | 584 i++; |
572 if (i >= argc) { | 585 if (i >= argc) { |
573 fatal_error("-o must be followed by a lock on cartridge filename\n"); | 586 fatal_error("-o must be followed by a lock on cartridge filename\n"); |
574 } | 587 } |
575 lock_on.size = load_rom(argv[i], &lock_on.buffer, NULL); | 588 if (!load_media(argv[i], &lock_on, NULL)) { |
576 if (!lock_on.size) { | |
577 fatal_error("Failed to load lock on cartridge %s\n", argv[i]); | 589 fatal_error("Failed to load lock on cartridge %s\n", argv[i]); |
578 } | 590 } |
579 lock_on.name = basename_no_extension(argv[i]); | |
580 lock_on.extension = path_extension(argv[i]); | |
581 cart.chain = &lock_on; | 591 cart.chain = &lock_on; |
582 break; | 592 break; |
583 } | 593 } |
584 case 'h': | 594 case 'h': |
585 info_message( | 595 info_message( |
609 } else if (!loaded) { | 619 } else if (!loaded) { |
610 reader_port = parse_addr_port(argv[i]); | 620 reader_port = parse_addr_port(argv[i]); |
611 if (reader_port) { | 621 if (reader_port) { |
612 reader_addr = argv[i]; | 622 reader_addr = argv[i]; |
613 } else { | 623 } else { |
614 if (!(cart.size = load_rom(argv[i], &cart.buffer, stype == SYSTEM_UNKNOWN ? &stype : NULL))) { | 624 if (!load_media(argv[i], &cart, stype == SYSTEM_UNKNOWN ? &stype : NULL)) { |
615 fatal_error("Failed to open %s for reading\n", argv[i]); | 625 fatal_error("Failed to open %s for reading\n", argv[i]); |
616 } | 626 } |
617 cart.dir = path_dirname(argv[i]); | |
618 cart.name = basename_no_extension(argv[i]); | |
619 cart.extension = path_extension(argv[i]); | |
620 } | 627 } |
621 romfname = argv[i]; | 628 romfname = argv[i]; |
622 loaded = 1; | 629 loaded = 1; |
623 } else if (width < 0) { | 630 } else if (width < 0) { |
624 width = atoi(argv[i]); | 631 width = atoi(argv[i]); |
625 } else if (height < 0) { | 632 } else if (height < 0) { |
626 height = atoi(argv[i]); | 633 height = atoi(argv[i]); |
627 } | 634 } |
628 } | 635 } |
629 | 636 |
630 int def_width = 0, def_height = 0; | 637 int def_width = 0, def_height = 0; |
631 char *config_width = tern_find_path(config, "video\0width\0", TVAL_PTR).ptrval; | 638 char *config_width = tern_find_path(config, "video\0width\0", TVAL_PTR).ptrval; |
632 if (config_width) { | 639 if (config_width) { |
633 def_width = atoi(config_width); | 640 def_width = atoi(config_width); |
634 } | 641 } |
655 } | 662 } |
656 render_init(width, height, "BlastEm", fullscreen); | 663 render_init(width, height, "BlastEm", fullscreen); |
657 render_set_drag_drop_handler(on_drag_drop); | 664 render_set_drag_drop_handler(on_drag_drop); |
658 } | 665 } |
659 set_bindings(); | 666 set_bindings(); |
660 | 667 |
661 uint8_t menu = !loaded; | 668 uint8_t menu = !loaded; |
662 uint8_t use_nuklear = 0; | 669 uint8_t use_nuklear = 0; |
663 #ifndef DISABLE_NUKLEAR | 670 #ifndef DISABLE_NUKLEAR |
664 use_nuklear = !headless && is_nuklear_available(); | 671 use_nuklear = !headless && is_nuklear_available(); |
665 #endif | 672 #endif |
668 romfname = tern_find_path(config, "ui\0rom\0", TVAL_PTR).ptrval; | 675 romfname = tern_find_path(config, "ui\0rom\0", TVAL_PTR).ptrval; |
669 if (!romfname) { | 676 if (!romfname) { |
670 romfname = "menu.bin"; | 677 romfname = "menu.bin"; |
671 } | 678 } |
672 if (is_absolute_path(romfname)) { | 679 if (is_absolute_path(romfname)) { |
673 if (!(cart.size = load_rom(romfname, &cart.buffer, &stype))) { | 680 if (!(cart.size = load_media(romfname, &cart, &stype))) { |
674 fatal_error("Failed to open UI ROM %s for reading", romfname); | 681 fatal_error("Failed to open UI ROM %s for reading", romfname); |
675 } | 682 } |
676 } else { | 683 } else { |
677 cart.buffer = (uint16_t *)read_bundled_file(romfname, &cart.size); | 684 cart.buffer = (uint16_t *)read_bundled_file(romfname, &cart.size); |
678 if (!cart.buffer) { | 685 if (!cart.buffer) { |
681 uint32_t rom_size = nearest_pow2(cart.size); | 688 uint32_t rom_size = nearest_pow2(cart.size); |
682 if (rom_size > cart.size) { | 689 if (rom_size > cart.size) { |
683 cart.buffer = realloc(cart.buffer, rom_size); | 690 cart.buffer = realloc(cart.buffer, rom_size); |
684 cart.size = rom_size; | 691 cart.size = rom_size; |
685 } | 692 } |
693 cart.dir = path_dirname(romfname); | |
694 cart.name = basename_no_extension(romfname); | |
695 cart.extension = path_extension(romfname); | |
686 } | 696 } |
687 //force system detection, value on command line is only for games not the menu | 697 //force system detection, value on command line is only for games not the menu |
688 stype = detect_system_type(&cart); | 698 stype = detect_system_type(&cart); |
689 cart.dir = path_dirname(romfname); | |
690 cart.name = basename_no_extension(romfname); | |
691 cart.extension = path_extension(romfname); | |
692 loaded = 1; | 699 loaded = 1; |
693 } | 700 } |
694 char *state_format = tern_find_path(config, "ui\0state_format\0", TVAL_PTR).ptrval; | 701 char *state_format = tern_find_path(config, "ui\0state_format\0", TVAL_PTR).ptrval; |
695 if (state_format && !strcmp(state_format, "gst")) { | 702 if (state_format && !strcmp(state_format, "gst")) { |
696 use_native_states = 0; | 703 use_native_states = 0; |
703 stype = detect_system_type(&cart); | 710 stype = detect_system_type(&cart); |
704 } | 711 } |
705 if (stype == SYSTEM_UNKNOWN) { | 712 if (stype == SYSTEM_UNKNOWN) { |
706 fatal_error("Failed to detect system type for %s\n", romfname); | 713 fatal_error("Failed to detect system type for %s\n", romfname); |
707 } | 714 } |
708 | 715 |
709 current_system = alloc_config_system(stype, &cart, menu ? 0 : opts, force_region); | 716 current_system = alloc_config_system(stype, &cart, menu ? 0 : opts, force_region); |
710 if (!current_system) { | 717 if (!current_system) { |
711 fatal_error("Failed to configure emulated machine for %s\n", romfname); | 718 fatal_error("Failed to configure emulated machine for %s\n", romfname); |
712 } | 719 } |
713 | 720 |
714 setup_saves(&cart, current_system); | 721 setup_saves(&cart, current_system); |
715 update_title(current_system->info.name); | 722 update_title(current_system->info.name); |
716 if (menu) { | 723 if (menu) { |
717 menu_system = current_system; | 724 menu_system = current_system; |
718 } else { | 725 } else { |
719 game_system = current_system; | 726 game_system = current_system; |
720 } | 727 } |
721 } | 728 } |
722 | 729 |
723 #ifndef DISABLE_NUKLEAR | 730 #ifndef DISABLE_NUKLEAR |
724 if (use_nuklear) { | 731 if (use_nuklear) { |
725 blastem_nuklear_init(!menu); | 732 blastem_nuklear_init(!menu); |
726 current_system = game_system; | 733 current_system = game_system; |
727 menu = 0; | 734 menu = 0; |
738 //free inflate stream as it was inflateCopied to an internal event reader in the player | 745 //free inflate stream as it was inflateCopied to an internal event reader in the player |
739 inflateEnd(&reader.input_stream); | 746 inflateEnd(&reader.input_stream); |
740 setup_saves(&cart, current_system); | 747 setup_saves(&cart, current_system); |
741 update_title(current_system->info.name); | 748 update_title(current_system->info.name); |
742 } | 749 } |
743 | 750 |
744 current_system->debugger_type = dtype; | 751 current_system->debugger_type = dtype; |
745 current_system->enter_debugger = start_in_debugger && menu == debug_target; | 752 current_system->enter_debugger = start_in_debugger && menu == debug_target; |
746 current_system->start_context(current_system, menu ? NULL : statefile); | 753 current_system->start_context(current_system, menu ? NULL : statefile); |
747 render_video_loop(); | 754 render_video_loop(); |
748 for(;;) | 755 for(;;) |