|
|
1.1 root 1: /*****************************************************************************/
2: /* Generator - Sega Genesis emulation - (c) James Ponder 1997-2000 */
3: /*****************************************************************************/
4: /* */
5: /* ui-console - generic 640x480 console emulation */
6: /* */
7: /*****************************************************************************/
8:
9: #include <stdlib.h>
10: #include <stdio.h>
11: #include <stdarg.h>
12: #include <time.h>
13: #include <string.h>
14:
15: #include "generator.h"
16:
17: #include "cpu68k.h"
18: #include "cpuz80.h"
19: #include "ui.h"
20: #include "vdp.h"
21: #include "reg68k.h"
22: #include "gensound.h"
23: #include "mem68k.h"
24: #include "logo.h"
25: #include "font.h"
26: #include "uip.h"
27: #include "ui-console.h"
28:
29: #define UI_LOGLINESIZE 128
30: #define UI_LOGLINES 64
31:
32: uint8 ui_vdpsimple = 0; /* 0=raster, 1=cell based plotter */
33: uint8 ui_clearnext = 0; /* flag indicating redraw required */
34: uint8 ui_info = 1; /* does the user want info onscreen or not */
35: uint8 ui_vsync = 0; /* does the user want us to wait for vsync */
36:
37: /*** forward reference declarations ***/
38:
39: void ui_endframe(void);
40: void ui_exithandler(void);
41: void ui_printlog(void);
42: void ui_newframe(void);
43: void ui_convertdata(uint8 *indata, uint8 *outdata, unsigned int pixels);
44: void ui_plotsprite_acorn(uint16 *logo, uint16 width, uint16 height,
45: uint16 x, uint16 y);
46: int ui_unpackfont(void);
47: uint16 ui_plotstring(const char *text, uint16 xpos, uint16 ypos);
48: uint16 ui_plotint2(uint8 num, uint16 xpos, uint16 ypos);
49: void ui_plotsettings(void);
50: void ui_drawbox(uint16 colour, uint16 x, uint16 y, uint16 width,
51: uint16 height);
52:
53: /*** static variables ***/
54:
55: static uint8 ui_vga = 0; /* flag for whether in VGA more or not */
56: static uint8 ui_frameskip = 0; /* 0 for dynamic */
57: static uint8 ui_actualskip = 0; /* the last skip we did (1..) */
58: static uint8 ui_state = 0; /* 0=stop, 1=paused, 2=play */
59: static uint32 ui_palcache[192];
60: static char *ui_initload = NULL; /* filename to load on init */
61: static char ui_loglines[UI_LOGLINES][UI_LOGLINESIZE];
62: static uint32 ui_logline = 0;
63: static uint8 ui_plotframe; /* flag indicating plotting this frame */
64: static uint16 *ui_font; /* unpacked font */
65: static uint8 bigbuffer[8192]; /* stupid no-vsnprintf platforms */
66: static uint16 ui_logcount = 0; /* log counter */
67: static t_uipinfo ui_uipinfo; /* uipinfo filled in by uip 'sub-system' */
68:
69: /*** Program entry point ***/
70:
71: int ui_init(int argc, char *argv[])
72: {
73: int i;
74:
75: for(i = 0; i < UI_LOGLINES; i++) {
76: ui_loglines[i][0] = '\0';
77: }
78: if (ui_unpackfont() == -1) {
79: fprintf(stderr, "Failed to unpack font, out of memory?\n");
80: return 1;
81: }
82: if (argc == 2) {
83: if ((ui_initload = malloc(strlen(argv[1])+1)) == NULL) {
84: fprintf(stderr, "Out of memory\n");
85: return 1;
86: }
87: strcpy(ui_initload, argv[1]);
88: }
89: if (atexit(ui_exithandler) == -1) {
90: LOG_CRITICAL(("Failed to set exit handler"));
91: return 1;
92: }
93: if (uip_init(&ui_uipinfo)) {
94: LOG_CRITICAL(("Failed to initialise platform dependent UI"));
95: return 1;
96: }
97: return 0;
98: }
99:
100: void ui_printlog(void)
101: {
102: unsigned int i;
103: char *p;
104:
105: printf("**** Last lines logged:\n");
106: for (i = ui_logline; i < (UI_LOGLINES+ui_logline); i++) {
107: p = ui_loglines[(i < UI_LOGLINES) ? i : (i-UI_LOGLINES)];
108: if (*p)
109: printf("%s\n", p);
110: }
111: printf("**** END\n");
112: }
113:
114: void ui_exithandler(void)
115: {
116: if (ui_vga)
117: uip_textmode();
118: ui_vga = 0;
119: ui_printlog();
120: }
121:
122: void ui_final(void)
123: {
124: if (ui_vga)
125: uip_textmode();
126: ui_vga = 0;
127: ui_printlog();
128: }
129:
130: /*** ui_drawbox - plot a box ***/
131:
132: void ui_drawbox(uint16 colour, uint16 x, uint16 y, uint16 width,
133: uint16 height)
134: {
135: uint16 *p, *q;
136: unsigned int i;
137:
138: p = (uint16 *)(ui_uipinfo.screenmem_w+y*ui_uipinfo.linewidth+x*2);
139: q = (uint16 *)((uint8 *)p+(height-1)*ui_uipinfo.linewidth);
140: for (i = 0; i < width; i++)
141: *p++ = *q++ = colour;
142: p = (uint16 *)(ui_uipinfo.screenmem_w+y*ui_uipinfo.linewidth+x*2);
143: for (i = 0; i < height; i++) {
144: p[0] = colour;
145: p[width-1] = colour;
146: p = (uint16 *)((uint8 *)p+ui_uipinfo.linewidth);
147: }
148: }
149:
150: /*** ui_unpackfont - unpack the font file ***/
151:
152: int ui_unpackfont(void)
153: {
154: unsigned int c, y, x;
155: unsigned char packed;
156: uint16 *cdata;
157:
158: if ((ui_font = malloc(128*6*10*2)) == NULL) /* 128 chars, 6x, 10y, 16bit */
159: return -1;
160: for (c = 0; c < 128; c++) { /* 128 characters */
161: cdata = ui_font+c*6*10;
162: for (y = 0; y < 10; y++) { /* 10 pixels height */
163: packed = generator_font[c*10+y];
164: for (x = 0; x < 6; x++) { /* 6 pixels width */
165: *cdata++ = (packed & 1<<(7-x)) ? 0xffff : 0;
166: }
167: }
168: }
169: return 0;
170: }
171:
172: /*** ui_plotint2 - plot a 2-char wide integer ***/
173:
174: uint16 ui_plotint2(uint8 num, uint16 xpos, uint16 ypos)
175: {
176: char buf[3];
177:
178: buf[0] = '0' + (num / 10) % 10;
179: buf[1] = '0' + (num % 10);
180: buf[2] = '\0';
181: return ui_plotstring(buf, xpos, ypos);
182: }
183:
184: /*** ui_plotstring - plot a string ***/
185:
186: uint16 ui_plotstring(const char *text, uint16 xpos, uint16 ypos)
187: {
188: const unsigned char *p;
189: const uint16 *cdata;
190: unsigned int x,y;
191: uint16 *scr;
192:
193: for (p = text; *p; p++) {
194: if (*p > 128)
195: cdata = ui_font+'.'*6*10;
196: else
197: cdata = ui_font+(*p)*6*10;
198: for (y = 0; y < 10; y++) {
199: scr = (uint16 *)(ui_uipinfo.screenmem_w+(ypos+y)*ui_uipinfo.linewidth
200: +xpos*2);
201: for (x = 0; x < 6; x++)
202: *scr++ = *cdata++;
203: }
204: xpos+= 6;
205: }
206: return xpos;
207: }
208:
209: /*** ui_plotsprite - plot a sprite ***/
210:
211: void ui_plotsprite_acorn(uint16 *logo, uint16 width, uint16 height,
212: uint16 x, uint16 y)
213: {
214: uint16 a, b;
215: uint16 *p, *q;
216: uint16 word;
217: uint8 red, green, blue;
218:
219: for (b = 0; b < height; b++) {
220: p = (uint16 *)(ui_uipinfo.screenmem_w+(y+b)*ui_uipinfo.linewidth+x*2);
221: for (a = 0; a < width; a++) {
222: word = (((uint8 *)logo)[1]<<8) | ((uint8 *)logo)[0];
223: green = (word>>5) & 0x1f;
224: red = word & 0x1f;
225: blue = (word>>10) & 0x1f;
226: *p++ = red<<ui_uipinfo.redshift | green<<ui_uipinfo.greenshift |
227: blue<<ui_uipinfo.blueshift;
228: logo++;
229: }
230: }
231: }
232:
233: /*** ui_setupscreen - plot borders and stuff ***/
234:
235: void ui_setupscreen(void)
236: {
237: uint16 grey = 24<<ui_uipinfo.redshift | 24<<ui_uipinfo.greenshift |
238: 24<<ui_uipinfo.blueshift;
239: uint16 red = 24<<ui_uipinfo.redshift;
240:
241: ui_drawbox(red, 140, 100, 360, 280);
242: ui_drawbox(grey, 141, 101, 358, 278);
243: if (!ui_info)
244: return;
245: ui_plotsprite_acorn((uint16 *)logo, 282, 40, 179, 80);
246: ui_plotsprite_acorn((uint16 *)logo, 282, 40, 179, 360);
247: ui_drawbox(red, 0, 415, 640, 1);
248: ui_drawbox(grey, 0, 416, 640, 1);
249: ui_drawbox(red, 0, 65, 640, 1);
250: ui_drawbox(grey, 0, 66, 640, 1);
251: ;
252: /* draw marker for 320x224 box */
253: // ui_drawbox(grey, 160, 128, 320, 224);
254: /* draw marker for 320x240 box */
255: // ui_drawbox(grey, 160, 120, 320, 240);
256: /* draw marker for 256x224 box */
257: // ui_drawbox(grey, 192, 128, 256, 224);
258: /* draw marker for 256x240 box */
259: // ui_drawbox(grey, 192, 120, 256, 240);
260: ;
261: ui_plotstring("Generator is (c) James Ponder 1997-2000, "
262: "all rights reserved.", 0, 0);
263: ui_plotstring(VERSTRING, 640-(strlen(VERSTRING)*6), 0);
264: ;
265: ui_plotstring("[A] A button", 0, 420);
266: ui_plotstring("[S] B button", 0, 430);
267: ui_plotstring("[D] C button", 0, 440);
268: ui_plotstring("[RETURN] Start", 0, 450);
269: ui_plotstring("[ARROWS] D-pad", 0, 460);
270: ui_plotstring("[ESCAPE] QUIT", 0, 470);
271: ;
272: ui_plotstring("FPS: 00", 120, 420);
273: ui_plotstring("Skip: 00", 120, 430);
274: ui_plotstring(":", 622, 470);
275: ;
276: ui_plotstring("[F5] Toggle info:", 0, 20);
277: ui_plotstring("[F6] Toggle video:", 0, 30);
278: ui_plotstring("[F7] Toggle country:", 0, 40);
279: ui_plotstring("[F8] Toggle plotter:", 0, 50);
280: ui_plotstring("[F9] Toggle vsync:", 216, 20);
281: ui_plotstring("[F12] Restart game", 216, 50);
282: ;
283: ui_plotstring("[1] B lo:", 64*6, 20);
284: ui_plotstring("[2] B hi:", 64*6, 30);
285: ui_plotstring("[3] A lo:", 64*6, 40);
286: ui_plotstring("[4] A hi:", 64*6, 50);
287: ui_plotstring("[5] W lo:", 78*6, 20);
288: ui_plotstring("[6] W hi:", 78*6, 30);
289: ui_plotstring("[7] H: ", 78*6, 40);
290: ui_plotstring("[8] S lo:", 92*6, 20);
291: ui_plotstring("[9] S hi:", 92*6, 30);
292: ;
293: ui_plotsettings();
294: ;
295: sprintf(bigbuffer, "%s %X %s", gen_cartinfo.version,
296: gen_cartinfo.checksum, gen_cartinfo.country);
297: ui_plotstring(bigbuffer, 216, 420);
298: ui_plotstring(gen_cartinfo.name_domestic, 216, 430);
299: ui_plotstring(gen_cartinfo.name_overseas, 216, 440);
300: }
301:
302: void ui_plotsettings(void)
303: {
304: ui_plotstring(ui_info ? "On " : "Off", 126, 20);
305: ui_plotstring(vdp_pal ? "Pal " : "NTSC", 126, 30);
306: ui_plotstring(vdp_overseas ? "USA/Europe" : "Japan ", 126, 40);
307: ui_plotstring(ui_vdpsimple ? "Cell (fast) " : "Raster (slow)", 126, 50);
308: ui_plotstring(ui_vsync ? "On " : "Off", 342, 20);
309: ;
310: ui_plotstring(vdp_layerB ? "On " : "Off", (64+10)*6, 20);
311: ui_plotstring(vdp_layerBp ? "On " : "Off", (64+10)*6, 30);
312: ui_plotstring(vdp_layerA ? "On " : "Off", (64+10)*6, 40);
313: ui_plotstring(vdp_layerAp ? "On " : "Off", (64+10)*6, 50);
314: ui_plotstring(vdp_layerW ? "On " : "Off", (78+10)*6, 20);
315: ui_plotstring(vdp_layerWp ? "On " : "Off", (78+10)*6, 30);
316: ui_plotstring(vdp_layerH ? "On " : "Off", (78+10)*6, 40);
317: ui_plotstring(vdp_layerS ? "On " : "Off", (92+10)*6, 20);
318: ui_plotstring(vdp_layerSp ? "On " : "Off", (92+10)*6, 30);
319: }
320:
321: /*** ui_loop - main UI loop ***/
322:
323: int ui_loop(void)
324: {
325: char *p;
326:
327: if (ui_initload) {
328: p = gen_loadimage(ui_initload);
329: if (p) {
330: LOG_CRITICAL(("Failed to load ROM image: %s", p));
331: return 1;
332: }
333: ui_state = 2;
334: } else {
335: LOG_CRITICAL(("You must specify a ROM to load"));
336: return 1;
337: }
338: if (uip_vgamode()) {
339: LOG_CRITICAL(("Failed to start VGA mode"));
340: return 1;
341: }
342: gen_quit = 0;
343: while(!uip_checkkeyboard()) {
344: switch(ui_state) {
345: case 0: /* stopped */
346: break;
347: case 1: /* paused */
348: break;
349: case 2: /* playing */
350: ui_newframe();
351: reg68k_framestep();
352: break;
353: }
354: }
355: return 0;
356: }
357:
358: void ui_newframe(void)
359: {
360: static int hmode = 0;
361: static int skipcount = 0;
362: static char frameplots[60]; /* 60 for NTSC, 50 for PAL */
363: static unsigned int frameplots_i = 0;
364: char buf[8];
365: unsigned int i;
366: int fps;
367: time_t t = time(NULL);
368: struct tm *tm_p = localtime(&t);
369:
370: if (frameplots_i > vdp_framerate)
371: frameplots_i = 0;
372: ui_plotframe = 0;
373: if (ui_frameskip == 0) {
374: if (sound_feedback != -1)
375: ui_plotframe = 1;
376: } else {
377: if (cpu68k_frames % ui_frameskip == 0)
378: ui_plotframe = 1;
379: }
380: if (!ui_plotframe) {
381: skipcount++;
382: frameplots[frameplots_i++] = 0;
383: return;
384: }
385: if (hmode != (vdp_reg[12]&1))
386: ui_clearnext = 2;
387: if (ui_clearnext) {
388: /* horizontal size has changed, so clear whole screen and setup
389: borders etc again */
390: ui_clearnext--;
391: hmode = vdp_reg[12]&1;
392: uip_clearscreen();
393: ui_setupscreen();
394: }
395: /* count the frames we've plotted in the last vdp_framerate real frames */
396: fps = 0;
397: for (i = 0; i < vdp_framerate; i++) {
398: if (frameplots[i])
399: fps++;
400: }
401: frameplots[frameplots_i++] = 1;
402: if (!ui_info)
403: return;
404: ui_plotint2(fps, 156, 420);
405: ui_plotint2(skipcount+1, 156, 430);
406: skipcount = 0;
407: ui_plotint2(tm_p->tm_hour, 610, 470);
408: ui_plotint2(tm_p->tm_min, 628, 470);
409: }
410:
411: void ui_checkpalcache(int flag)
412: {
413: uint32 pal;
414: unsigned int col;
415: uint8 *p;
416:
417: /* this code requires that there be at least 4 bits per colour, that
418: is, three bits that come from the console's palette, and one more bit
419: when we do a dim or bright colour, i.e. this code works with 12bpp
420: upwards */
421:
422: /* this code assumes 5 bits per colour in it's calculations */
423:
424: /* the flag forces it to do the check despite the vdp_cramf buffer */
425:
426: for (col = 0; col < 64; col++) {
427: if (!flag && !vdp_cramf[col])
428: continue;
429: vdp_cramf[col] = 0;
430: p = (uint8 *)vdp_cram+2*col;
431: ui_palcache[col] = /* normal */
432: (p[0]&0xE)<<(ui_uipinfo.blueshift+1) |
433: (p[1]&0xE)<<(ui_uipinfo.redshift+1) |
434: ((p[1]&0xE0)>>4)<<(ui_uipinfo.greenshift+1);
435: ui_palcache[col+64] = /* hilight */
436: (p[0]&0xE)<<ui_uipinfo.blueshift |
437: (p[1]&0xE)<<ui_uipinfo.redshift |
438: ((p[1]&0xE0)>>4)<<ui_uipinfo.greenshift |
439: (16 << ui_uipinfo.blueshift) | (16 << ui_uipinfo.redshift) |
440: (16 << ui_uipinfo.greenshift);
441: ui_palcache[col+128] = /* shadow */
442: (p[0]&0xE)<<ui_uipinfo.blueshift |
443: (p[1]&0xE)<<ui_uipinfo.redshift |
444: ((p[1]&0xE0)>>4)<<ui_uipinfo.greenshift;
445: }
446: }
447:
448: /*** ui_convertdata - convert genesis data to 16 bit colour */
449:
450: void ui_convertdata(uint8 *indata, uint8 *outdata, unsigned int pixels)
451: {
452: unsigned int ui;
453: uint32 data;
454:
455: ui_checkpalcache(0);
456: /* not scaled, 16bpp */
457: for (ui = 0; ui < pixels; ui++) {
458: data = ui_palcache[indata[ui]];
459: ((uint16 *)outdata)[ui] = data; /* already in local endian */
460: }
461: }
462:
463: /*** ui_line - it is time to render a line ***/
464:
465: void ui_line(unsigned int line)
466: {
467: static uint8 gfx[320];
468: uint16 *scr;
469:
470: if (ui_plotframe && !ui_vdpsimple) {
471: if (((vdp_reg[12]>>1) & 3) == 3)
472: vdp_renderline_interlace2(line*2+vdp_oddframe, (uint8 *)gfx);
473: else
474: vdp_renderline(line, (uint8 *)gfx);
475: ui_convertdata(gfx, (ui_uipinfo.screenmem_w+320+((vdp_reg[12]&1)?0:64)+
476: ui_uipinfo.linewidth*(120+line+
477: ((vdp_reg[1]&1<<3)?0:8))),
478: (vdp_reg[12]&1)?320:256);
479: }
480: }
481:
482: /*** ui_endfield - end of field reached ***/
483:
484: void ui_endfield(void)
485: {
486: ui_endframe();
487: }
488:
489: /*** ui_endframe - end of frame reached ***/
490:
491: void ui_endframe(void)
492: {
493: static uint8 gfx[(320+16)*(240+16)];
494: static int counter = 0;
495: unsigned int line;
496: uint16 *scr;
497:
498: if (ui_plotframe) {
499: if (ui_vdpsimple) {
500: /* cell mode - entire frame done here */
501: vdp_renderframe(gfx+(8*(320+16))+8, 320+16); /* plot frame */
502: for (line = 0; line < vdp_vislines; line++) {
503: ui_convertdata(gfx+8+(line+8)*(320+16),
504: (ui_uipinfo.screenmem_w+320+((vdp_reg[12]&1)?0:64)+
505: ui_uipinfo.linewidth*(120+line+
506: ((vdp_reg[1]&1<<3)?0:8))),
507: (vdp_reg[12]&1)?320:256);
508: }
509: }
510: uip_displaybank(-1);
511: if (ui_vsync)
512: uip_vsync();
513: }
514: if (ui_frameskip == 0) {
515: counter++;
516: if (sound_feedback >= 0) {
517: ui_actualskip = counter;
518: counter = 0;
519: }
520: } else {
521: ui_actualskip = ui_frameskip;
522: }
523: }
524:
525: /*** logging functions ***/
526:
527: /* logging is done this way because this was the best I could come up with
528: whilst battling with macros that can only take fixed numbers of arguments */
529:
530: #define LOG_FUNC(name,level,txt) void ui_log_ ## name ## (const char *text, ...) \
531: { \
532: va_list ap; \
533: char *ll = ui_loglines[ui_logline]; \
534: char *p = bigbuffer; \
535: if (gen_loglevel >= level) { \
536: p+= sprintf(p, "%d ", ui_logcount++); \
537: p+= sprintf(p, txt); \
538: va_start(ap, text); \
539: vsprintf(p, text, ap); \
540: va_end(ap); \
541: strncpy(ll, bigbuffer, UI_LOGLINESIZE); \
542: if (++ui_logline >= UI_LOGLINES) \
543: ui_logline = 0; \
544: } \
545: }
546:
547: LOG_FUNC(debug3, 7, "DEBG ");
548: LOG_FUNC(debug2, 6, "DEBG ");
549: LOG_FUNC(debug1, 5, "DEBG ");
550: LOG_FUNC(user, 4, "USER ");
551: LOG_FUNC(verbose, 3, "---- ");
552: LOG_FUNC(normal, 2, "---- ");
553: LOG_FUNC(critical, 1, "CRIT ");
554: LOG_FUNC(request, 0, "---- ");
555:
556: /*** ui_err - log error message and quit ***/
557:
558: void ui_err(const char *text, ...)
559: {
560: va_list ap;
561: char *ll = ui_loglines[ui_logline];
562: char *p = bigbuffer;
563:
564: p+= sprintf(p, "ERROR: ");
565: va_start(ap, text);
566: vsprintf(p, text, ap);
567: va_end(ap);
568: strncpy(ll, bigbuffer, UI_LOGLINESIZE);
569: if (++ui_logline >= UI_LOGLINES)
570: ui_logline = 0;
571: ui_printlog();
572: exit(0); /* don't exit(1) because windows makes an error then! */
573: }
574:
575: /*** ui_setinfo - there is new cart information ***/
576:
577: char *ui_setinfo(t_cartinfo *cartinfo)
578: {
579: return NULL;
580: }
581:
582: /*** ui_topbit - given an integer return the top most bit set ***/
583:
584: int ui_topbit(unsigned long int bits)
585: {
586: long int bit = 31;
587: unsigned long int mask = 1<<31;
588:
589: for (; bit >= 0; bit--, mask>>= 1) {
590: if (bits & mask)
591: return bit;
592: }
593: return -1;
594: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.