|
|
1.1 root 1: /* mdraw.c - display Mandelbrot set on EGA
2: * R. A. Garmoe 86/12/15
3: */
4:
5:
6:
7: /** Mdraw displays the elements of the Mandelbrot set
8: *
9: * z = z**2 + c
10: *
11: * where z and c are in the complex plane and z = 0 + 0i for the first
12: * iteration. The elements of the set are displayed in black and
13: * elements not in the set are displayed in color. The data to be
14: * displayed is computed by the program mandel.
15: */
16:
17:
18: /** Call
19: *
20: * mdraw file file ...
21: *
22: * where
23: * file a .cnt file created by the computation program mandel
24: *
25: * All of the files are read and displayed in order. After all of
26: * the images are displayed, keystrokes have the following meaning.
27: * e edit palette registers
28: * up/down arrow - select register
29: * right/left arrow - select color
30: * i reinitialize palette registers
31: * n advance to next display
32: * p backup to previous display
33: * q cleanup and exit
34: * r decrement palette register ripple
35: * R increment palette register ripple
36: * z continous forward zoom through images
37: * Z continous backward zoom through images
38: *
39: * All other characters are ignored.
40: */
41:
42:
43:
44:
45: /*
46: * The .cnt file has the format
47: * int number of points along the real axis
48: * int number of points along the imaginary axis
49: * int maximum iteration point for each point
50: * double real coordinate of upper left
51: * double imaginary coordinate of upper left
52: * double real coordinate of lower right
53: * double imaginary coordinate lower rightft
54: * double increment between points on real axis
55: * double increment between points on imaginary axis
56: * long (loop + 1) counters for histogram values
57: *
58: * The remainder of the file is the run length encoded scan
59: * lines encoded as:
60: * int number of words in scan line encoded as:
61: * +int actual count value for pixel
62: * -int int The first value is the run length and
63: * second value is the run value
64: */
65:
66:
67:
68: #include <stdio.h>
69: #include <subcalls.h>
70: #include <doscalls.h>
71: #include <dos.h>
72: #include "mdraw.h"
73:
74: /* The routines that are in the IOPL segment must be declared
75: * as pascal routines. When the IOPL routine is called through
76: * the intersegment call gate, the parameters are copied from the
77: * ring 3 user's stack to the ring 2 IOPL stack. The parameters
78: * must be popped from the IOPL stack (and the ring 3 stack) by the
79: * ret n instruction of the IOPL routine. Otherwise, the ring 2
80: * stack is left in an invalid state. For more information, refer
81: * to the 80286 Programmer's Manual for
82: * intersegment calls
83: * parameter passing through call gates
84: * CALLs to and RETurns from inner protection rings
85: *
86: * Note also that the number of words of passed parameters defined in
87: * each of these functions must exactly match the word counts defined
88: * in the EXPORTS statements in the mdraw.def linker definitions file.
89: */
90:
91: extern void far pascal SetDVideo ();
92: extern void far pascal SetEVideo ();
93: extern void far pascal SetScanClear ();
94: extern void far pascal SetScan (int, int, char *);
95: extern void far pascal SetScanSave (unsigned far *);
96: extern void far pascal SetScanSFont (unsigned);
97: extern void far pascal SetScanRFont (unsigned);
98: extern void far pascal SetScanRestore (unsigned far *);
99: extern void far pascal SetCursor (char far *);
100:
101:
102: void far mode_wait (void); /* starting address for a thread */
103: void far redraw_wait (void); /* starting address for another thread */
104:
105:
106:
107: /* Structures for VIO calls */
108:
109: struct ConfigData config; /* Display configuration data */
110: struct ModeData mode; /* Display mode data */
111: struct ModeData grmode; /* graphics display mode data */
112: struct PhysBufData physbuf; /* Physical buffer data */
113: struct CursorData cursor; /* Cursor data structure */
114: struct KeyData key; /* Keystroke data */
115: struct VIOSTATE vstate; /* Set vio state */
116:
117:
118:
119:
120: char pmand[60] = "mandel.cnt";
121: FILE *fmand;
122:
123: char chvalid = FALSE; /* key valid if true */
124: char cinit[15] = {WHITE, BLUE, GREEN, CYAN, RED, MAGENTA, BROWN, IWHITE,
125: DGRAY, LBLUE, LGREEN, LCYAN, LRED, LMAGENTA, YELLOW};
126: char firstread = FALSE; /* first character read from keyboard if true */
127: char flip = FALSE; /* flip display pages if true */
128: char graphics = FALSE; /* display is in graphics mode if true */
129: char mapped[MAXREAL]; /* character array holding mapped interation counters */
130: char initpal[16] = {
131: 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
132: 0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F
133: };
134: char palette[16] = {
135: 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
136: 0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F
137: };
138:
139: char *screenbuf; /* pointer to buffer to hold text screen */
140:
141: int *bp; /* pointer to next iteration counter in buf */
142: int buf[BUFFER]; /* run length encoded iteration counters */
143: int count = 0; /* number of integers remaining in buf */
144:
145: long delay = 0; /* ripple delay in milliseconds */
146: long drawsem = 0; /* RAM semaphore to control drawing */
147: long hist[MAXLOOP + 1] = {0}; /* histogram counters */
148:
149: struct image timage = {0}; /* local image descriptor structure */
150: struct ilist *head = NULL; /* pointer to head of ilist */
151: struct ilist *curr = NULL; /* pointer to current ilist */
152: struct ilist *tail = NULL; /* pointer to tail of ilist */
153:
154: unsigned curcol; /* cursor column position */
155: unsigned currow; /* cursor row position */
156: unsigned descsel; /* selector for image structure */
157: unsigned fontsel; /* selectors for font saves */
158: unsigned dpoffset = 0; /* display page offset 0x0000 or 0x8000 */
159: unsigned *psel; /* display memory selector */
160: unsigned screenlen; /* length of screen buffer */
161:
162: main (argc, argv)
163: int argc;
164: char **argv;
165: {
166: int c;
167: int i;
168: int temp;
169: int pal;
170: unsigned char *stack1, /* stack for mode_wait thread */
171: *stack2; /* stack for redraw_wait thread */
172: unsigned ThreadID;
173:
174: /* Validate the display configuration. It must be an EGA on an
175: * EGA adapter with at least 128k of memory.
176: */
177:
178: config.length = 10;
179: if ((temp = VIOGETCONFIG (0, (struct ConfigData far *)&config, 0)) != 0) {
180: printf ("Unable to get display configuration data - %d\n", temp);
181: exit (1);
182: }
183: if ((config.adapter_type != 2) || (config.display_type != 2) ||
184: config.memory_size < 0x20000) {
185: printf ("Display is not EGA on 128k EGA adapter %d %d %ld\n",
186: config.adapter_type, config.display_type, config.memory_size);
187: exit (1);
188: }
189:
190: if (config.memory_size == 0x40000)
191: flip = TRUE;
192:
193: /* Save information about the current display mode. This includes
194: * the current mode as known by VIO, the cursor type data, the
195: * current cursor position and the text screen data.
196: */
197:
198: mode.length = sizeof (struct ModeData);
199: if ((temp = VIOGETMODE ((struct ModeData far *)&mode, 0)) != 0) {
200: printf ("Unable to get display mode data - %d\n", temp);
201: exit (1);
202: }
203: if (VIOGETCURTYPE ((struct CursorData *)&cursor, 0) != 0) {
204: printf ("Unable to get current cursor data\n");
205: exit (1);
206: }
207: if (VIOGETCURPOS ((unsigned far *)&currow, (unsigned far *)&curcol, 0) != 0) {
208: printf ("Unable to get current cursor position\n");
209: exit (1);
210: }
211:
212: /* Allocate buffer to hold text screen data. Note that the buffer
213: * size is doubled because of the attribute bytes.
214: */
215:
216: screenlen = mode.col * mode.row * 2;
217: if ((screenbuf = (char *)malloc (screenlen)) == NULL) {
218: printf ("Unable to allocate memory for text screen buffer\n");
219: exit (1);
220: }
221: if (VIOREADCELLSTR ((char far *)screenbuf, (unsigned far *)&screenlen,
222: 0, 0, 0) != 0) {
223: printf ("Unable to read text screen data\n");
224: exit (1);
225: }
226:
227: /* Obtain selectors to the display memory */
228:
229: physbuf.buf_start = 0xa0000;
230: physbuf.buf_length = 0x20000;
231: if ((temp = VIOGETPHYSBUF ((struct PhysBufData far *)&physbuf, 0)) != 0) {
232: printf ("Unable to get physical buffer mapping - %d\n", temp);
233: exit (1);
234: }
235: if (DOSALLOCSEG (0,(unsigned far *)&fontsel, 0) != 0) {
236: printf ("Unable to allocate text font save segment\n");
237: exit (1);
238: }
239: /* Allocate memory for separate thread execution */
240:
241: stack1 = (unsigned char *)malloc (STACKSIZE);
242: stack2 = (unsigned char *)malloc (STACKSIZE);
243: if (!stack1 || !stack2) {
244: printf ("Out of memory\n");
245: exit (1);
246: }
247: stack1 += STACKSIZE;
248: stack2 += STACKSIZE;
249:
250: /* create thread to execute the mode wait */
251:
252: DOSCREATETHREAD (mode_wait, &ThreadID, stack1);
253:
254: /* create thread that will execute the redraw_wait () */
255:
256: DOSCREATETHREAD (redraw_wait, &ThreadID, stack2);
257:
258:
259: /* Pass pointer to the selectors for display memory and the
260: * selector to the font save segment to the ring 2 IOPL code.
261: */
262:
263: psel = physbuf.selectors;
264:
265: /* Save the font tables */
266:
267: SetScanSFont (fontsel);
268:
269: /* Set the EGA to 640 x 350 graphics mode */
270:
271: grmode = mode;
272: grmode.type = grmode.type | 0x02;
273: grmode.hres = 640;
274: grmode.vres = 350;
275: VIOSETMODE ((struct ModeData far *)&grmode, 0);
276: DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
277: setpalette (palette);
278: DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
279:
280: /* Set the file name if specified and open the file for reading */
281:
282: argc--;
283: argv++;
284: graphics = TRUE;
285: printf ("Clearing screen\n");
286: SetScanClear ();
287: printf ("Screen cleared\n");
288: while (argc > 0) {
289: /* set file name */
290: strcpy (pmand, *argv);
291: strcat (pmand, ".cnt");
292: if ((fmand = fopen (pmand, "rb")) == NULL) {
293: cleandisplay ();
294: printf ("Unable to open count file %s\n", pmand);
295: exit (3);
296: }
297: readimage ();
298: fclose (fmand);
299: argc--;
300: argv++;
301: }
302:
303: /* Wait for keyboard input to switch display or terminate. This
304: * thread must delay between checks for keyboard input. Otherwise,
305: * the code will execute a CPU bound loop and all other threads
306: * and processes will execute at a reduced rate.
307: */
308:
309: while (TRUE) {
310: if (nextchar (&c, 1)) {
311: switch (c) {
312: case 'e':
313: /* edit palette registers */
314: paledit ();
315: break;
316:
317: case 'i':
318: /* reinitialize palette registers */
319: for (i = 0; i < 16; i++)
320: palette[i] = initpal[i];
321: DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
322: setpalette (palette);
323: DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
324: break;
325:
326: case 'n':
327: /* advance to next display */
328: nextimage ();
329: break;
330:
331: case 'p':
332: /* backup to previous display */
333: previmage ();
334: break;
335:
336: case 'q':
337: /* cleanup and exit */
338: cleandisplay ();
339: exit ();
340:
341: case 'r':
342: /* decrement palette register ripple */
343: delay += SCANTIME;
344: break;
345:
346: case 'R':
347: /* increment palette register ripple */
348: delay -= SCANTIME;
349: break;
350:
351: case 'z':
352: /* continous forward zoom through images */
353: while (!nextchar (&c, 1))
354: nextimage ();
355: ungetchar ();
356: break;
357:
358: case 'Z':
359: /* continous backward zoom through images */
360: while (!nextchar (&c, 1))
361: previmage ();
362: ungetchar ();
363: break;
364:
365: default:
366: /* ignore character */
367: break;
368: }
369: }
370:
371: /* delay to prevent CPU bound loop */
372:
373: if (delay == 0)
374: DOSSLEEP ((long)100);
375: else if (delay > 0) {
376: ripple (RIPPLE_UP);
377: DOSSLEEP (delay);
378: }
379: else {
380: ripple (RIPPLE_DN);
381: DOSSLEEP ((long)(-delay));
382: }
383: }
384: }
385:
386:
387:
388:
389: /** mdisp - display Mandelbrot set
390: *
391: * mdisp (im);
392: *
393: */
394:
395:
396:
397: mdisp (im)
398: struct image far *im;
399: {
400: int i;
401: int ni; /* scan row counter */
402: int temp;
403: int len;
404: char *pmapped;
405:
406: VIOSCRLOCK (1, (char far *)&temp, 0);
407: DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
408: SetScanClear ();
409: DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
410:
411: for (ni = 0; ni < im->lni; ni++) {
412: pmapped = mapped;
413: if (!nextvalue (&len))
414: break;
415: while ((--len >= 0) && (pmapped - mapped < im->lnr) && nextvalue (&i)) {
416: if (i >= 0)
417: *pmapped++ = im->cmap[i];
418: else {
419: if (!nextvalue (&temp))
420: break;
421: len--;
422: temp = im->cmap[temp];
423: for (; (i < 0) && (pmapped - mapped < im->lnr); i++)
424: *pmapped++ = temp;
425: }
426: }
427:
428: /* The scan line drawing is locked with a RAM semaphore so
429: * the redraw-wait routine can save and restore the screen
430: */
431:
432: DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
433: SetScan (ni, im->lnr, mapped);
434: DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
435: }
436:
437: /* Save screen image and unlock the screen */
438:
439: DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
440: SetScanSave (curr->desc->savesel);
441: DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
442:
443: VIOSCRUNLOCK (0);
444: }
445:
446:
447:
448:
449: /** nextvalue - return next value from file
450: *
451: * flag = nextvalue (ptr);
452: *
453: * Entry ptr = pointer to integer to receive value
454: * Exit *ptr = next value from file
455: * Return TRUE if next value returned
456: * FALSE if end of file
457: */
458:
459:
460: int nextvalue (p)
461: int *p;
462: {
463: if (count == 0) {
464: count = fread ((char *)buf, sizeof (int), BUFFER, fmand);
465: bp = buf;
466: }
467: if (count == EOF)
468: return (FALSE);
469: *p = *bp++;
470: count--;
471: return (TRUE);
472: }
473:
474:
475:
476:
477: /** mode_wait - wait for mode reset request
478: *
479: * This routine is executed by another thread that is started
480: * by the main routine.
481: *
482: * This routine calls VIOmode_wait requesting to be notified
483: * after the completion of an application or hard error popup.
484: * On such a notification, it puts the screen in the desired
485: * graphics mode.
486: */
487:
488: void mode_wait ()
489: {
490: unsigned NotifyType;
491:
492: while (TRUE) {
493: /* wait for notification to restore mode */
494: VIOMODEWAIT (0, &NotifyType, 0);
495: if (NotifyType == 0 && graphics)
496: DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
497: VIOSETMODE ((struct ModeData far *)&grmode, 0);
498: SetScanClear ();
499: DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
500: }
501: }
502:
503:
504:
505:
506: /** redraw_wait - wait for mode reset request
507: *
508: * This routine is executed by another thread that is started
509: * by the main routine.
510: *
511: * This routine calls VioSavRedrawWait requesting to be notified
512: * for both save and redraw. On save notification, it copies the
513: * EGA adapter memory to allocated memory segments. On redraw
514: * notification, it puts the screen in the desired graphics mode
515: * and then redraws the Mandelbrot set.
516: */
517:
518:
519: void redraw_wait ()
520: {
521: unsigned NotifyType;
522:
523: while (TRUE) {
524: VIOSAVREDRAWWAIT (0, &NotifyType, 0);
525: if (graphics) {
526: if (NotifyType == 0) {
527: /* save graphics screen */
528: DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
529: SetScanSave (curr->desc->savesel);
530: SetScanClear ();
531: continue;
532: }
533: else if (NotifyType == 1) {
534: /* restore graphics screen */
535: dpoffset = 0;
536: VIOSETMODE ((struct ModeData far *)&grmode, 0);
537: SetScanClear ();
538: SetDVideo ();
539: SetScanRestore (curr->desc->savesel);
540: SetEVideo ();
541: DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
542: }
543: }
544: }
545: }
546:
547:
548:
549:
550: /** readimage - read and display next image
551: *
552: * readimage ();
553: *
554: */
555:
556:
557: readimage ()
558: {
559: int i;
560: struct ilist *tlist;
561: int nr;
562:
563: /* Allocate memory for image structure and link to chain of images */
564:
565: if ((tlist = (struct ilist *)malloc (sizeof (struct ilist))) == NULL) {
566: cleandisplay ();
567: printf ("Unable to allocate memory for ilist structure\n");
568: exit (1);
569: }
570: if (DOSALLOCSEG (sizeof (struct image),(unsigned far *)&descsel, 0) != 0) {
571: cleandisplay ();
572: printf ("Unable to allocate image descriptor segment of %d bytes\n", sizeof (struct image));
573: exit (1);
574: }
575:
576: FP_SEG (tlist->desc) = descsel;
577: FP_OFF (tlist->desc) = 0;
578:
579: /* Read description of the computed Mandelbrot set from the file
580: * and perform simple validation checks. Limit the display rows and
581: * columns to the display maximums.
582: */
583:
584: if (fread ((char *)&timage.nreal, sizeof (int), 1, fmand) != 1) {
585: cleandisplay ();
586: printf ("Error reading maximum number of reals %d\n", timage.nreal);
587: exit (2);
588: }
589: timage.lnr = (timage.nreal > 640)? 640: timage.nreal;
590: if (fread ((char *)&timage.nimag, sizeof (int), 1, fmand) != 1) {
591: cleandisplay ();
592: printf ("Error reading maximum number of imaginaries %d\n", timage.nimag);
593: exit (2);
594: }
595: timage.lni = (timage.nimag > 350)? 350: timage.nimag;
596: if (fread ((char *)&timage.mloop, sizeof (int), 1, fmand) != 1) {
597: cleandisplay ();
598: printf ("Error reading maximum loop count %d\n", timage.mloop);
599: exit (2);
600: }
601: if (fread ((char *)&timage.ul, sizeof (timage.ul), 1, fmand) != 1) {
602: cleandisplay ();
603: printf ("Error reading upper left coordinates\n");
604: exit (2);
605: }
606: if (fread ((char *)&timage.lr, sizeof (timage.lr), 1, fmand) != 1) {
607: cleandisplay ();
608: printf ("Error reading lower right coordinates\n");
609: exit (2);
610: }
611:
612: if (fread ((char *)&timage.rinc, sizeof (timage.rinc), 1, fmand) != 1) {
613: cleandisplay ();
614: printf ("Error reading real increment\n");
615: exit (2);
616: }
617: if (fread ((char *)&timage.iinc, sizeof (timage.iinc), 1, fmand) != 1) {
618: cleandisplay ();
619: printf ("Error reading imaginary increment\n");
620: exit (2);
621: }
622: if (fread ((char *)&timage.aspect, sizeof (timage.aspect), 1, fmand) != 1) {
623: cleandisplay ();
624: printf ("Error reading aspect ratio\n");
625: exit (2);
626: }
627: if (fread ((char *)timage.hist, sizeof (long), timage.mloop + 1, fmand) != timage.mloop + 1) {
628: cleandisplay ();
629: printf ("Error reading histogram\n");
630: exit (2);
631: }
632:
633: /* Assign colors to each iteration count. Black is reserved for
634: * points within the Mandelbrot set.
635: */
636:
637: for (nr = 0; nr < timage.mloop; nr++) {
638: timage.cmap[nr] = (nr % 15) + 1;
639: }
640: timage.cmap[timage.mloop] = 0;
641:
642: /* Allocate memory for segments to save graphics screen and
643: * EGA font tables.
644: */
645:
646: for ( i = 0; i < 2; i++) {
647: if (DOSALLOCSEG (56020, (unsigned far *)&timage.savesel[i], 0) != 0) {
648: cleandisplay ();
649: printf ("Unable to allocate screen save segments\n");
650: exit (1);
651: }
652: }
653:
654: /* Link image to chain of images */
655:
656: DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
657: /* copy structure to far segment */
658: *(tlist->desc) = timage;
659: tlist->next = NULL;
660: tlist->prev = tail;
661: if (head == NULL)
662: head = tlist;
663: else
664: tail->next = tlist;
665: tail = tlist;
666: curr = tlist;
667:
668: DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
669:
670: /* Lock the screen, set the display to graphics mode
671: * and draw the Mandelbrot set
672: */
673:
674: mdisp (curr->desc);
675: }
676:
677:
678:
679:
680: /**
681: *
682: *
683: */
684:
685: cleandisplay ()
686: {
687: /* cancel mode wait and redraw wait threads */
688:
689: VIOMODEUNDO (GIVEUPOWNER, KILLTHREAD, RESERVED);
690: VIOSAVREDRAWUNDO (GIVEUPOWNER, KILLTHREAD, RESERVED);
691:
692: /* Return the EGA adapter to a default mode that hopefully
693: * matches the mode that was present when we went into graphics
694: * mode. Then restore mode data, text screen data, cursor
695: * position and cursor type.
696: */
697:
698: SetDVideo ();
699: if (graphics) {
700: /* clear display memory */
701: dpoffset = 0;
702: SetScanClear ();
703: if (flip)
704: dpoffset = PAGESIZE;
705: SetScanClear ();
706: SetScanRFont (fontsel);
707: }
708: SetEVideo ();
709: VIOSETMODE ((struct ModeData far *)&mode, 0);
710: if (VIOWRTCELLSTR ((char far *)screenbuf, screenlen, 0, 0, 0) != 0) {
711: printf ("Unable to write text screen data\n");
712: exit (1);
713: }
714: if (VIOSETCURPOS (currow, curcol, 0) != 0) {
715: printf ("Unable to set current cursor position\n");
716: exit (1);
717: }
718: if (VIOSETCURTYPE ((struct CursorData *)&cursor, 0) != 0) {
719: printf ("Unable to set current cursor data\n");
720: exit (1);
721: }
722: }
723:
724:
725:
726: /** nextimage
727: *
728: */
729:
730:
731: nextimage ()
732: {
733: int temp;
734:
735: if (head != tail) {
736: DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
737: if (curr->next == NULL)
738: curr = head;
739: else
740: curr = curr->next;
741: if (flip)
742: dpoffset ^= PAGESIZE;
743: SetScanRestore (curr->desc->savesel);
744: DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
745: }
746: }
747:
748:
749:
750: /** previmage
751: *
752: */
753:
754:
755: previmage ()
756: {
757: int temp;
758:
759: if (head != tail) {
760: DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
761: VIOSCRLOCK (1, (char far *)&temp, 0);
762: if (curr->prev == NULL)
763: curr = tail;
764: else
765: curr = curr->prev;
766: if (flip)
767: dpoffset ^= PAGESIZE;
768: SetScanRestore (curr->desc->savesel);
769: VIOSCRUNLOCK (0);
770: DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
771: }
772: }
773:
774:
775:
776:
777: /** ripple - ripple palette registers
778: *
779: * ripple (direction);
780: *
781: * Entry direction = 0 if rotate palette registers up
782: * direction = 1 if rotate palette registers down
783: * Exit palette registers rotated by one
784: * Returns none
785: */
786:
787:
788: ripple (dir)
789: int dir;
790: {
791: int temp;
792: int i;
793:
794: switch (dir) {
795: case RIPPLE_UP:
796: temp = palette[0x0f];
797: for (i = 0x0f; i > 1; i--)
798: palette[i] = palette[i - 1];
799: palette[1] = temp;
800: break;
801:
802: case RIPPLE_DN:
803: temp = palette[1];
804: for (i = 1; i < 0x0f; i++)
805: palette[i] = palette[i + 1];
806: palette[0x0f] = temp;
807: break;
808: }
809: DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
810: setpalette (palette);
811: DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
812: }
813:
814:
815:
816:
817: /** flicker - flicker palette value
818: *
819: * flicker (pal);
820: *
821: * Entry pal = index of register to flicker
822: * Exit palette register toggled between value and black
823: * until keyboard input
824: * Returns none
825: */
826:
827:
828: flicker (pal)
829: int pal;
830: {
831: int temp;
832: int c;
833:
834: if ((pal > 0) && (pal < 0x10)) {
835: temp = palette[pal];
836: while (!nextchar (&c, 1)) {
837: palette[pal] = BLACK;
838: DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
839: setpalette (palette);
840: DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
841: DOSSLEEP ((long)100);
842: palette[pal] = temp;
843: DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
844: setpalette (palette);
845: DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
846: DOSSLEEP ((long)100);
847: }
848: ungetchar ();
849: }
850: }
851:
852:
853:
854:
855:
856: /** paledit - edit palette registers
857: *
858: * paledit ();
859: *
860: * Entry none
861: */
862:
863:
864: paledit ()
865: {
866: int pal;
867: int c;
868:
869: /* select palette register */
870:
871: pal = 1;
872: flicker (pal);
873: while (TRUE) {
874: nextchar (&c, 0);
875: switch (-c) {
876: case UP:
877: if (pal++ > 0x0f)
878: pal = 1;
879: flicker (pal);
880: break;
881:
882: case DOWN:
883: if (pal-- < 1)
884: pal = 0x0f;
885: flicker (pal);
886: break;
887:
888: case RIGHT:
889: if (++palette[pal] > 0x3f)
890: palette[pal] = 1;
891: DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
892: setpalette (palette);
893: DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
894: break;
895:
896: case LEFT:
897: if (--palette[pal] == 0)
898: palette[pal] = 0x3f;
899: DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
900: setpalette (palette);
901: DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
902: break;
903:
904: default:
905: ungetchar ();
906: return;
907: }
908: }
909: }
910:
911:
912:
913:
914: /** nextchar - get next character from keyboard
915: *
916: * flag = nextchar (pchar, wait);
917: *
918: * Entry char = pointer to character return location
919: * wait = 0 if delay until character entered
920: * wait = 1 if immediate return if no character
921: * Exit char = next character if found
922: * char = -scan code if extend character
923: * Return flag = TRUE if character read from keyboard
924: * flag = FALSE if no character read and immediate return
925: */
926:
927:
928: nextchar (pchar, wait)
929: int *pchar;
930: int wait;
931: {
932: int ret;
933:
934: if (!chvalid) {
935: if ((ret = KBDCHARIN ((struct KeyData far *)&key, wait, 0)) != 0) {
936: cleandisplay ();
937: printf ("Error %d return from KBDCHARIN\n", ret);
938: exit (1);
939: }
940: firstread = TRUE;
941: if ((key.status & 0x40) != 0x40)
942: return (FALSE);
943: }
944: chvalid = FALSE;
945: if (key.char_code == 0x00)
946: /* process extended ASCII character */
947: *pchar = -(int)key.scan_code;
948: else
949: *pchar = (int)key.char_code;
950: return (TRUE);
951: }
952:
953:
954:
955:
956:
957: /** ungetchar - unget character from keyboard
958: *
959: * ungetchar ();
960: *
961: * Entry none
962: * Exit previous character returned to keyboard
963: * Return none
964: */
965:
966:
967: ungetchar ()
968: {
969: if (firstread)
970: chvalid = TRUE;
971: }
972:
973:
974:
975:
976: /** setpalette - set EGA palette registers
977: *
978: * setpalette (palette);
979: *
980: * Entry palette = byte array of palette registers
981: * Exit palette registers written to EGA
982: * Return none
983: */
984:
985:
986: setpalette (p)
987: char *p;
988: {
989: int *ip;
990:
991: vstate.length = sizeof (struct VIOSTATE);
992: vstate.req_type = 0;
993: vstate.double_defined = 0;
994: for (ip = &vstate.palette0; ip <= &vstate.palette15; )
995: *ip++ = *p++;
996: if (VIOSETSTATE ((struct VIOSTATE far *)&vstate, 0) != 0) {
997: cleandisplay ();
998: printf ("Unable to set palette registers\n");
999: exit (1);
1000: }
1001: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.