diff --git a/cen64.c b/cen64.c index 0aa7ec355..a3cef30e3 100644 --- a/cen64.c +++ b/cen64.c @@ -53,6 +53,8 @@ int cen64_main(int argc, const char **argv) { struct save_file flashram; struct is_viewer is, *is_in = NULL; + FILE* m64_fp = NULL; + if (!cart_db_is_well_formed()) { printf("Internal cart detection database is not well-formed.\n"); return EXIT_FAILURE; @@ -180,6 +182,30 @@ int cen64_main(int argc, const char **argv) { } } + if (options.m64_path) { + m64_fp = fopen(options.m64_path, "rb"); + if (m64_fp != NULL) { + // http://tasvideos.org/EmulatorResources/Mupen/M64.html + uint8_t header[0x400]; + size_t n = fread(header, 1, sizeof header, m64_fp); + if (n == sizeof header && memcmp(header, "M64\x1A", 4) == 0) { + printf("Playing back m64:\n"); + printf(" ROM name: %.32s (crc %X, region %X)\n", + header+0xC4, + *(uint32_t*)(header+0xE4), + *(uint16_t*)(header+0xE8)); + printf(" Author: %.222s\n", header+0x222); + printf(" Description: %.256s\n", header+0x300); + } else { + fclose(m64_fp); + printf("Invalid Mupen64 movie file '%s'.\n", options.m64_path); + return EXIT_FAILURE; + } + } else { + printf("Failed to open Mupen64 movie file '%s'.\n", options.m64_path); + return EXIT_FAILURE; + } + } // Allocate memory for and create the device. @@ -193,7 +219,7 @@ int cen64_main(int argc, const char **argv) { if (device_create(device, &ddipl, dd_variant, &ddrom, &pifrom, &cart, &eeprom, &sram, - &flashram, is_in, controller, + &flashram, is_in, controller, m64_fp, options.no_audio, options.no_video, options.enable_profiling) == NULL) { printf("Failed to create a device.\n"); status = EXIT_FAILURE; diff --git a/device/device.c b/device/device.c index cd5a046c6..4f2289609 100644 --- a/device/device.c +++ b/device/device.c @@ -44,7 +44,7 @@ struct cen64_device *device_create(struct cen64_device *device, const struct rom_file *pifrom, const struct rom_file *cart, const struct save_file *eeprom, const struct save_file *sram, const struct save_file *flashram, struct is_viewer *is, - const struct controller *controller, + const struct controller *controller, FILE* m64_fp, bool no_audio, bool no_video, bool profiling) { // Allocate memory for VR4300 @@ -99,7 +99,7 @@ struct cen64_device *device_create(struct cen64_device *device, // Initialize the SI. if (si_init(&device->si, &device->bus, pifrom->ptr, cart->ptr, dd_variant, eeprom->ptr, eeprom->size, - controller)) { + controller, m64_fp)) { debug("create_device: Failed to initialize the SI.\n"); return NULL; } @@ -160,6 +160,10 @@ void device_destroy(struct cen64_device *device, const char *cart_path) { fclose(f); } + + if (device->si.m64_fp != NULL) { + fclose(device->si.m64_fp); + } } // Called when we should (probably?) leave simulation. @@ -351,4 +355,4 @@ int device_debug_spin(struct cen64_device *device) { cen64_cold void device_connect_debugger(struct cen64_device *device, void* break_handler_data, vr4300_debug_break_handler break_handler) { vr4300_connect_debugger(device->vr4300, break_handler_data, break_handler); -} \ No newline at end of file +} diff --git a/device/device.h b/device/device.h index 81709c25a..dd63b3f8e 100644 --- a/device/device.h +++ b/device/device.h @@ -61,7 +61,7 @@ cen64_cold struct cen64_device *device_create(struct cen64_device *device, const struct rom_file *pifrom, const struct rom_file *cart, const struct save_file *eeprom, const struct save_file *sram, const struct save_file *flashram, struct is_viewer *is, - const struct controller *controller, + const struct controller *controller, FILE* m64_fp, bool no_audio, bool no_video, bool profiling); cen64_cold void device_exit(struct bus_controller *bus); diff --git a/device/options.c b/device/options.c index 65265061d..014aaa003 100644 --- a/device/options.c +++ b/device/options.c @@ -26,6 +26,7 @@ const struct cen64_options default_cen64_options = { NULL, // flashram_path 0, // is_viewer_present NULL, // controller + NULL, // m64_path #ifdef _WIN32 false, // console #endif @@ -153,6 +154,15 @@ int parse_options(struct cen64_options *options, int argc, const char *argv[]) { options->controller[num] = opt; } + else if (!strcmp(argv[i], "-m64")) { + if ((i + 1) >= (argc - 1)) { + printf("-m64 requires a path to the movie file.\n\n"); + return 1; + } + + options->m64_path = argv[++i]; + } + // TODO: Handle this better. else break; @@ -282,6 +292,8 @@ void print_command_line_usage(const char *invokation_string) { " -sram : Path to SRAM save.\n" " -flash : Path to FlashRAM save.\n" " For mempak see controller options.\n" + "Mupen64 movie playback options:\n" + " -m64 : Path to m64 movie file.\n" ,invokation_string ); diff --git a/device/options.h b/device/options.h index c8d38b9aa..aca8b8836 100644 --- a/device/options.h +++ b/device/options.h @@ -27,6 +27,8 @@ struct cen64_options { struct controller *controller; + const char* m64_path; + #ifdef _WIN32 bool console; #endif diff --git a/si/controller.c b/si/controller.c index d62330620..f6b9a9660 100644 --- a/si/controller.c +++ b/si/controller.c @@ -44,7 +44,8 @@ int si_init(struct si_controller *si, struct bus_controller *bus, const uint8_t *pif_rom, const uint8_t *cart_rom, const struct dd_variant *dd_variant, uint8_t *eeprom, size_t eeprom_size, - const struct controller *controller) { + const struct controller *controller, + FILE* m64_fp) { uint32_t cic_seed; si->bus = bus; @@ -83,6 +84,9 @@ int si_init(struct si_controller *si, struct bus_controller *bus, // controllers memcpy(si->controller, controller, sizeof(struct controller) * 4); + // Mupen64 movie file + si->m64_fp = m64_fp; + return 0; } @@ -146,7 +150,18 @@ int pif_perform_command(struct si_controller *si, if (likely(bus->vi->window)) { cen64_mutex_lock(&bus->vi->window->event_mutex); + + if (si->m64_fp != NULL) { + fread(si->input, 1, 4, si->m64_fp); + if (feof(si->m64_fp) || ferror(si->m64_fp)) { + fclose(si->m64_fp); + si->m64_fp = NULL; + printf("Movie playback finished.\n"); + } + } + memcpy(recv_buf, si->input, sizeof(si->input)); + cen64_mutex_unlock(&bus->vi->window->event_mutex); } diff --git a/si/controller.h b/si/controller.h index 2e8a4ff4b..229ae9807 100644 --- a/si/controller.h +++ b/si/controller.h @@ -41,13 +41,16 @@ struct si_controller { uint8_t input[4]; struct eeprom eeprom; struct controller controller[4]; + + FILE* m64_fp; // Mupen64 movie file }; cen64_cold int si_init(struct si_controller *si, struct bus_controller *bus, const uint8_t *pif_rom, const uint8_t *cart_rom, const struct dd_variant *dd_variant, uint8_t *eeprom, size_t eeprom_size, - const struct controller *controller); + const struct controller *controller, + FILE* m64_fp); int read_pif_rom_and_ram(void *opaque, uint32_t address, uint32_t *word); int write_pif_rom_and_ram(void *opaque, uint32_t address, uint32_t word, uint32_t dqm);