Annotation of generator/main/ui-console.c, revision 1.1.1.3

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.