Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
9837 | turbocat | 1 | // DGen/SDL 1.17 |
2 | // by Joe Groff |
||
3 | // Read LICENSE for copyright etc., but if you've seen one BSDish license, |
||
4 | // you've seen them all ;) |
||
5 | |||
6 | #include |
||
7 | #include |
||
8 | #include |
||
9 | #include |
||
10 | #include |
||
11 | #include |
||
12 | #include |
||
13 | #include |
||
14 | #include |
||
15 | #include |
||
16 | |||
17 | #ifdef __MINGW32__ |
||
18 | #include |
||
19 | #include |
||
20 | #endif |
||
21 | |||
22 | #define IS_MAIN_CPP |
||
23 | #include "system.h" |
||
24 | #include "md.h" |
||
25 | #include "pd.h" |
||
26 | #include "pd-defs.h" |
||
27 | #include "rc.h" |
||
28 | #include "rc-vars.h" |
||
29 | |||
30 | #ifdef __BEOS__ |
||
31 | #include |
||
32 | #endif |
||
33 | |||
34 | #ifdef __MINGW32__ |
||
35 | static long dgen_mingw_detach = 1; |
||
36 | #endif |
||
37 | |||
38 | // Defined in ras.cpp, and set to true if the Genesis palette's changed. |
||
39 | extern int pal_dirty; |
||
40 | |||
41 | FILE *debug_log = NULL; |
||
42 | |||
43 | // Do a demo frame, if active |
||
44 | enum demo_status { |
||
45 | DEMO_OFF, |
||
46 | DEMO_RECORD, |
||
47 | DEMO_PLAY |
||
48 | }; |
||
49 | |||
50 | static inline void do_demo(md& megad, FILE* demo, enum demo_status* status) |
||
51 | { |
||
52 | uint32_t pad[2]; |
||
53 | |||
54 | switch (*status) { |
||
55 | case DEMO_OFF: |
||
56 | break; |
||
57 | case DEMO_RECORD: |
||
58 | pad[0] = h2be32(megad.pad[0]); |
||
59 | pad[1] = h2be32(megad.pad[1]); |
||
60 | fwrite(&pad, sizeof(pad), 1, demo); |
||
61 | break; |
||
62 | case DEMO_PLAY: |
||
63 | if (fread(&pad, sizeof(pad), 1, demo) == 1) { |
||
64 | megad.pad[0] = be2h32(pad[0]); |
||
65 | megad.pad[1] = be2h32(pad[1]); |
||
66 | } |
||
67 | else { |
||
68 | if (feof(demo)) |
||
69 | pd_message("Demo finished."); |
||
70 | else |
||
71 | pd_message("Demo finished (read error)."); |
||
72 | *status = DEMO_OFF; |
||
73 | } |
||
74 | break; |
||
75 | } |
||
76 | } |
||
77 | |||
78 | // Temporary garbage can string :) |
||
79 | static char temp[65536] = ""; |
||
80 | |||
81 | // Show help and exit with code 2 |
||
82 | static void help() |
||
83 | { |
||
84 | printf( |
||
85 | "DGen/SDL v"VER"\n" |
||
86 | "Usage: dgen [options] [romname [...]]\n\n" |
||
87 | "Where options are:\n" |
||
88 | " -v Print version number and exit.\n" |
||
89 | " -r RCFILE Read in the file RCFILE after parsing\n" |
||
90 | " $HOME/.dgen/dgenrc.\n" |
||
91 | " -n USEC Causes DGen to sleep USEC microseconds per frame, to\n" |
||
92 | " be nice to other processes.\n" |
||
93 | " -p CODE,CODE... Takes a comma-delimited list of Game Genie (ABCD-EFGH)\n" |
||
94 | " or Hex (123456:ABCD) codes to patch the ROM with.\n" |
||
95 | " -R (J|X|U|E| ) Force emulator region. Affects vertical resolution,\n" |
||
96 | " frame rate and ROM operation.\n" |
||
97 | " J: Japan (NTSC), X: Japan (PAL), U: America (NTSC)\n" |
||
98 | " E: Europe (PAL), ' ': auto (default).\n" |
||
99 | " -N Use NTSC mode (60Hz).\n" |
||
100 | " -P Use PAL mode (50Hz).\n" |
||
101 | " -H HZ Use a custom frame rate.\n" |
||
102 | " -d DEMONAME Record a demo of the game you are playing.\n" |
||
103 | " -D DEMONAME Play back a previously recorded demo.\n" |
||
104 | " -s SLOT Load the saved state from the given slot at startup.\n" |
||
105 | #ifdef __MINGW32__ |
||
106 | " -m Do not detach from console.\n" |
||
107 | #endif |
||
108 | ); |
||
109 | // Display platform-specific options |
||
110 | pd_help(); |
||
111 | exit(2); |
||
112 | } |
||
113 | |||
114 | // Save/load states |
||
115 | // It is externed from your implementation to change the current slot |
||
116 | // (I know this is a hack :) |
||
117 | int slot = 0; |
||
118 | void md_save(md& megad) |
||
119 | { |
||
120 | FILE *save; |
||
121 | char file[64]; |
||
122 | |||
123 | if (!megad.plugged) { |
||
124 | pd_message("Cannot save state when no ROM is loaded."); |
||
125 | return; |
||
126 | } |
||
127 | if (((size_t)snprintf(file, |
||
128 | sizeof(file), |
||
129 | "%s.gs%d", |
||
130 | megad.romname, |
||
131 | slot) >= sizeof(file)) || |
||
132 | ((save = dgen_fopen("saves", file, DGEN_WRITE)) == NULL)) { |
||
133 | snprintf(temp, sizeof(temp), |
||
134 | "Couldn't save state to slot %d!", slot); |
||
135 | pd_message(temp); |
||
136 | return; |
||
137 | } |
||
138 | megad.export_gst(save); |
||
139 | fclose(save); |
||
140 | snprintf(temp, sizeof(temp), "Saved state to slot %d.", slot); |
||
141 | pd_message(temp); |
||
142 | } |
||
143 | |||
144 | void md_load(md& megad) |
||
145 | { |
||
146 | FILE *load; |
||
147 | char file[64]; |
||
148 | |||
149 | if (!megad.plugged) { |
||
150 | pd_message("Cannot restore state when no ROM is loaded."); |
||
151 | return; |
||
152 | } |
||
153 | if (((size_t)snprintf(file, |
||
154 | sizeof(file), |
||
155 | "%s.gs%d", |
||
156 | megad.romname, |
||
157 | slot) >= sizeof(file)) || |
||
158 | ((load = dgen_fopen("saves", file, DGEN_READ)) == NULL)) { |
||
159 | snprintf(temp, sizeof(temp), |
||
160 | "Couldn't load state from slot %d!", slot); |
||
161 | pd_message(temp); |
||
162 | return; |
||
163 | } |
||
164 | megad.import_gst(load); |
||
165 | fclose(load); |
||
166 | snprintf(temp, sizeof(temp), "Loaded state from slot %d.", slot); |
||
167 | pd_message(temp); |
||
168 | } |
||
169 | |||
170 | // Load/save states from file |
||
171 | void ram_save(md& megad) |
||
172 | { |
||
173 | FILE *save; |
||
174 | int ret; |
||
175 | |||
176 | if (!megad.has_save_ram()) |
||
177 | return; |
||
178 | save = dgen_fopen("ram", megad.romname, DGEN_WRITE); |
||
179 | if (save == NULL) |
||
180 | goto fail; |
||
181 | ret = megad.put_save_ram(save); |
||
182 | fclose(save); |
||
183 | if (ret == 0) |
||
184 | return; |
||
185 | fail: |
||
186 | fprintf(stderr, "Couldn't save battery RAM to `%s'\n", megad.romname); |
||
187 | } |
||
188 | |||
189 | void ram_load(md& megad) |
||
190 | { |
||
191 | FILE *load; |
||
192 | int ret; |
||
193 | |||
194 | if (!megad.has_save_ram()) |
||
195 | return; |
||
196 | load = dgen_fopen("ram", megad.romname, DGEN_READ); |
||
197 | if (load == NULL) |
||
198 | goto fail; |
||
199 | ret = megad.get_save_ram(load); |
||
200 | fclose(load); |
||
201 | if (ret == 0) |
||
202 | return; |
||
203 | fail: |
||
204 | fprintf(stderr, "Couldn't load battery RAM from `%s'\n", |
||
205 | megad.romname); |
||
206 | } |
||
207 | |||
208 | int main(int argc, char *argv[]) |
||
209 | { |
||
210 | int c = 0, stop = 0, usec = 0, start_slot = -1; |
||
211 | unsigned long frames, frames_old, fps; |
||
212 | char *patches = NULL, *rom = NULL; |
||
213 | unsigned long oldclk, newclk, startclk, fpsclk; |
||
214 | FILE *file = NULL; |
||
215 | enum demo_status demo_status = DEMO_OFF; |
||
216 | unsigned int samples; |
||
217 | class md *megad; |
||
218 | bool first = true; |
||
219 | bool forced_hz = false; |
||
220 | bool forced_pal = false; |
||
221 | |||
222 | // Parse the RC file |
||
223 | if ((dgen_autoconf) && |
||
224 | ((file = dgen_fopen_autorc(DGEN_READ)) != NULL)) { |
||
225 | parse_rc(file, DGEN_AUTORC); |
||
226 | fclose(file); |
||
227 | } |
||
228 | if ((file = dgen_fopen_rc(DGEN_READ)) != NULL) { |
||
229 | parse_rc(file, DGEN_RC); |
||
230 | fclose(file); |
||
231 | file = NULL; |
||
232 | pd_rc(); |
||
233 | } |
||
234 | else if (errno == ENOENT) { |
||
235 | if ((file = dgen_fopen_rc(DGEN_APPEND)) != NULL) { |
||
236 | fprintf(file, |
||
237 | "# DGen " VER " configuration file.\n" |
||
238 | "# See dgenrc(5) for more information.\n"); |
||
239 | fclose(file); |
||
240 | file = NULL; |
||
241 | } |
||
242 | } |
||
243 | else |
||
244 | fprintf(stderr, "rc: %s: %s\n", DGEN_RC, strerror(errno)); |
||
245 | |||
246 | // Check all our options |
||
247 | snprintf(temp, sizeof(temp), "%s%s", |
||
248 | #ifdef __MINGW32__ |
||
249 | "m" |
||
250 | #endif |
||
251 | "s:hvr:n:p:R:NPH:d:D:", |
||
252 | pd_options); |
||
253 | while((c = getopt(argc, argv, temp)) != EOF) |
||
254 | { |
||
255 | switch(c) |
||
256 | { |
||
257 | case 'v': |
||
258 | // Show version and exit |
||
259 | printf("DGen/SDL version "VER"\n"); |
||
260 | return 0; |
||
261 | case 'r': |
||
262 | // Parse another RC file or stdin |
||
263 | if ((strcmp(optarg, "-") == 0) || |
||
264 | ((file = dgen_fopen(NULL, optarg, |
||
265 | (DGEN_READ | DGEN_CURRENT))) != NULL)) { |
||
266 | if (file == NULL) |
||
267 | parse_rc(stdin, "(stdin)"); |
||
268 | else { |
||
269 | parse_rc(file, optarg); |
||
270 | fclose(file); |
||
271 | file = NULL; |
||
272 | } |
||
273 | pd_rc(); |
||
274 | } |
||
275 | else |
||
276 | fprintf(stderr, "rc: %s: %s\n", optarg, strerror(errno)); |
||
277 | break; |
||
278 | case 'n': |
||
279 | // Sleep for n microseconds |
||
280 | dgen_nice = atoi(optarg); |
||
281 | break; |
||
282 | case 'p': |
||
283 | // Game Genie patches |
||
284 | patches = optarg; |
||
285 | break; |
||
286 | case 'R': |
||
287 | // Region selection |
||
288 | if (strlen(optarg) != 1) |
||
289 | goto bad_region; |
||
290 | switch (optarg[0] | 0x20) { |
||
291 | case 'j': |
||
292 | case 'x': |
||
293 | case 'u': |
||
294 | case 'e': |
||
295 | case ' ': |
||
296 | break; |
||
297 | default: |
||
298 | bad_region: |
||
299 | fprintf(stderr, "main: invalid region `%s'.\n", |
||
300 | optarg); |
||
301 | return EXIT_FAILURE; |
||
302 | } |
||
303 | dgen_region = (optarg[0] & ~(0x20)); |
||
304 | // Override PAL and Hz settings if region is specified. |
||
305 | if (dgen_region) { |
||
306 | int hz; |
||
307 | int pal; |
||
308 | |||
309 | md::region_info(dgen_region, &pal, &hz, 0, 0, 0); |
||
310 | dgen_hz = hz; |
||
311 | dgen_pal = pal; |
||
312 | } |
||
313 | forced_pal = false; |
||
314 | forced_hz = false; |
||
315 | break; |
||
316 | case 'N': |
||
317 | // NTSC mode |
||
318 | dgen_hz = NTSC_HZ; |
||
319 | dgen_pal = 0; |
||
320 | forced_pal = true; |
||
321 | break; |
||
322 | case 'P': |
||
323 | // PAL mode |
||
324 | dgen_hz = PAL_HZ; |
||
325 | dgen_pal = 1; |
||
326 | forced_pal = true; |
||
327 | break; |
||
328 | case 'H': |
||
329 | // Custom frame rate |
||
330 | dgen_hz = atoi(optarg); |
||
331 | if ((dgen_hz <= 0) || (dgen_hz > 1000)) { |
||
332 | fprintf(stderr, "main: invalid frame rate (%ld).\n", |
||
333 | (long)dgen_hz); |
||
334 | dgen_hz = (dgen_pal ? 50 : 60); |
||
335 | forced_hz = false; |
||
336 | } |
||
337 | else |
||
338 | forced_hz = true; |
||
339 | break; |
||
340 | #ifdef __MINGW32__ |
||
341 | case 'm': |
||
342 | dgen_mingw_detach = 0; |
||
343 | break; |
||
344 | #endif |
||
345 | case 'd': |
||
346 | // Record demo |
||
347 | if(file) |
||
348 | { |
||
349 | fprintf(stderr,"main: Can't record and play at the same time!\n"); |
||
350 | break; |
||
351 | } |
||
352 | if(!(file = dgen_fopen("demos", optarg, DGEN_WRITE))) |
||
353 | { |
||
354 | fprintf(stderr, "main: Can't record demo file %s!\n", optarg); |
||
355 | break; |
||
356 | } |
||
357 | demo_status = DEMO_RECORD; |
||
358 | break; |
||
359 | case 'D': |
||
360 | // Play demo |
||
361 | if(file) |
||
362 | { |
||
363 | fprintf(stderr,"main: Can't record and play at the same time!\n"); |
||
364 | break; |
||
365 | } |
||
366 | if(!(file = dgen_fopen("demos", optarg, (DGEN_READ | DGEN_CURRENT)))) |
||
367 | { |
||
368 | fprintf(stderr, "main: Can't play demo file %s!\n", optarg); |
||
369 | break; |
||
370 | } |
||
371 | demo_status = DEMO_PLAY; |
||
372 | break; |
||
373 | case '?': // Bad option! |
||
374 | case 'h': // A cry for help :) |
||
375 | help(); |
||
376 | case 's': |
||
377 | // Pick a savestate to autoload |
||
378 | start_slot = atoi(optarg); |
||
379 | break; |
||
380 | default: |
||
381 | // Pass it on to platform-dependent stuff |
||
382 | pd_option(c, optarg); |
||
383 | break; |
||
384 | } |
||
385 | } |
||
386 | |||
387 | #ifdef __BEOS__ |
||
388 | // BeOS snooze() sleeps in milliseconds, not microseconds |
||
389 | dgen_nice /= 1000; |
||
390 | #endif |
||
391 | |||
392 | #ifdef __MINGW32__ |
||
393 | if (dgen_mingw_detach) { |
||
394 | FILE *cons; |
||
395 | |||
396 | fprintf(stderr, |
||
397 | "main: Detaching from console, use -m to prevent" |
||
398 | " this.\n"); |
||
399 | // Console isn't needed anymore. Redirect output to log file. |
||
400 | cons = dgen_fopen(NULL, "log.txt", (DGEN_WRITE | DGEN_TEXT)); |
||
401 | if (cons != NULL) { |
||
402 | fflush(stdout); |
||
403 | fflush(stderr); |
||
404 | dup2(fileno(cons), fileno(stdout)); |
||
405 | dup2(fileno(cons), fileno(stderr)); |
||
406 | fclose(cons); |
||
407 | setvbuf(stdout, NULL, _IONBF, 0); |
||
408 | setvbuf(stderr, NULL, _IONBF, 0); |
||
409 | cons = NULL; |
||
410 | } |
||
411 | FreeConsole(); |
||
412 | } |
||
413 | #endif |
||
414 | |||
415 | // Initialize the platform-dependent stuff. |
||
416 | if (!pd_graphics_init(dgen_sound, dgen_pal, dgen_hz)) |
||
417 | { |
||
418 | fprintf(stderr, "main: Couldn't initialize graphics!\n"); |
||
419 | return 1; |
||
420 | } |
||
421 | if(dgen_sound) |
||
422 | { |
||
423 | long rate = dgen_soundrate; |
||
424 | |||
425 | if (dgen_soundsegs < 0) |
||
426 | dgen_soundsegs = 0; |
||
427 | samples = (dgen_soundsegs * (rate / dgen_hz)); |
||
428 | pd_sound_init(rate, samples); |
||
429 | } |
||
430 | |||
431 | rom = argv[optind]; |
||
432 | // Create the megadrive object. |
||
433 | megad = new md(dgen_pal, dgen_region); |
||
434 | if ((megad == NULL) || (!megad->okay())) { |
||
435 | fprintf(stderr, "main: Mega Drive initialization failed.\n"); |
||
436 | goto clean_up; |
||
437 | } |
||
438 | next_rom: |
||
439 | // Load the requested ROM. |
||
440 | if (rom != NULL) { |
||
441 | if (megad->load(rom)) { |
||
442 | pd_message("Unable to load \"%s\".", rom); |
||
443 | if ((first) && ((optind + 1) == argc)) |
||
444 | goto clean_up; |
||
445 | } |
||
446 | else |
||
447 | pd_message("Loaded \"%s\".", rom); |
||
448 | } |
||
449 | else |
||
450 | pd_message("No cartridge."); |
||
451 | first = false; |
||
452 | // Set untouched pads. |
||
453 | megad->pad[0] = MD_PAD_UNTOUCHED; |
||
454 | megad->pad[1] = MD_PAD_UNTOUCHED; |
||
455 | #ifdef WITH_JOYSTICK |
||
456 | if (dgen_joystick) |
||
457 | megad->init_joysticks(); |
||
458 | #endif |
||
459 | // Load patches, if given. |
||
460 | if (patches) { |
||
461 | printf("main: Using patch codes \"%s\".\n", patches); |
||
462 | megad->patch(patches, NULL, NULL, NULL); |
||
463 | // Use them only once. |
||
464 | patches = NULL; |
||
465 | } |
||
466 | // Reset |
||
467 | megad->reset(); |
||
468 | |||
469 | // Automatic region settings from ROM header. |
||
470 | if (!dgen_region) { |
||
471 | uint8_t c = megad->region_guess(); |
||
472 | int hz; |
||
473 | int pal; |
||
474 | |||
475 | md::region_info(c, &pal, &hz, 0, 0, 0); |
||
476 | if (forced_hz) |
||
477 | hz = dgen_hz; |
||
478 | if (forced_pal) |
||
479 | pal = dgen_pal; |
||
480 | if ((hz != dgen_hz) || (pal != dgen_pal) || |
||
481 | (c != megad->region)) { |
||
482 | megad->region = c; |
||
483 | dgen_hz = hz; |
||
484 | dgen_pal = pal; |
||
485 | printf("main: reconfiguring for region \"%c\": " |
||
486 | "%dHz (%s)\n", c, hz, (pal ? "PAL" : "NTSC")); |
||
487 | pd_graphics_reinit(dgen_sound, dgen_pal, dgen_hz); |
||
488 | if (dgen_sound) { |
||
489 | long rate = dgen_soundrate; |
||
490 | |||
491 | pd_sound_deinit(); |
||
492 | samples = (dgen_soundsegs * (rate / dgen_hz)); |
||
493 | pd_sound_init(rate, samples); |
||
494 | } |
||
495 | megad->pal = pal; |
||
496 | megad->init_pal(); |
||
497 | megad->init_sound(); |
||
498 | } |
||
499 | } |
||
500 | |||
501 | // Load up save RAM |
||
502 | ram_load(*megad); |
||
503 | // If -s option was given, load the requested slot |
||
504 | if (start_slot >= 0) { |
||
505 | slot = start_slot; |
||
506 | md_load(*megad); |
||
507 | } |
||
508 | // If autoload is on, load save state 0 |
||
509 | else if (dgen_autoload) { |
||
510 | slot = 0; |
||
511 | md_load(*megad); |
||
512 | } |
||
513 | |||
514 | // Start the timing refs |
||
515 | startclk = pd_usecs(); |
||
516 | oldclk = startclk; |
||
517 | fpsclk = startclk; |
||
518 | |||
519 | // Show cartridge header |
||
520 | if (dgen_show_carthead) |
||
521 | pd_show_carthead(*megad); |
||
522 | |||
523 | // Go around, and around, and around, and around... ;) |
||
524 | frames = 0; |
||
525 | frames_old = 0; |
||
526 | fps = 0; |
||
527 | while (!stop) { |
||
528 | const unsigned int usec_frame = (1000000 / dgen_hz); |
||
529 | unsigned long tmp; |
||
530 | int frames_todo; |
||
531 | |||
532 | newclk = pd_usecs(); |
||
533 | |||
534 | if (pd_stopped()) { |
||
535 | // Fix FPS count. |
||
536 | tmp = (newclk - oldclk); |
||
537 | startclk += tmp; |
||
538 | fpsclk += tmp; |
||
539 | oldclk = newclk; |
||
540 | } |
||
541 | |||
542 | // Update FPS count. |
||
543 | tmp = ((newclk - fpsclk) & 0x3fffff); |
||
544 | if (tmp >= 1000000) { |
||
545 | fpsclk = newclk; |
||
546 | if (frames_old > frames) |
||
547 | fps = (frames_old - frames); |
||
548 | else |
||
549 | fps = (frames - frames_old); |
||
550 | frames_old = frames; |
||
551 | } |
||
552 | |||
553 | if (dgen_frameskip == 0) { |
||
554 | // Check whether megad->one_frame() must be called. |
||
555 | if (pd_freeze) |
||
556 | goto frozen; |
||
557 | goto do_not_skip; |
||
558 | } |
||
559 | |||
560 | // Measure how many frames to do this round. |
||
561 | usec += ((newclk - oldclk) & 0x3fffff); // no more than 4 secs |
||
562 | frames_todo = (usec / usec_frame); |
||
563 | usec %= usec_frame; |
||
564 | oldclk = newclk; |
||
565 | |||
566 | if (frames_todo == 0) { |
||
567 | // No frame to do yet, relax the CPU until next one. |
||
568 | tmp = (usec_frame - usec); |
||
569 | if (tmp > 1000) { |
||
570 | // Never sleep for longer than the 50Hz value |
||
571 | // so events are checked often enough. |
||
572 | if (tmp > (1000000 / 50)) |
||
573 | tmp = (1000000 / 50); |
||
574 | tmp -= 1000; |
||
575 | #ifdef __BEOS__ |
||
576 | snooze(tmp / 1000); |
||
577 | #else |
||
578 | usleep(tmp); |
||
579 | #endif |
||
580 | } |
||
581 | } |
||
582 | else { |
||
583 | // Check whether megad->one_frame() must be called. |
||
584 | if (pd_freeze) |
||
585 | goto frozen; |
||
586 | |||
587 | // Draw frames. |
||
588 | while (frames_todo != 1) { |
||
589 | do_demo(*megad, file, &demo_status); |
||
590 | if (dgen_sound) { |
||
591 | // Skip this frame, keep sound going. |
||
592 | megad->one_frame(NULL, NULL, &sndi); |
||
593 | pd_sound_write(); |
||
594 | } |
||
595 | else |
||
596 | megad->one_frame(NULL, NULL, NULL); |
||
597 | --frames_todo; |
||
598 | stop |= (pd_handle_events(*megad) ^ 1); |
||
599 | } |
||
600 | --frames_todo; |
||
601 | do_not_skip: |
||
602 | do_demo(*megad, file, &demo_status); |
||
603 | if (dgen_sound) { |
||
604 | megad->one_frame(&mdscr, mdpal, &sndi); |
||
605 | pd_sound_write(); |
||
606 | } |
||
607 | else |
||
608 | megad->one_frame(&mdscr, mdpal, NULL); |
||
609 | frozen: |
||
610 | if ((mdpal) && (pal_dirty)) { |
||
611 | pd_graphics_palette_update(); |
||
612 | pal_dirty = 0; |
||
613 | } |
||
614 | pd_graphics_update(megad->plugged); |
||
615 | ++frames; |
||
616 | } |
||
617 | |||
618 | stop |= (pd_handle_events(*megad) ^ 1); |
||
619 | |||
620 | if (dgen_nice) { |
||
621 | #ifdef __BEOS__ |
||
622 | snooze(dgen_nice); |
||
623 | #else |
||
624 | usleep(dgen_nice); |
||
625 | #endif |
||
626 | } |
||
627 | } |
||
628 | |||
629 | #ifdef WITH_JOYSTICK |
||
630 | if (dgen_joystick) |
||
631 | megad->deinit_joysticks(); |
||
632 | #endif |
||
633 | |||
634 | // Print fps |
||
635 | fpsclk = ((pd_usecs() - startclk) / 1000000); |
||
636 | if (fpsclk == 0) |
||
637 | fpsclk = 1; |
||
638 | #ifdef WITH_DEBUGGER |
||
639 | megad->debug_leave(); |
||
640 | #endif |
||
641 | printf("%lu frames per second (average %lu, optimal %ld)\n", |
||
642 | fps, (frames / fpsclk), (long)dgen_hz); |
||
643 | |||
644 | ram_save(*megad); |
||
645 | if (dgen_autosave) { |
||
646 | slot = 0; |
||
647 | md_save(*megad); |
||
648 | } |
||
649 | megad->unplug(); |
||
650 | if (file) { |
||
651 | fclose(file); |
||
652 | file = NULL; |
||
653 | } |
||
654 | if ((++optind) < argc) { |
||
655 | rom = argv[optind]; |
||
656 | stop = 0; |
||
657 | goto next_rom; |
||
658 | } |
||
659 | clean_up: |
||
660 | // Cleanup |
||
661 | delete megad; |
||
662 | pd_sound_deinit(); |
||
663 | pd_quit(); |
||
664 | // Save configuration. |
||
665 | if (dgen_autoconf) { |
||
666 | if ((file = dgen_fopen_autorc(DGEN_WRITE)) == NULL) |
||
667 | fputs("main: can't write " DGEN_AUTORC ".\n", stderr); |
||
668 | else { |
||
669 | fprintf(file, |
||
670 | "# DGen/SDL v" VER "\n" |
||
671 | "# This file is automatically overwritten.\n" |
||
672 | "\n"); |
||
673 | dump_rc(file); |
||
674 | fclose(file); |
||
675 | file = NULL; |
||
676 | } |
||
677 | } |
||
678 | // Come back anytime :) |
||
679 | return 0; |
||
680 | }>>=> |