xref: /freebsd/lib/libvgl/simple.c (revision e95923a2288fb2845c7be4822b1b92b2fc106d18)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1991-1997 Søren Schmidt
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer
12  *    in this position and unchanged.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33 
34 #include <signal.h>
35 #include <sys/fbio.h>
36 #include "vgl.h"
37 
38 static byte VGLSavePaletteRed[256];
39 static byte VGLSavePaletteGreen[256];
40 static byte VGLSavePaletteBlue[256];
41 
42 #define ABS(a)		(((a)<0) ? -(a) : (a))
43 #define SGN(a)		(((a)<0) ? -1 : 1)
44 #define min(x, y)	(((x) < (y)) ? (x) : (y))
45 #define max(x, y)	(((x) > (y)) ? (x) : (y))
46 
47 static void
48 color2mem(u_long color, byte *b, int len)
49 {
50   switch (len) {
51   case 4:
52     b[3] = (color >> 24) & 0xff;
53     /* fallthrough */
54   case 3:
55     b[2] = (color >> 16) & 0xff;
56     /* fallthrough */
57   case 2:
58     b[1] = (color >> 8) & 0xff;
59     /* fallthrough */
60   case 1:
61   default:
62     b[0] = color & 0xff;
63     break;
64   }
65 
66   return;
67 }
68 
69 static u_long
70 mem2color(byte *b, int len)
71 {
72   u_long color = 0;
73 
74   switch (len) {
75   case 4:
76     color |= (b[3] & 0xff) << 24;
77     /* fallthrough */
78   case 3:
79     color |= (b[2] & 0xff) << 16;
80     /* fallthrough */
81   case 2:
82     color |= (b[1] & 0xff) << 8;
83     /* fallthrough */
84   case 1:
85   default:
86     color |= (b[0] & 0xff);
87     break;
88   }
89 
90   return color;
91 }
92 
93 void
94 VGLSetXY(VGLBitmap *object, int x, int y, u_long color)
95 {
96   int offset;
97   byte b[4];
98 
99   VGLCheckSwitch();
100   if (x>=0 && x<object->VXsize && y>=0 && y<object->VYsize) {
101     if (object->Type == MEMBUF ||
102         !VGLMouseFreeze(x, y, 1, 1, 0x80000000 | color)) {
103       switch (object->Type) {
104       case MEMBUF:
105       switch (object->PixelBytes) {
106       case 2:
107         goto vidbuf16;
108       case 3:
109         goto vidbuf24;
110       case 4:
111         goto vidbuf32;
112       }
113       /* fallthrough */
114       case VIDBUF8:
115         object->Bitmap[y*object->VXsize+x]=((byte)color);
116         break;
117       case VIDBUF8S:
118 	object->Bitmap[VGLSetSegment(y*object->VXsize+x)]=((byte)color);
119 	break;
120       case VIDBUF16:
121 vidbuf16:
122       case VIDBUF24:
123 vidbuf24:
124       case VIDBUF32:
125 vidbuf32:
126 	color2mem(color, b, object->PixelBytes);
127         bcopy(b, &object->Bitmap[(y*object->VXsize+x) * object->PixelBytes],
128 		object->PixelBytes);
129         break;
130       case VIDBUF16S:
131       case VIDBUF24S:
132       case VIDBUF32S:
133 	color2mem(color, b, object->PixelBytes);
134 	offset = VGLSetSegment((y*object->VXsize+x) * object->PixelBytes);
135 	bcopy(b, &object->Bitmap[offset], object->PixelBytes);
136 	break;
137       case VIDBUF8X:
138         outb(0x3c4, 0x02);
139         outb(0x3c5, 0x01 << (x&0x3));
140 	object->Bitmap[(unsigned)(VGLAdpInfo.va_line_width*y)+(x/4)] = ((byte)color);
141 	break;
142       case VIDBUF4S:
143 	offset = VGLSetSegment(y*VGLAdpInfo.va_line_width + x/8);
144 	goto set_planar;
145       case VIDBUF4:
146 	offset = y*VGLAdpInfo.va_line_width + x/8;
147 set_planar:
148         outb(0x3c4, 0x02); outb(0x3c5, 0x0f);
149         outb(0x3ce, 0x00); outb(0x3cf, (byte)color & 0x0f);	/* set/reset */
150         outb(0x3ce, 0x01); outb(0x3cf, 0x0f);		/* set/reset enable */
151         outb(0x3ce, 0x08); outb(0x3cf, 0x80 >> (x%8));	/* bit mask */
152 	object->Bitmap[offset] |= (byte)color;
153       }
154     }
155     if (object->Type != MEMBUF)
156       VGLMouseUnFreeze();
157   }
158 }
159 
160 static u_long
161 __VGLGetXY(VGLBitmap *object, int x, int y)
162 {
163   int offset;
164   byte b[4];
165   int i;
166   u_long color;
167   byte mask;
168 
169   switch (object->Type) {
170     case MEMBUF:
171     switch (object->PixelBytes) {
172     case 2:
173       goto vidbuf16;
174     case 3:
175       goto vidbuf24;
176     case 4:
177       goto vidbuf32;
178     }
179     /* fallthrough */
180     case VIDBUF8:
181       return object->Bitmap[((y*object->VXsize)+x)];
182     case VIDBUF8S:
183       return object->Bitmap[VGLSetSegment(y*object->VXsize+x)];
184     case VIDBUF16:
185 vidbuf16:
186     case VIDBUF24:
187 vidbuf24:
188     case VIDBUF32:
189 vidbuf32:
190       bcopy(&object->Bitmap[(y*object->VXsize+x) * object->PixelBytes],
191 		b, object->PixelBytes);
192       return (mem2color(b, object->PixelBytes));
193     case VIDBUF16S:
194     case VIDBUF24S:
195     case VIDBUF32S:
196 	offset = VGLSetSegment((y*object->VXsize+x) * object->PixelBytes);
197 	bcopy(&object->Bitmap[offset], b, object->PixelBytes);
198 
199       return (mem2color(b, object->PixelBytes));
200     case VIDBUF8X:
201       outb(0x3ce, 0x04); outb(0x3cf, x & 0x3);
202       return object->Bitmap[(unsigned)(VGLAdpInfo.va_line_width*y)+(x/4)];
203     case VIDBUF4S:
204       offset = VGLSetSegment(y*VGLAdpInfo.va_line_width + x/8);
205       goto get_planar;
206     case VIDBUF4:
207       offset = y*VGLAdpInfo.va_line_width + x/8;
208 get_planar:
209       color = 0;
210       mask = 0x80 >> (x%8);
211       for (i = 0; i < VGLModeInfo.vi_planes; i++) {
212 	outb(0x3ce, 0x04); outb(0x3cf, i);
213 	color |= (((volatile VGLBitmap *)object)->Bitmap[offset] & mask) ?
214 		 (1 << i) : 0;
215       }
216       return color;
217   }
218   return 0;		/* XXX black? */
219 }
220 
221 u_long
222 VGLGetXY(VGLBitmap *object, int x, int y)
223 {
224   u_long color;
225 
226   VGLCheckSwitch();
227   if (x<0 || x>=object->VXsize || y<0 || y>=object->VYsize)
228     return 0;
229   if (object->Type != MEMBUF) {
230     color = VGLMouseFreeze(x, y, 1, 1, 0x40000000);
231     if (color & 0x40000000) {
232       VGLMouseUnFreeze();
233       return color & 0xffffff;
234     }
235   }
236   color = __VGLGetXY(object, x, y);
237   if (object->Type != MEMBUF)
238     VGLMouseUnFreeze();
239   return color;
240 }
241 
242  /*
243   * Symmetric Double Step Line Algorithm by Brian Wyvill from
244   * "Graphics Gems", Academic Press, 1990.
245   */
246 
247 #define SL_SWAP(a,b)           {a^=b; b^=a; a^=b;}
248 #define SL_ABSOLUTE(i,j,k)     ( (i-j)*(k = ( (i-j)<0 ? -1 : 1)))
249 
250 void
251 plot(VGLBitmap * object, int x, int y, int flag, u_long color)
252 {
253   /* non-zero flag indicates the pixels need swapping back. */
254   if (flag)
255     VGLSetXY(object, y, x, color);
256   else
257     VGLSetXY(object, x, y, color);
258 }
259 
260 
261 void
262 VGLLine(VGLBitmap *object, int x1, int y1, int x2, int y2, u_long color)
263 {
264   int dx, dy, incr1, incr2, D, x, y, xend, c, pixels_left;
265   int sign_x, sign_y, step, reverse, i;
266 
267   dx = SL_ABSOLUTE(x2, x1, sign_x);
268   dy = SL_ABSOLUTE(y2, y1, sign_y);
269   /* decide increment sign by the slope sign */
270   if (sign_x == sign_y)
271     step = 1;
272   else
273     step = -1;
274 
275   if (dy > dx) {	/* chooses axis of greatest movement (make dx) */
276     SL_SWAP(x1, y1);
277     SL_SWAP(x2, y2);
278     SL_SWAP(dx, dy);
279     reverse = 1;
280   } else
281     reverse = 0;
282   /* note error check for dx==0 should be included here */
283   if (x1 > x2) {      /* start from the smaller coordinate */
284     x = x2;
285     y = y2;
286 /*  x1 = x1;
287     y1 = y1; */
288   } else {
289     x = x1;
290     y = y1;
291     x1 = x2;
292     y1 = y2;
293   }
294 
295 
296   /* Note dx=n implies 0 - n or (dx+1) pixels to be set */
297   /* Go round loop dx/4 times then plot last 0,1,2 or 3 pixels */
298   /* In fact (dx-1)/4 as 2 pixels are already plotted */
299   xend = (dx - 1) / 4;
300   pixels_left = (dx - 1) % 4;  /* number of pixels left over at the
301            * end */
302   plot(object, x, y, reverse, color);
303   if (pixels_left < 0)
304     return;      /* plot only one pixel for zero length
305            * vectors */
306   plot(object, x1, y1, reverse, color);  /* plot first two points */
307   incr2 = 4 * dy - 2 * dx;
308   if (incr2 < 0) {    /* slope less than 1/2 */
309     c = 2 * dy;
310     incr1 = 2 * c;
311     D = incr1 - dx;
312 
313     for (i = 0; i < xend; i++) {  /* plotting loop */
314       ++x;
315       --x1;
316       if (D < 0) {
317         /* pattern 1 forwards */
318         plot(object, x, y, reverse, color);
319         plot(object, ++x, y, reverse, color);
320         /* pattern 1 backwards */
321         plot(object, x1, y1, reverse, color);
322         plot(object, --x1, y1, reverse, color);
323         D += incr1;
324       } else {
325         if (D < c) {
326           /* pattern 2 forwards */
327           plot(object, x, y, reverse, color);
328           plot(object, ++x, y += step, reverse,
329               color);
330           /* pattern 2 backwards */
331           plot(object, x1, y1, reverse, color);
332           plot(object, --x1, y1 -= step, reverse,
333               color);
334         } else {
335           /* pattern 3 forwards */
336           plot(object, x, y += step, reverse, color);
337           plot(object, ++x, y, reverse, color);
338           /* pattern 3 backwards */
339           plot(object, x1, y1 -= step, reverse,
340               color);
341           plot(object, --x1, y1, reverse, color);
342         }
343         D += incr2;
344       }
345     }      /* end for */
346 
347     /* plot last pattern */
348     if (pixels_left) {
349       if (D < 0) {
350         plot(object, ++x, y, reverse, color);  /* pattern 1 */
351         if (pixels_left > 1)
352           plot(object, ++x, y, reverse, color);
353         if (pixels_left > 2)
354           plot(object, --x1, y1, reverse, color);
355       } else {
356         if (D < c) {
357           plot(object, ++x, y, reverse, color);  /* pattern 2  */
358           if (pixels_left > 1)
359             plot(object, ++x, y += step, reverse, color);
360           if (pixels_left > 2)
361             plot(object, --x1, y1, reverse, color);
362         } else {
363           /* pattern 3 */
364           plot(object, ++x, y += step, reverse, color);
365           if (pixels_left > 1)
366             plot(object, ++x, y, reverse, color);
367           if (pixels_left > 2)
368             plot(object, --x1, y1 -= step, reverse, color);
369         }
370       }
371     }      /* end if pixels_left */
372   }
373   /* end slope < 1/2 */
374   else {        /* slope greater than 1/2 */
375     c = 2 * (dy - dx);
376     incr1 = 2 * c;
377     D = incr1 + dx;
378     for (i = 0; i < xend; i++) {
379       ++x;
380       --x1;
381       if (D > 0) {
382         /* pattern 4 forwards */
383         plot(object, x, y += step, reverse, color);
384         plot(object, ++x, y += step, reverse, color);
385         /* pattern 4 backwards */
386         plot(object, x1, y1 -= step, reverse, color);
387         plot(object, --x1, y1 -= step, reverse, color);
388         D += incr1;
389       } else {
390         if (D < c) {
391           /* pattern 2 forwards */
392           plot(object, x, y, reverse, color);
393           plot(object, ++x, y += step, reverse,
394               color);
395 
396           /* pattern 2 backwards */
397           plot(object, x1, y1, reverse, color);
398           plot(object, --x1, y1 -= step, reverse,
399               color);
400         } else {
401           /* pattern 3 forwards */
402           plot(object, x, y += step, reverse, color);
403           plot(object, ++x, y, reverse, color);
404           /* pattern 3 backwards */
405           plot(object, x1, y1 -= step, reverse, color);
406           plot(object, --x1, y1, reverse, color);
407         }
408         D += incr2;
409       }
410     }      /* end for */
411     /* plot last pattern */
412     if (pixels_left) {
413       if (D > 0) {
414         plot(object, ++x, y += step, reverse, color);  /* pattern 4 */
415         if (pixels_left > 1)
416           plot(object, ++x, y += step, reverse,
417               color);
418         if (pixels_left > 2)
419           plot(object, --x1, y1 -= step, reverse,
420               color);
421       } else {
422         if (D < c) {
423           plot(object, ++x, y, reverse, color);  /* pattern 2  */
424           if (pixels_left > 1)
425             plot(object, ++x, y += step, reverse, color);
426           if (pixels_left > 2)
427             plot(object, --x1, y1, reverse, color);
428         } else {
429           /* pattern 3 */
430           plot(object, ++x, y += step, reverse, color);
431           if (pixels_left > 1)
432             plot(object, ++x, y, reverse, color);
433           if (pixels_left > 2) {
434             if (D > c)  /* step 3 */
435               plot(object, --x1, y1 -= step, reverse, color);
436             else  /* step 2 */
437               plot(object, --x1, y1, reverse, color);
438           }
439         }
440       }
441     }
442   }
443 }
444 
445 void
446 VGLBox(VGLBitmap *object, int x1, int y1, int x2, int y2, u_long color)
447 {
448   VGLLine(object, x1, y1, x2, y1, color);
449   VGLLine(object, x2, y1, x2, y2, color);
450   VGLLine(object, x2, y2, x1, y2, color);
451   VGLLine(object, x1, y2, x1, y1, color);
452 }
453 
454 void
455 VGLFilledBox(VGLBitmap *object, int x1, int y1, int x2, int y2, u_long color)
456 {
457   int y;
458 
459   for (y=y1; y<=y2; y++) VGLLine(object, x1, y, x2, y, color);
460 }
461 
462 static inline void
463 set4pixels(VGLBitmap *object, int x, int y, int xc, int yc, u_long color)
464 {
465   if (x!=0) {
466     VGLSetXY(object, xc+x, yc+y, color);
467     VGLSetXY(object, xc-x, yc+y, color);
468     if (y!=0) {
469       VGLSetXY(object, xc+x, yc-y, color);
470       VGLSetXY(object, xc-x, yc-y, color);
471     }
472   }
473   else {
474     VGLSetXY(object, xc, yc+y, color);
475     if (y!=0)
476       VGLSetXY(object, xc, yc-y, color);
477   }
478 }
479 
480 void
481 VGLEllipse(VGLBitmap *object, int xc, int yc, int a, int b, u_long color)
482 {
483   int x = 0, y = b, asq = a*a, asq2 = a*a*2, bsq = b*b;
484   int bsq2 = b*b*2, d = bsq-asq*b+asq/4, dx = 0, dy = asq2*b;
485 
486   while (dx<dy) {
487     set4pixels(object, x, y, xc, yc, color);
488     if (d>0) {
489       y--; dy-=asq2; d-=dy;
490     }
491     x++; dx+=bsq2; d+=bsq+dx;
492   }
493   d+=(3*(asq-bsq)/2-(dx+dy))/2;
494   while (y>=0) {
495     set4pixels(object, x, y, xc, yc, color);
496     if (d<0) {
497       x++; dx+=bsq2; d+=dx;
498     }
499     y--; dy-=asq2; d+=asq-dy;
500   }
501 }
502 
503 static inline void
504 set2lines(VGLBitmap *object, int x, int y, int xc, int yc, u_long color)
505 {
506   if (x!=0) {
507     VGLLine(object, xc+x, yc+y, xc-x, yc+y, color);
508     if (y!=0)
509       VGLLine(object, xc+x, yc-y, xc-x, yc-y, color);
510   }
511   else {
512     VGLLine(object, xc, yc+y, xc, yc-y, color);
513   }
514 }
515 
516 void
517 VGLFilledEllipse(VGLBitmap *object, int xc, int yc, int a, int b, u_long color)
518 {
519   int x = 0, y = b, asq = a*a, asq2 = a*a*2, bsq = b*b;
520   int bsq2 = b*b*2, d = bsq-asq*b+asq/4, dx = 0, dy = asq2*b;
521 
522   while (dx<dy) {
523     set2lines(object, x, y, xc, yc, color);
524     if (d>0) {
525       y--; dy-=asq2; d-=dy;
526     }
527     x++; dx+=bsq2; d+=bsq+dx;
528   }
529   d+=(3*(asq-bsq)/2-(dx+dy))/2;
530   while (y>=0) {
531     set2lines(object, x, y, xc, yc, color);
532     if (d<0) {
533       x++; dx+=bsq2; d+=dx;
534     }
535     y--; dy-=asq2; d+=asq-dy;
536   }
537 }
538 
539 void
540 VGLClear(VGLBitmap *object, u_long color)
541 {
542   int offset;
543   int len;
544   int i, total = 0;
545   byte b[4];
546 
547   VGLCheckSwitch();
548   if (object->Type != MEMBUF)
549     VGLMouseFreeze(0, 0, object->Xsize, object->Ysize, color);
550   switch (object->Type) {
551   case MEMBUF:
552   switch (object->PixelBytes) {
553   case 2:
554     goto vidbuf16;
555   case 3:
556     goto vidbuf24;
557   case 4:
558     goto vidbuf32;
559   }
560   /* fallthrough */
561   case VIDBUF8:
562     memset(object->Bitmap, (byte)color, object->VXsize*object->VYsize);
563     break;
564 
565   case VIDBUF8S:
566     for (offset = 0; offset < object->VXsize*object->VYsize; ) {
567       VGLSetSegment(offset);
568       len = min(object->VXsize*object->VYsize - offset,
569 		VGLAdpInfo.va_window_size);
570       memset(object->Bitmap, (byte)color, len);
571       offset += len;
572     }
573     break;
574   case VIDBUF16:
575 vidbuf16:
576   case VIDBUF24:
577 vidbuf24:
578   case VIDBUF32:
579 vidbuf32:
580     color2mem(color, b, object->PixelBytes);
581     total = object->VXsize*object->VYsize*object->PixelBytes;
582     for (i = 0; i < total; i += object->PixelBytes)
583       bcopy(b, object->Bitmap + i, object->PixelBytes);
584     break;
585 
586   case VIDBUF16S:
587   case VIDBUF24S:
588   case VIDBUF32S:
589     color2mem(color, b, object->PixelBytes);
590     total = object->VXsize*object->VYsize*object->PixelBytes;
591     for (offset = 0; offset < total; ) {
592       VGLSetSegment(offset);
593       len = min(total - offset, VGLAdpInfo.va_window_size);
594       for (i = 0; i < len; i += object->PixelBytes)
595         bcopy(b, object->Bitmap + (offset + i) % VGLAdpInfo.va_window_size,
596               object->PixelBytes);
597       offset += len;
598     }
599     break;
600 
601   case VIDBUF8X:
602     /* XXX works only for Xsize % 4 = 0 */
603     outb(0x3c6, 0xff);
604     outb(0x3c4, 0x02); outb(0x3c5, 0x0f);
605     memset(object->Bitmap, (byte)color, VGLAdpInfo.va_line_width*object->VYsize);
606     break;
607 
608   case VIDBUF4:
609   case VIDBUF4S:
610     /* XXX works only for Xsize % 8 = 0 */
611     outb(0x3c4, 0x02); outb(0x3c5, 0x0f);
612     outb(0x3ce, 0x05); outb(0x3cf, 0x02);		/* mode 2 */
613     outb(0x3ce, 0x01); outb(0x3cf, 0x00);		/* set/reset enable */
614     outb(0x3ce, 0x08); outb(0x3cf, 0xff);		/* bit mask */
615     for (offset = 0; offset < VGLAdpInfo.va_line_width*object->VYsize; ) {
616       VGLSetSegment(offset);
617       len = min(object->VXsize*object->VYsize - offset,
618 		VGLAdpInfo.va_window_size);
619       memset(object->Bitmap, (byte)color, len);
620       offset += len;
621     }
622     outb(0x3ce, 0x05); outb(0x3cf, 0x00);
623     break;
624   }
625   if (object->Type != MEMBUF)
626     VGLMouseUnFreeze();
627 }
628 
629 void
630 VGLRestorePalette()
631 {
632   int i;
633 
634   outb(0x3C6, 0xFF);
635   inb(0x3DA);
636   outb(0x3C8, 0x00);
637   for (i=0; i<256; i++) {
638     outb(0x3C9, VGLSavePaletteRed[i]);
639     inb(0x84);
640     outb(0x3C9, VGLSavePaletteGreen[i]);
641     inb(0x84);
642     outb(0x3C9, VGLSavePaletteBlue[i]);
643     inb(0x84);
644   }
645   inb(0x3DA);
646   outb(0x3C0, 0x20);
647 }
648 
649 void
650 VGLSavePalette()
651 {
652   int i;
653 
654   outb(0x3C6, 0xFF);
655   inb(0x3DA);
656   outb(0x3C7, 0x00);
657   for (i=0; i<256; i++) {
658     VGLSavePaletteRed[i] = inb(0x3C9);
659     inb(0x84);
660     VGLSavePaletteGreen[i] = inb(0x3C9);
661     inb(0x84);
662     VGLSavePaletteBlue[i] = inb(0x3C9);
663     inb(0x84);
664   }
665   inb(0x3DA);
666   outb(0x3C0, 0x20);
667 }
668 
669 void
670 VGLSetPalette(byte *red, byte *green, byte *blue)
671 {
672   int i;
673 
674   for (i=0; i<256; i++) {
675     VGLSavePaletteRed[i] = red[i];
676     VGLSavePaletteGreen[i] = green[i];
677     VGLSavePaletteBlue[i] = blue[i];
678   }
679   VGLCheckSwitch();
680   outb(0x3C6, 0xFF);
681   inb(0x3DA);
682   outb(0x3C8, 0x00);
683   for (i=0; i<256; i++) {
684     outb(0x3C9, VGLSavePaletteRed[i]);
685     inb(0x84);
686     outb(0x3C9, VGLSavePaletteGreen[i]);
687     inb(0x84);
688     outb(0x3C9, VGLSavePaletteBlue[i]);
689     inb(0x84);
690   }
691   inb(0x3DA);
692   outb(0x3C0, 0x20);
693 }
694 
695 void
696 VGLSetPaletteIndex(byte color, byte red, byte green, byte blue)
697 {
698   VGLSavePaletteRed[color] = red;
699   VGLSavePaletteGreen[color] = green;
700   VGLSavePaletteBlue[color] = blue;
701   VGLCheckSwitch();
702   outb(0x3C6, 0xFF);
703   inb(0x3DA);
704   outb(0x3C8, color);
705   outb(0x3C9, red); outb(0x3C9, green); outb(0x3C9, blue);
706   inb(0x3DA);
707   outb(0x3C0, 0x20);
708 }
709 
710 void
711 VGLSetBorder(byte color)
712 {
713   VGLCheckSwitch();
714   inb(0x3DA);
715   outb(0x3C0,0x11); outb(0x3C0, color);
716   inb(0x3DA);
717   outb(0x3C0, 0x20);
718 }
719 
720 void
721 VGLBlankDisplay(int blank)
722 {
723   byte val;
724 
725   VGLCheckSwitch();
726   outb(0x3C4, 0x01); val = inb(0x3C5); outb(0x3C4, 0x01);
727   outb(0x3C5, ((blank) ? (val |= 0x20) : (val &= 0xDF)));
728 }
729