|
|
1.1 ! root 1: /* Generator is (c) James Ponder, 1997-2001 http://www.squish.net/generator/ */ ! 2: ! 3: /* generic 640x480 console mode */ ! 4: ! 5: /* I call the first field the even field and the second field the odd field, ! 6: sorry - I counted lines from 0 when I wrote the code... strictly speaking ! 7: this is confusing... (it confuses me) */ ! 8: ! 9: #include <sys/types.h> ! 10: #include <sys/stat.h> ! 11: #include <fcntl.h> ! 12: #include <stdlib.h> ! 13: #include <stdio.h> ! 14: #include <stdarg.h> ! 15: #include <time.h> ! 16: #include <string.h> ! 17: #include <unistd.h> ! 18: #include <errno.h> ! 19: ! 20: #include "generator.h" ! 21: #include "snprintf.h" ! 22: ! 23: #include "cpu68k.h" ! 24: #include "cpuz80.h" ! 25: #include "ui.h" ! 26: #include "vdp.h" ! 27: #include "event.h" ! 28: #include "gensound.h" ! 29: #include "mem68k.h" ! 30: #include "logo.h" ! 31: #include "font.h" ! 32: #include "uip.h" ! 33: #include "ui-console.h" ! 34: #include "state.h" ! 35: ! 36: #define UI_LOGLINESIZE 128 ! 37: #define UI_LOGLINES 64 ! 38: ! 39: uint32 ui_fkeys = 0; ! 40: ! 41: uint8 ui_vdpsimple = 0; /* 0=raster, 1=cell based plotter */ ! 42: uint8 ui_clearnext = 0; /* flag indicating redraw required */ ! 43: uint8 ui_fullscreen = 0; /* does the user want full screen or not */ ! 44: uint8 ui_info = 1; /* does the user want info onscreen or not */ ! 45: uint8 ui_vsync = 0; /* does the user want us to wait for vsync */ ! 46: t_interlace ui_interlace = DEINTERLACE_WEAVEFILTER; /* type of de-interlace */ ! 47: ! 48: /*** forward reference declarations ***/ ! 49: ! 50: static void ui_usage(void); ! 51: static void ui_plotline(unsigned int line, uint8 *gfx); ! 52: void ui_exithandler(void); ! 53: void ui_newframe(void); ! 54: void ui_convertdata(uint8 *indata, uint16 *outdata, unsigned int pixels); ! 55: void ui_plotsprite_acorn(uint16 *logo, uint16 width, uint16 height, ! 56: uint16 x, uint16 y); ! 57: int ui_unpackfont(void); ! 58: uint16 ui_plotstring(const char *text, uint16 xpos, uint16 ypos); ! 59: uint16 ui_plotint2(uint8 num, uint16 xpos, uint16 ypos); ! 60: void ui_plotsettings(void); ! 61: void ui_drawbox(uint16 colour, uint16 x, uint16 y, uint16 width, ! 62: uint16 height); ! 63: void ui_rendertoscreen(void); ! 64: void ui_render_x1(uint16 *linedata, uint16 *olddata, uint8 *screen, ! 65: unsigned int linewidth, unsigned int pixels); ! 66: void ui_render_x2(uint16 *linedata, uint16 *olddata, uint8 *screen, ! 67: unsigned int linewidth, unsigned int pixels); ! 68: void ui_render_x2h(uint16 *linedata, uint16 *olddata, uint8 *screen, ! 69: unsigned int linewidth, unsigned int pixels); ! 70: void ui_irender_weavefilter(uint16 *evendata, uint16 *odddata, uint8 *screen, ! 71: unsigned int linewidth, unsigned int pixels); ! 72: void ui_basicbits(void); ! 73: void ui_licensescreen(void); ! 74: void ui_imagescreen(void); ! 75: void ui_imagescreen_main(void); ! 76: void ui_statescreen(void); ! 77: void ui_statescreen_main(void); ! 78: int ui_statescreen_loadsavestate(int save); ! 79: void ui_resetscreen(void); ! 80: void ui_resetscreen_main(void); ! 81: int ui_saveimage(const char *type, char *filename, int buflen, ! 82: int *xsize, int *ysize); ! 83: int ui_setcolourbits(const char *str); ! 84: ! 85: /* we store up log lines and dump them right at the end for allegro */ ! 86: #ifdef ALLEGRO ! 87: void ui_printlog(void); ! 88: #endif ! 89: ! 90: /*** static variables ***/ ! 91: ! 92: static uint8 ui_vga = 0; /* flag for whether in VGA more or not */ ! 93: static uint8 ui_frameskip = 0; /* 0 for dynamic */ ! 94: static uint8 ui_actualskip = 0; /* the last skip we did (1..) */ ! 95: static uint8 ui_state = 0; /* 0=stop, 1=paused, 2=play */ ! 96: static uint32 ui_palcache[192]; ! 97: static char *ui_initload = NULL; /* filename to load on init */ ! 98: static char ui_loglines[UI_LOGLINES][UI_LOGLINESIZE]; ! 99: static uint32 ui_logline = 0; ! 100: static uint8 ui_plotfield = 0; /* flag indicating plotting this field */ ! 101: static uint8 ui_plotprevfield = 0; /* did we plot the previous field? */ ! 102: static uint16 *ui_font; /* unpacked font */ ! 103: static uint8 bigbuffer[8192]; /* stupid no-vsnprintf platforms */ ! 104: static uint16 ui_logcount = 0; /* log counter */ ! 105: static t_uipinfo ui_uipinfo; /* uipinfo filled in by uip 'sub-system' */ ! 106: static uint16 *ui_screen0; /* pointer to screen block for bank 0 */ ! 107: static uint16 *ui_screen1; /* pointer to screen block for bank 1 */ ! 108: static uint16 *ui_newscreen; /* pointer to new screen block */ ! 109: static int ui_saverom; /* flag to save rom and quit */ ! 110: ! 111: static uint16 ui_screen[3][320*240]; /* screen buffers */ ! 112: ! 113: /*** Program entry point ***/ ! 114: ! 115: int ui_init(int argc, char *argv[]) ! 116: { ! 117: int i; ! 118: int ch; ! 119: ! 120: for(i = 0; i < UI_LOGLINES; i++) ! 121: ui_loglines[i][0] = '\0'; ! 122: if (ui_unpackfont() == -1) { ! 123: fprintf(stderr, "Failed to unpack font, out of memory?\n"); ! 124: return 1; ! 125: } ! 126: while ((ch = getopt(argc, argv, "i:c:w:f:sd:v:l:")) != -1) { ! 127: switch (ch) { ! 128: case 'c': /* set colour bit positions */ ! 129: if (ui_setcolourbits(optarg)) { ! 130: fprintf(stderr, "-c option not understood, must be " ! 131: "'red,green,blue'\n"); ! 132: return 1; ! 133: } ! 134: break; ! 135: case 'i': /* de-interlacing mode */ ! 136: if (!strcasecmp(optarg, "bob")) { ! 137: ui_interlace = DEINTERLACE_BOB; ! 138: } else if (!strcasecmp(optarg, "weave")) { ! 139: ui_interlace = DEINTERLACE_WEAVE; ! 140: } else if (!strcasecmp(optarg, "weave-filter")) { ! 141: ui_interlace = DEINTERLACE_WEAVEFILTER; ! 142: } else { ! 143: fprintf(stderr, "-i option not understood, must be " ! 144: "bob|weave|weave-filter\n"); ! 145: return 1; ! 146: } ! 147: break; ! 148: case 'd': /* enable sound debug mode */ ! 149: /* re-write this to cope with comma separated items later */ ! 150: if (!strcasecmp(optarg, "sound")) ! 151: sound_debug = 1; ! 152: break; ! 153: case 's': /* save raw format rom */ ! 154: ui_saverom = 1; ! 155: break; ! 156: case 'l': /* set min fields / audio latency */ ! 157: sound_minfields = atoi(optarg); ! 158: break; ! 159: case 'f': /* set max fields / audio fragments */ ! 160: sound_maxfields = atoi(optarg); ! 161: break; ! 162: case 'k': /* set frame skip */ ! 163: ui_frameskip = atoi(optarg); ! 164: break; ! 165: case 'v': /* set log verbosity level */ ! 166: gen_loglevel = atoi(optarg); ! 167: break; ! 168: case 'w': /* saved game work dir */ ! 169: chdir(optarg); /* for the moment this will do */ ! 170: break; ! 171: case '?': ! 172: default: ! 173: ui_usage(); ! 174: } ! 175: } ! 176: argc-= optind; ! 177: argv+= optind; ! 178: ! 179: if (argc < 1 || argc > 3) ! 180: ui_usage(); ! 181: if ((ui_initload = malloc(strlen(argv[0])+1)) == NULL) { ! 182: fprintf(stderr, "Out of memory\n"); ! 183: return 1; ! 184: } ! 185: strcpy(ui_initload, argv[0]); ! 186: ! 187: if (atexit(ui_exithandler) == -1) { ! 188: LOG_CRITICAL(("Failed to set exit handler")); ! 189: return 1; ! 190: } ! 191: if (uip_init(&ui_uipinfo)) { ! 192: LOG_CRITICAL(("Failed to initialise platform dependent UI")); ! 193: return 1; ! 194: } ! 195: /* ui_newscreen is where the emulation data is rendered to - it is ! 196: then compared with ui_screen0 or ui_screen1 depending on which ! 197: screen bank it is being written to, and the delta changes are sent ! 198: to screen memory. The ui_screenX and ui_newscreen pointers are then ! 199: switched, and the next frame/field begins... */ ! 200: memset(ui_screen[0], 0, sizeof(ui_screen[0])); ! 201: memset(ui_screen[1], 0, sizeof(ui_screen[1])); ! 202: ui_screen0 = ui_screen[0]; ! 203: ui_screen1 = ui_screen[1]; ! 204: ui_newscreen = ui_screen[2]; ! 205: return 0; ! 206: } ! 207: ! 208: void ui_usage(void) ! 209: { ! 210: fprintf(stderr, "Generator is (c) James Ponder 1997-2001, all rights " ! 211: "reserved. " VERSTRING "\n\n"); ! 212: fprintf(stderr, "generator [options] <rom>\n\n"); ! 213: fprintf(stderr, " -v <verbose level> can be: 0 = none, 1 = critical, " ! 214: "2 = normal, 3 = verbose\n"); ! 215: fprintf(stderr, " -d sound - turns on debug mode for sound\n"); ! 216: fprintf(stderr, " -l <sound latency> is the number of video fields worth " ! 217: "of sound to\n try to keep buffered (default 5)\n"); ! 218: fprintf(stderr, " -f <sound fragments> is the number of video fields worth " ! 219: "of sound to\n allow buffered (approx) (default 10)\n"); ! 220: fprintf(stderr, " -w <work dir> indicates where saved games are stored " ! 221: "(default is current dir)\n"); ! 222: fprintf(stderr, " -c [<r>,<g>,<b>] sets the colour bit positions of where " ! 223: "red, green and blue\n 5-bit values should be shifted " ! 224: "to (default 10,5,0 for 15-bit modes)\n"); ! 225: fprintf(stderr, " -i <mode> selects de-interlace mode, one of: bob " ! 226: "weave weave-filter\n"); ! 227: fprintf(stderr, " -k <x> forces the frame step (1=all frames, 2=every other," ! 228: " etc.)\n"); ! 229: fprintf(stderr, " -s will save the ROM to the work directory in raw " ! 230: "format\n\n"); ! 231: fprintf(stderr, " ROM types supported: .rom or .smd interleaved " ! 232: "(autodetected)\n"); ! 233: fprintf(stderr, " Sound latency will be kept between -l and -a values. " ! 234: "If you are having sound\n problems try -l 20 -f 30\n"); ! 235: exit(1); ! 236: } ! 237: ! 238: #ifdef ALLEGRO ! 239: void ui_printlog(void) ! 240: { ! 241: unsigned int i; ! 242: char *p; ! 243: ! 244: printf("**** Last lines logged:\n"); ! 245: for (i = ui_logline; i < (UI_LOGLINES+ui_logline); i++) { ! 246: p = ui_loglines[(i < UI_LOGLINES) ? i : (i-UI_LOGLINES)]; ! 247: if (*p) ! 248: printf("%s\n", p); ! 249: } ! 250: printf("**** END\n"); ! 251: } ! 252: #endif ! 253: ! 254: void ui_exithandler(void) ! 255: { ! 256: if (ui_vga) ! 257: uip_textmode(); ! 258: ui_vga = 0; ! 259: #ifdef ALLEGRO ! 260: ui_printlog(); ! 261: #endif ! 262: } ! 263: ! 264: void ui_final(void) ! 265: { ! 266: if (ui_vga) ! 267: uip_textmode(); ! 268: ui_vga = 0; ! 269: #ifdef ALLEGRO ! 270: ui_printlog(); ! 271: #endif ! 272: } ! 273: ! 274: int ui_setcolourbits(const char *str) ! 275: { ! 276: char *green, *blue; ! 277: char s[32]; ! 278: int r, g, b; ! 279: ! 280: snprintf(s, sizeof(s), "%s", str); ! 281: ! 282: if ((green = strchr(str, ',')) == NULL) ! 283: return -1; ! 284: *green++ = '\0'; ! 285: if ((blue = strchr(green, ',')) == NULL) ! 286: return -1; ! 287: *blue++= '\0'; ! 288: if ((r = atoi(s)) < 0 || r > 15 || ! 289: (g = atoi(green)) < 0 || g > 15 || ! 290: (b = atoi(blue)) < 0 || b > 15) ! 291: return -1; ! 292: if (uip_setcolourbits(r, g, b)) ! 293: return -1; ! 294: return 0; ! 295: } ! 296: ! 297: /*** ui_drawbox - plot a box ***/ ! 298: ! 299: void ui_drawbox(uint16 colour, uint16 x, uint16 y, uint16 width, ! 300: uint16 height) ! 301: { ! 302: uint16 *p, *q; ! 303: unsigned int i; ! 304: ! 305: p = (uint16 *)(ui_uipinfo.screenmem_w+y*ui_uipinfo.linewidth+x*2); ! 306: q = (uint16 *)((uint8 *)p+(height-1)*ui_uipinfo.linewidth); ! 307: for (i = 0; i < width; i++) ! 308: *p++ = *q++ = colour; ! 309: p = (uint16 *)(ui_uipinfo.screenmem_w+y*ui_uipinfo.linewidth+x*2); ! 310: for (i = 0; i < height; i++) { ! 311: p[0] = colour; ! 312: p[width-1] = colour; ! 313: p = (uint16 *)((uint8 *)p+ui_uipinfo.linewidth); ! 314: } ! 315: } ! 316: ! 317: /*** ui_unpackfont - unpack the font file ***/ ! 318: ! 319: int ui_unpackfont(void) ! 320: { ! 321: unsigned int c, y, x; ! 322: unsigned char packed; ! 323: uint16 *cdata; ! 324: ! 325: if ((ui_font = malloc(128*6*10*2)) == NULL) /* 128 chars, 6x, 10y, 16bit */ ! 326: return -1; ! 327: for (c = 0; c < 128; c++) { /* 128 characters */ ! 328: cdata = ui_font+c*6*10; ! 329: for (y = 0; y < 10; y++) { /* 10 pixels height */ ! 330: packed = generator_font[c*10+y]; ! 331: for (x = 0; x < 6; x++) { /* 6 pixels width */ ! 332: *cdata++ = (packed & 1<<(7-x)) ? 0xffff : 0; ! 333: } ! 334: } ! 335: } ! 336: return 0; ! 337: } ! 338: ! 339: /*** ui_plotint2 - plot a 2-char wide integer ***/ ! 340: ! 341: uint16 ui_plotint2(uint8 num, uint16 xpos, uint16 ypos) ! 342: { ! 343: char buf[3]; ! 344: ! 345: buf[0] = '0' + (num / 10) % 10; ! 346: buf[1] = '0' + (num % 10); ! 347: buf[2] = '\0'; ! 348: return ui_plotstring(buf, xpos, ypos); ! 349: } ! 350: ! 351: /*** ui_plotstring - plot a string ***/ ! 352: ! 353: uint16 ui_plotstring(const char *text, uint16 xpos, uint16 ypos) ! 354: { ! 355: const unsigned char *p; ! 356: const uint16 *cdata; ! 357: unsigned int x,y; ! 358: uint16 *scr; ! 359: ! 360: for (p = text; *p; p++) { ! 361: if (*p > 128) ! 362: cdata = ui_font+'.'*6*10; ! 363: else ! 364: cdata = ui_font+(*p)*6*10; ! 365: for (y = 0; y < 10; y++) { ! 366: scr = (uint16 *)(ui_uipinfo.screenmem_w+(ypos+y)*ui_uipinfo.linewidth ! 367: +xpos*2); ! 368: for (x = 0; x < 6; x++) ! 369: *scr++ = *cdata++; ! 370: } ! 371: xpos+= 6; ! 372: } ! 373: return xpos; ! 374: } ! 375: ! 376: /*** ui_plotsprite - plot a sprite ***/ ! 377: ! 378: void ui_plotsprite_acorn(uint16 *logo, uint16 width, uint16 height, ! 379: uint16 x, uint16 y) ! 380: { ! 381: uint16 a, b; ! 382: uint16 *p, *q; ! 383: uint16 word; ! 384: uint8 red, green, blue; ! 385: ! 386: for (b = 0; b < height; b++) { ! 387: p = (uint16 *)(ui_uipinfo.screenmem_w+(y+b)*ui_uipinfo.linewidth+x*2); ! 388: for (a = 0; a < width; a++) { ! 389: word = (((uint8 *)logo)[1]<<8) | ((uint8 *)logo)[0]; ! 390: green = (word>>5) & 0x1f; ! 391: red = word & 0x1f; ! 392: blue = (word>>10) & 0x1f; ! 393: *p++ = red<<ui_uipinfo.redshift | green<<ui_uipinfo.greenshift | ! 394: blue<<ui_uipinfo.blueshift; ! 395: logo++; ! 396: } ! 397: } ! 398: } ! 399: ! 400: /*** ui_setupscreen - plot borders and stuff ***/ ! 401: ! 402: void ui_setupscreen(void) ! 403: { ! 404: uint16 grey = 24<<ui_uipinfo.redshift | 24<<ui_uipinfo.greenshift | ! 405: 24<<ui_uipinfo.blueshift; ! 406: uint16 red = 24<<ui_uipinfo.redshift; ! 407: ! 408: if (!ui_info) { ! 409: if (!ui_fullscreen) { ! 410: ui_drawbox(red, 140, 100, 360, 280); ! 411: ui_drawbox(grey, 141, 101, 358, 278); ! 412: } ! 413: return; ! 414: } ! 415: if (ui_fullscreen) { ! 416: ui_plotstring(":", 622, 470); ! 417: return; ! 418: } ! 419: ui_drawbox(red, 140, 100, 360, 280); ! 420: ui_drawbox(grey, 141, 101, 358, 278); ! 421: ui_plotsprite_acorn((uint16 *)logo, 282, 40, 179, 80); ! 422: ui_plotsprite_acorn((uint16 *)logo, 282, 40, 179, 360); ! 423: ui_drawbox(red, 0, 415, 640, 1); ! 424: ui_drawbox(grey, 0, 416, 640, 1); ! 425: ui_drawbox(red, 0, 65, 640, 1); ! 426: ui_drawbox(grey, 0, 66, 640, 1); ! 427: ; ! 428: /* draw marker for 320x224 box */ ! 429: // ui_drawbox(grey, 160, 128, 320, 224); ! 430: /* draw marker for 320x240 box */ ! 431: // ui_drawbox(grey, 160, 120, 320, 240); ! 432: /* draw marker for 256x224 box */ ! 433: // ui_drawbox(grey, 192, 128, 256, 224); ! 434: /* draw marker for 256x240 box */ ! 435: // ui_drawbox(grey, 192, 120, 256, 240); ! 436: ; ! 437: ui_plotstring("Generator is (c) James Ponder 1997-2001, " ! 438: "all rights reserved.", 0, 0); ! 439: ui_plotstring(VERSTRING, 640-(strlen(VERSTRING)*6), 0); ! 440: ; ! 441: ui_plotstring("[A] A button", 0, 420); ! 442: ui_plotstring("[S] B button", 0, 430); ! 443: ui_plotstring("[D] C button", 0, 440); ! 444: ui_plotstring("[RETURN] Start", 0, 450); ! 445: ui_plotstring("[ARROWS] D-pad", 0, 460); ! 446: ui_plotstring("[ESCAPE] QUIT", 0, 470); ! 447: ; ! 448: ui_plotstring("FPS: 00", 120, 420); ! 449: ui_plotstring("Skip: 00", 120, 430); ! 450: ui_plotstring(":", 622, 470); ! 451: ; ! 452: ui_plotstring("[F1] License", 0, 20); ! 453: ui_plotstring("[F2] Load/Save state", 0, 30); ! 454: ui_plotstring("[F3] -", 0, 40); ! 455: ui_plotstring("[F4] Save image", 0, 50); ! 456: ; ! 457: ui_plotstring("[F5] Toggle info:", 216, 20); ! 458: ui_plotstring("[F6] Toggle video:", 216, 30); ! 459: ui_plotstring("[F7] Toggle country:", 216, 40); ! 460: ui_plotstring("[F8] Toggle plotter:", 216, 50); ! 461: ; ! 462: ui_plotstring("[F9] Toggle vsync:", 432, 20); ! 463: ui_plotstring("[F10] Full screen", 432, 30); ! 464: ui_plotstring("[F11] -", 432, 40); ! 465: ui_plotstring("[F12] Reset", 432, 50); ! 466: ; ! 467: ui_plotsettings(); ! 468: ; ! 469: sprintf(bigbuffer, "%s %X %s", gen_cartinfo.version, ! 470: gen_cartinfo.checksum, gen_cartinfo.country); ! 471: ui_plotstring(bigbuffer, 216, 420); ! 472: ui_plotstring(gen_cartinfo.name_domestic, 216, 430); ! 473: ui_plotstring(gen_cartinfo.name_overseas, 216, 440); ! 474: } ! 475: ! 476: void ui_plotsettings(void) ! 477: { ! 478: ui_plotstring(ui_info ? "On " : "Off", 216+126, 20); ! 479: ui_plotstring(vdp_pal ? "Pal " : "NTSC", 216+126, 30); ! 480: ui_plotstring(vdp_overseas ? "USA/Europe" : "Japan ", 216+126, 40); ! 481: ui_plotstring(ui_vdpsimple ? "Cell (fast) " : "Raster (slow)", 216+126, 50); ! 482: ui_plotstring(ui_vsync ? "On " : "Off", 216+342, 20); ! 483: } ! 484: ! 485: /*** ui_loop - main UI loop ***/ ! 486: ! 487: int ui_loop(void) ! 488: { ! 489: char *p; ! 490: int f; ! 491: ! 492: if (ui_initload) { ! 493: p = gen_loadimage(ui_initload); ! 494: if (p) { ! 495: LOG_CRITICAL(("Failed to load ROM image: %s", p)); ! 496: return 1; ! 497: } ! 498: if (ui_saverom) { ! 499: snprintf(bigbuffer, sizeof(bigbuffer)-1, "%s (%X-%s)", ! 500: gen_cartinfo.name_overseas, gen_cartinfo.checksum, ! 501: gen_cartinfo.country); ! 502: if ((f = open(bigbuffer, O_CREAT | O_EXCL | O_WRONLY, 0777)) == -1 || ! 503: write(f, cpu68k_rom, cpu68k_romlen) == -1 || close(f) == -1) { ! 504: fprintf(stderr, "Failed to write file: %s\n", strerror(errno)); ! 505: } ! 506: printf("Successfully wrote: %s\n", bigbuffer); ! 507: gen_quit = 1; ! 508: return 0; ! 509: } ! 510: ui_state = 2; ! 511: } else { ! 512: LOG_CRITICAL(("You must specify a ROM to load")); ! 513: return 1; ! 514: } ! 515: if (uip_vgamode()) { ! 516: LOG_CRITICAL(("Failed to start VGA mode")); ! 517: return 1; ! 518: } ! 519: gen_quit = 0; ! 520: while(!uip_checkkeyboard()) { ! 521: switch(ui_state) { ! 522: case 0: /* stopped */ ! 523: break; ! 524: case 1: /* paused */ ! 525: break; ! 526: case 2: /* playing */ ! 527: if (ui_fkeys & 1<<1) ! 528: ui_licensescreen(); ! 529: if (ui_fkeys & 1<<2) ! 530: ui_statescreen(); ! 531: if (ui_fkeys & 1<<4) ! 532: ui_imagescreen(); ! 533: if (ui_fkeys & 1<<5) { ! 534: ui_info^= 1; ! 535: ui_clearnext = 2; ! 536: } ! 537: if (ui_fkeys & 1<<6) { ! 538: vdp_pal^= 1; ! 539: vdp_setupvideo(); ! 540: ui_clearnext = 2; ! 541: } ! 542: if (ui_fkeys & 1<<7) { ! 543: vdp_overseas^= 1; ! 544: ui_clearnext = 2; ! 545: } ! 546: if (ui_fkeys & 1<<8) { ! 547: ui_vdpsimple^= 1; ! 548: ui_clearnext = 2; ! 549: } ! 550: if (ui_fkeys & 1<<9) { ! 551: ui_vsync^= 1; ! 552: ui_clearnext = 2; ! 553: } ! 554: if (ui_fkeys & 1<<10) { ! 555: ui_fullscreen^= 1; ! 556: ui_clearnext = 2; ! 557: } ! 558: if (ui_fkeys & 1<<12) ! 559: ui_resetscreen(); ! 560: ui_fkeys = 0; ! 561: ui_newframe(); ! 562: event_doframe(); ! 563: break; ! 564: } ! 565: } ! 566: return 0; ! 567: } ! 568: ! 569: void ui_newframe(void) ! 570: { ! 571: static int hmode = 0; ! 572: static int skipcount = 0; ! 573: static char frameplots[60]; /* 60 for NTSC, 50 for PAL */ ! 574: static unsigned int frameplots_i = 0; ! 575: char buf[8]; ! 576: unsigned int i; ! 577: int fps; ! 578: time_t t = time(NULL); ! 579: struct tm *tm_p = localtime(&t); ! 580: ! 581: /* we store whether we plotted the previous field as this is important ! 582: for doing weave interlacing - we don't want to weave two distant fields */ ! 583: ui_plotprevfield = ui_plotfield; ! 584: ! 585: if (frameplots_i > vdp_framerate) ! 586: frameplots_i = 0; ! 587: if (((vdp_reg[12] >> 1) & 3) && vdp_oddframe) { ! 588: /* interlace mode, and we're about to do an odd field - we always leave ! 589: ui_plotfield alone so we do fields in pairs */ ! 590: } else { ! 591: ui_plotfield = 0; ! 592: if (ui_frameskip == 0) { ! 593: if (sound_feedback != -1) ! 594: ui_plotfield = 1; ! 595: } else { ! 596: if (cpu68k_frames % ui_frameskip == 0) ! 597: ui_plotfield = 1; ! 598: } ! 599: } ! 600: if (!ui_plotfield) { ! 601: skipcount++; ! 602: frameplots[frameplots_i++] = 0; ! 603: return; ! 604: } ! 605: if (hmode != (vdp_reg[12]&1)) ! 606: ui_clearnext = 2; ! 607: if (ui_clearnext) { ! 608: /* horizontal size has changed, so clear whole screen and setup ! 609: borders etc again */ ! 610: ui_clearnext--; ! 611: hmode = vdp_reg[12] & 1; ! 612: memset(uip_whichbank() ? ui_screen1 : ui_screen0, 0, ! 613: sizeof(ui_screen[0])); ! 614: uip_clearscreen(); ! 615: ui_setupscreen(); ! 616: } ! 617: /* count the frames we've plotted in the last vdp_framerate real frames */ ! 618: fps = 0; ! 619: for (i = 0; i < vdp_framerate; i++) { ! 620: if (frameplots[i]) ! 621: fps++; ! 622: } ! 623: frameplots[frameplots_i++] = 1; ! 624: if (!ui_info) ! 625: return; ! 626: if (ui_fullscreen) { ! 627: ui_plotint2(fps, 0, 470); ! 628: } else { ! 629: ui_plotint2(fps, 156, 420); ! 630: ui_plotint2(skipcount+1, 156, 430); ! 631: skipcount = 0; ! 632: } ! 633: ui_plotint2(tm_p->tm_hour, 610, 470); ! 634: ui_plotint2(tm_p->tm_min, 628, 470); ! 635: /* ! 636: if (!ui_fullscreen) { ! 637: int y, i, s; ! 638: for (i = 0; i < 8; i++) { ! 639: for (s = 0; s < 4; s++) { ! 640: ui_plotstring((sound_keys[i] & (1<<s)) ? "*" : ".", ! 641: 510+(5*s), 200+10*i); ! 642: } ! 643: } ! 644: } ! 645: */ ! 646: } ! 647: ! 648: /* ui_checkpalcache goes through the CRAM memory in the Genesis and ! 649: converts it to the ui_palcache table. The Genesis has 64 colours, ! 650: but we store three versions of the colour table into ui_palcache - a ! 651: normal, hilighted and dim version. The vdp_cramf buffer has 64 ! 652: entries and is set to 1 when the game writes to CRAM, this means this ! 653: code skips entries that have not changed, unless 'flag' is set to 1 in ! 654: which case this updates all entries regardless. */ ! 655: ! 656: void ui_checkpalcache(int flag) ! 657: { ! 658: uint32 pal; ! 659: unsigned int col; ! 660: uint8 *p; ! 661: ! 662: /* this code requires that there be at least 4 bits per colour, that ! 663: is, three bits that come from the console's palette, and one more bit ! 664: when we do a dim or bright colour, i.e. this code works with 12bpp ! 665: upwards */ ! 666: ! 667: /* the flag forces it to do the update despite the vdp_cramf buffer */ ! 668: ! 669: for (col = 0; col < 64; col++) { /* the CRAM has 64 colours */ ! 670: if (!flag && !vdp_cramf[col]) ! 671: continue; ! 672: vdp_cramf[col] = 0; ! 673: p = (uint8 *)vdp_cram+2*col; /* point p to the two-byte CRAM entry */ ! 674: ui_palcache[col] = /* normal */ ! 675: (p[0]&0xE)<<(ui_uipinfo.blueshift+1) | ! 676: (p[1]&0xE)<<(ui_uipinfo.redshift+1) | ! 677: ((p[1]&0xE0)>>4)<<(ui_uipinfo.greenshift+1); ! 678: ui_palcache[col+64] = /* hilight */ ! 679: (p[0]&0xE)<<ui_uipinfo.blueshift | ! 680: (p[1]&0xE)<<ui_uipinfo.redshift | ! 681: ((p[1]&0xE0)>>4)<<ui_uipinfo.greenshift | ! 682: (16 << ui_uipinfo.blueshift) | (16 << ui_uipinfo.redshift) | ! 683: (16 << ui_uipinfo.greenshift); ! 684: ui_palcache[col+128] = /* shadow */ ! 685: (p[0]&0xE)<<ui_uipinfo.blueshift | ! 686: (p[1]&0xE)<<ui_uipinfo.redshift | ! 687: ((p[1]&0xE0)>>4)<<ui_uipinfo.greenshift; ! 688: } ! 689: } ! 690: ! 691: /*** ui_convertdata - convert genesis data to 16 bit colour */ ! 692: ! 693: void ui_convertdata(uint8 *indata, uint16 *outdata, unsigned int pixels) ! 694: { ! 695: unsigned int ui; ! 696: uint32 outdata1; ! 697: uint32 outdata2; ! 698: uint32 indata_val; ! 699: ! 700: ui_checkpalcache(0); ! 701: /* not scaled, 16bpp - we do 4 pixels at a time */ ! 702: for (ui = 0; ui < pixels>>2; ui++) { ! 703: indata_val = ((uint32 *)indata)[ui]; /* 4 bytes of in data */ ! 704: outdata1 = (ui_palcache[indata_val & 0xff] | ! 705: ui_palcache[(indata_val>>8) & 0xff]<<16); ! 706: outdata2 = (ui_palcache[(indata_val>>16) & 0xff] | ! 707: ui_palcache[(indata_val>>24) & 0xff]<<16); ! 708: #ifdef WORDS_BIGENDIAN ! 709: ((uint32 *)outdata)[(ui<<1)] = outdata2; ! 710: ((uint32 *)outdata)[(ui<<1)+1] = outdata1; ! 711: #else ! 712: ((uint32 *)outdata)[(ui<<1)] = outdata1; ! 713: ((uint32 *)outdata)[(ui<<1)+1] = outdata2; ! 714: #endif ! 715: } ! 716: } ! 717: ! 718: /*** ui_render_x1 - copy to screen with delta changes ***/ ! 719: ! 720: void ui_render_x1(uint16 *linedata, uint16 *olddata, uint8 *screen, ! 721: unsigned int linewidth, unsigned int pixels) ! 722: { ! 723: unsigned int ui; ! 724: uint32 inval; ! 725: ! 726: if (0==1) { ! 727: memcpy(screen, linedata, pixels*2); ! 728: } else { ! 729: for (ui = 0; ui < pixels>>1; ui++) { ! 730: inval = ((uint32 *)linedata)[ui]; /* two words of input data */ ! 731: if (inval != ((uint32 *)olddata)[ui]) { ! 732: ((uint32 *)screen)[ui] = inval; ! 733: } ! 734: } ! 735: } ! 736: } ! 737: ! 738: /*** ui_render_x2 - blow up screen image by two */ ! 739: ! 740: void ui_render_x2(uint16 *linedata, uint16 *olddata, uint8 *screen, ! 741: unsigned int linewidth, unsigned int pixels) ! 742: { ! 743: unsigned int ui; ! 744: uint32 inval, outval, mask; ! 745: uint8 *screen2 = screen + linewidth; ! 746: ! 747: for (ui = 0; ui < pixels>>1; ui++) { ! 748: inval = ((uint32 *)linedata)[ui]; /* two words of input data */ ! 749: mask = inval ^ ((uint32 *)olddata)[ui]; /* check for changed data */ ! 750: if (mask & 0xffff) { ! 751: outval = inval & 0xffff; ! 752: outval|= outval<<16; ! 753: #ifdef WORDS_BIGENDIAN ! 754: ((uint32 *)screen)[(ui<<1)+1] = outval; /* write first two words */ ! 755: ((uint32 *)screen2)[(ui<<1)+1] = outval; ! 756: #else ! 757: ((uint32 *)screen)[(ui<<1)] = outval; /* write first two words */ ! 758: ((uint32 *)screen2)[(ui<<1)] = outval; ! 759: #endif ! 760: } ! 761: if (mask & 0xffff0000) { ! 762: outval = inval & 0xffff0000; ! 763: outval|= outval>>16; ! 764: #ifdef WORDS_BIGENDIAN ! 765: ((uint32 *)screen)[(ui<<1)] = outval; /* write second two words */ ! 766: ((uint32 *)screen2)[(ui<<1)] = outval; ! 767: #else ! 768: ((uint32 *)screen)[(ui<<1)+1] = outval; /* write second two words */ ! 769: ((uint32 *)screen2)[(ui<<1)+1] = outval; ! 770: #endif ! 771: } ! 772: } ! 773: } ! 774: ! 775: /*** ui_render_x2h - blow up by two in horizontal direction only */ ! 776: ! 777: void ui_render_x2h(uint16 *linedata, uint16 *olddata, uint8 *screen, ! 778: unsigned int linewidth, unsigned int pixels) ! 779: { ! 780: unsigned int ui; ! 781: uint32 inval, outval, mask; ! 782: ! 783: mask = 0xffffffff; ! 784: for (ui = 0; ui < pixels>>1; ui++) { ! 785: inval = ((uint32 *)linedata)[ui]; /* two words of input data */ ! 786: if (olddata) ! 787: mask = inval ^ ((uint32 *)olddata)[ui]; /* check for changed data */ ! 788: if (mask & 0xffff) { ! 789: outval = inval & 0xffff; ! 790: outval|= outval<<16; ! 791: #ifdef WORDS_BIGENDIAN ! 792: ((uint32 *)screen)[(ui<<1)+1] = outval; /* write first two words */ ! 793: #else ! 794: ((uint32 *)screen)[(ui<<1)] = outval; /* write first two words */ ! 795: #endif ! 796: } ! 797: if (mask & 0xffff0000) { ! 798: outval = inval & 0xffff0000; ! 799: outval|= outval>>16; ! 800: #ifdef WORDS_BIGENDIAN ! 801: ((uint32 *)screen)[(ui<<1)] = outval; /* write second two words */ ! 802: #else ! 803: ((uint32 *)screen)[(ui<<1)+1] = outval; /* write second two words */ ! 804: #endif ! 805: } ! 806: } ! 807: } ! 808: ! 809: /*** ui_irender_weavefilter - take even and odd fields, filter and plot ***/ ! 810: ! 811: void ui_irender_weavefilter(uint16 *evendata, uint16 *odddata, uint8 *screen, ! 812: unsigned int linewidth, unsigned int pixels) ! 813: { ! 814: unsigned int ui; ! 815: uint32 evenval, oddval, e_r, e_g, e_b, o_r, o_g, o_b; ! 816: uint32 outval, w1, w2; ! 817: ! 818: for (ui = 0; ui < pixels>>1; ui++) { ! 819: evenval = ((uint32 *)evendata)[ui]; /* two words of input data */ ! 820: oddval = ((uint32 *)odddata)[ui]; /* two words of input data */ ! 821: e_r = (evenval >> ui_uipinfo.redshift) & 0x001f001f; ! 822: e_g = (evenval >> ui_uipinfo.greenshift) & 0x001f001f; ! 823: e_b = (evenval >> ui_uipinfo.blueshift) & 0x001f001f; ! 824: o_r = (oddval >> ui_uipinfo.redshift) & 0x001f001f; ! 825: o_g = (oddval >> ui_uipinfo.greenshift) & 0x001f001f; ! 826: o_b = (oddval >> ui_uipinfo.blueshift) & 0x001f001f; ! 827: outval = (((e_r+o_r)>>1) & 0x001f001f) << ui_uipinfo.redshift | ! 828: (((e_g+o_g)>>1) & 0x001f001f) << ui_uipinfo.greenshift | ! 829: (((e_b+o_b)>>1) & 0x001f001f) << ui_uipinfo.blueshift; ! 830: w1 = (outval & 0xffff); ! 831: w1|= w1<<16; ! 832: w2 = outval & 0xffff0000; ! 833: w2|= w2>>16; ! 834: #ifdef WORDS_BIGENDIAN ! 835: ((uint32 *)screen)[(ui<<1)] = w2; ! 836: ((uint32 *)screen)[(ui<<1)+1] = w1; ! 837: LOG_CRITICAL(("this code hasn't been checked")); ! 838: #else ! 839: ((uint32 *)screen)[(ui<<1)] = w1; ! 840: ((uint32 *)screen)[(ui<<1)+1] = w2; ! 841: #endif ! 842: } ! 843: } ! 844: ! 845: /*** ui_line - it is time to render a line ***/ ! 846: ! 847: void ui_line(unsigned int line) ! 848: { ! 849: static uint8 gfx[320]; ! 850: unsigned int yoffset = (vdp_reg[1] & 1<<3) ? 0 : 8; ! 851: unsigned int width = (vdp_reg[12] & 1) ? 320 : 256; ! 852: ! 853: if (ui_plotfield && !ui_vdpsimple) { ! 854: /* we are plotting this frame, and we're not doing a simple plot at ! 855: the end of it all */ ! 856: if (((vdp_reg[12]>>1) & 3) == 3) ! 857: vdp_renderline(line, gfx, vdp_oddframe); /* interlace */ ! 858: else ! 859: vdp_renderline(line, gfx, 0); ! 860: ui_convertdata(gfx, ui_newscreen+line*320, width); ! 861: } ! 862: } ! 863: ! 864: /*** ui_endfield - end of field reached ***/ ! 865: ! 866: void ui_endfield(void) ! 867: { ! 868: static int counter = 0; ! 869: unsigned int line; ! 870: unsigned int width = (vdp_reg[12] & 1) ? 320 : 256; ! 871: uint8 gfx[(320+16)*(240+16)]; ! 872: ! 873: if (ui_plotfield) { ! 874: if (ui_vdpsimple) { ! 875: /* cell mode - entire frame done here */ ! 876: vdp_renderframe(gfx+(8*(320+16))+8, 320+16); /* plot frame */ ! 877: for (line = 0; line < vdp_vislines; line++) { ! 878: ui_convertdata(gfx+8+(line+8)*(320+16), ! 879: ui_newscreen+line*320, width); ! 880: } ! 881: } ! 882: ui_rendertoscreen(); /* plot ui_newscreen to screen */ ! 883: } ! 884: if (ui_frameskip == 0) { ! 885: /* dynamic frame skipping */ ! 886: counter++; ! 887: if (sound_feedback >= 0) { ! 888: ui_actualskip = counter; ! 889: counter = 0; ! 890: } ! 891: } else { ! 892: ui_actualskip = ui_frameskip; ! 893: } ! 894: } ! 895: ! 896: void ui_rendertoscreen(void) ! 897: { ! 898: uint16 **oldscreenpp = uip_whichbank() ? &ui_screen1 : &ui_screen0; ! 899: uint16 *scrtmp; ! 900: uint16 *newlinedata, *oldlinedata; ! 901: unsigned int line; ! 902: unsigned int nominalwidth = (vdp_reg[12] & 1) ? 320 : 256; ! 903: unsigned int yoffset = (vdp_reg[1] & 1<<3) ? 0 : 8; ! 904: unsigned int xoffset = (vdp_reg[12] & 1) ? 0 : 32; ! 905: uint8 *screen; ! 906: uint16 *evenscreen; /* interlace: lines 0,2,etc. */ ! 907: uint16 *oddscreen; /* lines 1,3,etc. */ ! 908: ! 909: for (line = 0; line < vdp_vislines; line++) { ! 910: newlinedata = ui_newscreen+line*320; ! 911: oldlinedata = *oldscreenpp+line*320; ! 912: if (ui_fullscreen) { ! 913: screen = (ui_uipinfo.screenmem_w+xoffset*4+ ! 914: ui_uipinfo.linewidth*2*(line+yoffset)); ! 915: switch ((vdp_reg[12] >> 1) & 3) { /* interlace mode */ ! 916: case 0: ! 917: case 1: ! 918: case 2: ! 919: ui_render_x2h(newlinedata, oldlinedata, screen, ! 920: ui_uipinfo.linewidth, nominalwidth); ! 921: break; ! 922: case 3: ! 923: /* work out which buffer contains the odd and even fields */ ! 924: if (vdp_oddframe) { ! 925: oddscreen = ui_newscreen; ! 926: evenscreen = uip_whichbank() ? ui_screen0 : ui_screen1; ! 927: } else { ! 928: evenscreen = ui_newscreen; ! 929: oddscreen = uip_whichbank() ? ui_screen0 : ui_screen1; ! 930: } ! 931: switch (ui_interlace) { ! 932: case DEINTERLACE_BOB: ! 933: ui_render_x2(newlinedata, oldlinedata, screen, ! 934: ui_uipinfo.linewidth, nominalwidth); ! 935: break; ! 936: case DEINTERLACE_WEAVE: ! 937: ui_render_x2h(evenscreen+line*320, NULL, screen, ! 938: ui_uipinfo.linewidth, nominalwidth); ! 939: ui_render_x2h(oddscreen+line*320, NULL, ! 940: screen+ui_uipinfo.linewidth, ! 941: ui_uipinfo.linewidth, nominalwidth); ! 942: break; ! 943: case DEINTERLACE_WEAVEFILTER: ! 944: ui_irender_weavefilter(evenscreen+line*320, /* line */ ! 945: oddscreen+line*320, /* line+1 */ ! 946: screen, ! 947: ui_uipinfo.linewidth, nominalwidth); ! 948: ui_irender_weavefilter(oddscreen+line*320, /* line+1 */ ! 949: evenscreen+line*320+320, /* line+2 */ ! 950: screen+ui_uipinfo.linewidth, ! 951: ui_uipinfo.linewidth, nominalwidth); ! 952: break; ! 953: } ! 954: break; ! 955: } ! 956: } else { ! 957: screen = (ui_uipinfo.screenmem_w+320+xoffset*2+ ! 958: ui_uipinfo.linewidth*(120+line+yoffset)); ! 959: ui_render_x1(newlinedata, oldlinedata, screen, ! 960: ui_uipinfo.linewidth, nominalwidth); ! 961: } ! 962: } ! 963: uip_displaybank(-1); ! 964: if (ui_vsync) ! 965: uip_vsync(); ! 966: /* swap ui_screenX and ui_newscreen pointers */ ! 967: scrtmp = *oldscreenpp; ! 968: *oldscreenpp = ui_newscreen; ! 969: ui_newscreen = scrtmp; ! 970: } ! 971: ! 972: void ui_basicbits(void) ! 973: { ! 974: uint16 grey = 24<<ui_uipinfo.redshift | 24<<ui_uipinfo.greenshift | ! 975: 24<<ui_uipinfo.blueshift; ! 976: uint16 red = 24<<ui_uipinfo.redshift; ! 977: ! 978: ui_plotstring("Generator is (c) James Ponder 1997-2001, " ! 979: "all rights reserved.", 0, 0); ! 980: ui_plotstring(VERSTRING, 640-(strlen(VERSTRING)*6), 0); ! 981: ui_drawbox(red, 140, 100, 360, 280); ! 982: ui_drawbox(grey, 141, 101, 358, 278); ! 983: ui_plotsprite_acorn((uint16 *)logo, 282, 40, 179, 80); ! 984: ui_plotsprite_acorn((uint16 *)logo, 282, 40, 179, 360); ! 985: } ! 986: ! 987: void ui_licensescreen(void) ! 988: { ! 989: char c; ! 990: ! 991: sound_stop(); ! 992: uip_singlebank(); ! 993: uip_clearscreen(); ! 994: ui_basicbits(); ! 995: /* #01234567890123456789012345678901234567890123456789012 */ ! 996: ui_plotstring("Generator - Sega Genesis (Mega Drive) emulator", 160, 120); ! 997: ui_plotstring("Copyright (C) 1997-2001 James Ponder", 160, 130); ! 998: ui_plotstring("YM2612 chip emulation by Tatsuyuki Satoh", 160, 150); ! 999: ui_plotstring("Multi-Z80 CPU emulator by Neil Bradley", 160, 160); ! 1000: ui_plotstring(" Portable C version written by Edward Massey", 160, 170); ! 1001: ui_plotstring("This program is free software; you can redistribute", 160, ! 1002: 190); ! 1003: ui_plotstring("it and/or modify it under the terms of the GNU", 160, 200); ! 1004: ui_plotstring("General Public License version 2 as published by", 160, 210); ! 1005: ui_plotstring("the Free Software Foundation.", 160, 220); ! 1006: ui_plotstring("http://www.squish.net/generator/", 160, 240); ! 1007: ui_plotstring("[0] Return to game", 160, 280); ! 1008: while((c = uip_getchar()) != '0') { ! 1009: } ! 1010: uip_doublebank(); ! 1011: ui_clearnext = 2; ! 1012: sound_start(); ! 1013: } ! 1014: ! 1015: void ui_resetscreen(void) ! 1016: { ! 1017: sound_stop(); ! 1018: uip_singlebank(); ! 1019: uip_clearscreen(); ! 1020: ui_basicbits(); ! 1021: ui_resetscreen_main(); ! 1022: uip_doublebank(); ! 1023: ui_clearnext = 2; ! 1024: sound_final(); ! 1025: } ! 1026: ! 1027: void ui_resetscreen_main(void) ! 1028: { ! 1029: char c; ! 1030: ! 1031: for (;;) { ! 1032: uip_clearmiddle(); ! 1033: ui_plotstring("Reset menu", 160, 120); ! 1034: ui_plotstring("----------", 160, 130); ! 1035: ui_plotstring("[1] Soft reset", 160, 140); ! 1036: ui_plotstring("[2] Hard reset", 160, 150); ! 1037: ui_plotstring("[0] Return to game", 160, 170); ! 1038: ; ! 1039: switch((c = uip_getchar())) { ! 1040: case '0': ! 1041: return; ! 1042: case '1': ! 1043: gen_softreset(); ! 1044: return; ! 1045: case '2': ! 1046: gen_reset(); ! 1047: return; ! 1048: } ! 1049: } ! 1050: } ! 1051: ! 1052: void ui_statescreen(void) ! 1053: { ! 1054: sound_stop(); ! 1055: uip_singlebank(); ! 1056: uip_clearscreen(); ! 1057: ui_basicbits(); ! 1058: ui_statescreen_main(); ! 1059: uip_doublebank(); ! 1060: ui_clearnext = 2; ! 1061: sound_start(); ! 1062: } ! 1063: ! 1064: void ui_statescreen_main(void) ! 1065: { ! 1066: char c; ! 1067: ! 1068: for (;;) { ! 1069: uip_clearmiddle(); ! 1070: ui_plotstring("Load / Save state menu", 160, 120); ! 1071: ui_plotstring("----------------------", 160, 130); ! 1072: ui_plotstring("[1] Load state", 160, 140); ! 1073: ui_plotstring("[2] Save state", 160, 150); ! 1074: ui_plotstring("[0] Return to game", 160, 170); ! 1075: ; ! 1076: switch((c = uip_getchar())) { ! 1077: case '0': ! 1078: return; ! 1079: case '1': ! 1080: if (ui_statescreen_loadsavestate(0)) ! 1081: return; ! 1082: break; ! 1083: case '2': ! 1084: if (ui_statescreen_loadsavestate(1)) ! 1085: return; ! 1086: break; ! 1087: } ! 1088: } ! 1089: } ! 1090: ! 1091: int ui_statescreen_loadsavestate(int save) ! 1092: { ! 1093: char c; ! 1094: time_t t; ! 1095: char buf[64]; ! 1096: int i, y; ! 1097: ! 1098: for (;;) { ! 1099: uip_clearmiddle(); ! 1100: if (save) ! 1101: ui_plotstring("Save state", 160, 120); ! 1102: else ! 1103: ui_plotstring("Load state", 160, 120); ! 1104: ui_plotstring("----------", 160, 130); ! 1105: for (i = 1; i <= 9; i++) { ! 1106: y = 140 + 10 * i; ! 1107: snprintf(buf, sizeof(buf), "[%d]", i); ! 1108: ui_plotstring(buf, 160, y); ! 1109: if ((t = state_date(i)) == 0) { ! 1110: ui_plotstring("empty slot", 160+4*6, y); ! 1111: } else { ! 1112: strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", localtime(&t)); ! 1113: ui_plotstring(buf, 160+4*6, y); ! 1114: } ! 1115: } ! 1116: ui_plotstring("[0] ...back", 160, 140+10*11); ! 1117: if ((c = uip_getchar()) == '0') ! 1118: return 0; ! 1119: if (c >= '1' && c <= '9') { ! 1120: /* this is a function call! */ ! 1121: if ((save ? state_save : state_load)(c - '0') == 0) ! 1122: return 1; ! 1123: uip_clearmiddle(); ! 1124: if (save) ! 1125: ui_plotstring("Failed to save file.", 160, 120); ! 1126: else ! 1127: ui_plotstring("Failed to load file.", 160, 120); ! 1128: ui_plotstring("Press any key to continue", 160, 140); ! 1129: uip_getchar(); ! 1130: } ! 1131: } ! 1132: } ! 1133: ! 1134: void ui_imagescreen(void) ! 1135: { ! 1136: sound_stop(); ! 1137: uip_singlebank(); ! 1138: uip_clearscreen(); ! 1139: ui_basicbits(); ! 1140: ui_imagescreen_main(); ! 1141: uip_doublebank(); ! 1142: ui_clearnext = 2; ! 1143: sound_start(); ! 1144: } ! 1145: ! 1146: void ui_imagescreen_main(void) ! 1147: { ! 1148: char c; ! 1149: char filename[256]; ! 1150: char buf[256]; ! 1151: int xsize, ysize; ! 1152: ! 1153: for (;;) { ! 1154: uip_clearmiddle(); ! 1155: ui_plotstring("Save screen shot menu", 160, 120); ! 1156: ui_plotstring("---------------------", 160, 130); ! 1157: ui_plotstring("[1] Save svga screen (640x480)", 160, 140); ! 1158: ui_plotstring("[2] Save game screen", 160, 150); ! 1159: ui_plotstring("[0] Return to game", 160, 170); ! 1160: ; ! 1161: c = uip_getchar(); ! 1162: if (c == '0') { ! 1163: return; ! 1164: } else if (c == '1' || c == '2') { ! 1165: if (ui_saveimage(c == '1' ? "svga" : "game", filename, 256, ! 1166: &xsize, &ysize)) { ! 1167: uip_clearmiddle(); ! 1168: ui_plotstring("Failed to save image.", 160, 120); ! 1169: ui_plotstring("Press any key to continue", 160, 140); ! 1170: uip_getchar(); ! 1171: } else { ! 1172: uip_clearmiddle(); ! 1173: snprintf(buf, sizeof(buf), "Successfully saved %s", filename); ! 1174: ui_plotstring(buf, 160, 120); ! 1175: snprintf(buf, sizeof(buf), "(%d x %d 24 bit raw image)", xsize, ysize); ! 1176: ui_plotstring(buf, 160, 130); ! 1177: ui_plotstring("Press any key to continue", 160, 150); ! 1178: uip_getchar(); ! 1179: } ! 1180: } ! 1181: } ! 1182: } ! 1183: ! 1184: int ui_saveimage(const char *type, char *filename, int buflen, ! 1185: int *xsize, int *ysize) ! 1186: { ! 1187: int i, y; ! 1188: int fd = 0; ! 1189: char out[3]; ! 1190: int count; ! 1191: ! 1192: for (i = 1; i <= 9; i++) { ! 1193: snprintf(filename, buflen, "%s.ss%d", gen_leafname, i); ! 1194: if ((fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0644)) != -1) ! 1195: break; ! 1196: } ! 1197: if (i < 1 || i > 9) { ! 1198: *filename = '\0'; ! 1199: LOG_CRITICAL(("Error - there are already 9 saved images")); ! 1200: return -1; ! 1201: } ! 1202: if (!strcasecmp(type, "svga")) { ! 1203: uint8 *scr; ! 1204: uint16 *line; ! 1205: /* get the bank that we're not writing/reading to now */ ! 1206: scr = (ui_uipinfo.screenmem_w == ui_uipinfo.screenmem0) ? ! 1207: ui_uipinfo.screenmem1 : ui_uipinfo.screenmem0; ! 1208: for (y = 0; y < 480; y++) { ! 1209: line = (uint16 *)(scr + y * ui_uipinfo.linewidth); ! 1210: for (i = 0; i < 640; i++) { ! 1211: out[0] = ((line[i]>>ui_uipinfo.redshift) & 0x1f) << 3; ! 1212: out[1] = ((line[i]>>ui_uipinfo.greenshift) & 0x1f) << 3; ! 1213: out[2] = ((line[i]>>ui_uipinfo.blueshift) & 0x1f) << 3; ! 1214: count = write(fd, out, 3); ! 1215: if (count == -1) { ! 1216: LOG_CRITICAL(("Error whilst writing to output image file: %s", ! 1217: strerror(errno))); ! 1218: close(fd); ! 1219: return -1; ! 1220: } else if (count != 3) { ! 1221: LOG_CRITICAL(("Short write - wrote 3 bytes, got %d", count)); ! 1222: close(fd); ! 1223: return -1; ! 1224: } ! 1225: } ! 1226: } ! 1227: *xsize = 640; ! 1228: *ysize = 480; ! 1229: } else if (!strcasecmp(type, "game")) { ! 1230: uint16 data; ! 1231: uint16 *scr = uip_whichbank() ? ui_screen0 : ui_screen1; ! 1232: *xsize = (vdp_reg[12] & 1) ? 320 : 256; ! 1233: *ysize = vdp_vislines; ! 1234: for (y = 0; y < *ysize; y++) { ! 1235: for (i = 0; i < *xsize; i++) { ! 1236: data = scr[320*y+i]; ! 1237: out[0] = ((data>>ui_uipinfo.redshift) & 0x1f) << 3; ! 1238: out[1] = ((data>>ui_uipinfo.greenshift) & 0x1f) << 3; ! 1239: out[2] = ((data>>ui_uipinfo.blueshift) & 0x1f) << 3; ! 1240: count = write(fd, out, 3); ! 1241: if (count == -1) { ! 1242: LOG_CRITICAL(("Error whilst writing to output image file: %s", ! 1243: strerror(errno))); ! 1244: close(fd); ! 1245: return -1; ! 1246: } else if (count != 3) { ! 1247: LOG_CRITICAL(("Short write - wrote 3 bytes, got %d", count)); ! 1248: close(fd); ! 1249: return -1; ! 1250: } ! 1251: } ! 1252: } ! 1253: } else { ! 1254: LOG_CRITICAL(("Invalid image type '%s' passed to image save routine", ! 1255: type)); ! 1256: close(fd); ! 1257: return -1; ! 1258: } ! 1259: if (close(fd)) { ! 1260: LOG_CRITICAL(("Close returned error whilst writing image")); ! 1261: return -1; ! 1262: } ! 1263: return 0; ! 1264: } ! 1265: ! 1266: /*** logging functions ***/ ! 1267: ! 1268: /* logging is done this way because this was the best I could come up with ! 1269: whilst battling with macros that can only take fixed numbers of arguments */ ! 1270: ! 1271: #ifdef ALLEGRO ! 1272: #define LOG_FUNC(name,level,txt) void ui_log_ ## name ## (const char *text, ...) \ ! 1273: { \ ! 1274: va_list ap; \ ! 1275: char *ll = ui_loglines[ui_logline]; \ ! 1276: char *p = bigbuffer; \ ! 1277: if (gen_loglevel >= level) { \ ! 1278: p+= sprintf(p, "%d ", ui_logcount++); \ ! 1279: p+= sprintf(p, txt); \ ! 1280: va_start(ap, text); \ ! 1281: vsprintf(p, text, ap); \ ! 1282: va_end(ap); \ ! 1283: strncpy(ll, bigbuffer, UI_LOGLINESIZE); \ ! 1284: if (++ui_logline >= UI_LOGLINES) \ ! 1285: ui_logline = 0; \ ! 1286: } \ ! 1287: } ! 1288: #else ! 1289: #define LOG_FUNC(name,level,txt) void ui_log_ ## name ## (const char *text, ...) \ ! 1290: { \ ! 1291: va_list ap; \ ! 1292: if (gen_loglevel >= level) { \ ! 1293: printf("[%s] ", txt); \ ! 1294: va_start(ap, text); \ ! 1295: vprintf(text, ap); \ ! 1296: va_end(ap); \ ! 1297: putchar(10); \ ! 1298: } \ ! 1299: } ! 1300: #endif ! 1301: ! 1302: LOG_FUNC(debug3, 7, "DEBG "); ! 1303: LOG_FUNC(debug2, 6, "DEBG "); ! 1304: LOG_FUNC(debug1, 5, "DEBG "); ! 1305: LOG_FUNC(user, 4, "USER "); ! 1306: LOG_FUNC(verbose, 3, "---- "); ! 1307: LOG_FUNC(normal, 2, "---- "); ! 1308: LOG_FUNC(critical, 1, "CRIT "); ! 1309: LOG_FUNC(request, 0, "---- "); /* this generates a warning, such is life */ ! 1310: ! 1311: /*** ui_err - log error message and quit ***/ ! 1312: ! 1313: void ui_err(const char *text, ...) ! 1314: { ! 1315: va_list ap; ! 1316: ! 1317: printf("ERROR: "); ! 1318: ! 1319: va_start(ap, text); ! 1320: vfprintf(stderr, text, ap); ! 1321: va_end(ap); ! 1322: putc(10, stderr); ! 1323: exit(0); /* don't exit(1) because windows makes an error then! */ ! 1324: } ! 1325: ! 1326: /*** ui_setinfo - there is new cart information ***/ ! 1327: ! 1328: char *ui_setinfo(t_cartinfo *cartinfo) ! 1329: { ! 1330: return NULL; ! 1331: } ! 1332: ! 1333: /*** ui_topbit - given an integer return the top most bit set ***/ ! 1334: ! 1335: int ui_topbit(unsigned long int bits) ! 1336: { ! 1337: long int bit = 31; ! 1338: unsigned long int mask = 1<<31; ! 1339: ! 1340: for (; bit >= 0; bit--, mask>>= 1) { ! 1341: if (bits & mask) ! 1342: return bit; ! 1343: } ! 1344: return -1; ! 1345: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.