|
|
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.