]> icculus.org git repositories - btb/d2x.git/blob - arch/dos/gr.c
remove rcs tags
[btb/d2x.git] / arch / dos / gr.c
1 /*
2  *
3  * Graphics functions for DOS.
4  *
5  *
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include <conf.h>
10 #endif
11
12 #include <stdio.h>
13 #include <string.h>
14 #include <io.h>
15 #include <dos.h>
16 #include <dpmi.h>
17 #include "gr.h"
18 #include "grdef.h"
19 #include "palette.h"
20 #include "maths.h"
21 #include "u_mem.h"
22 #include "u_dpmi.h"
23 #include "vesa.h"
24 #include "modex.h"
25 #include "error.h"
26
27 #ifdef __DJGPP__
28 #include <sys/nearptr.h>
29 #endif
30
31 static int last_r=0, last_g=0, last_b=0;
32
33 /* old gr.c stuff */
34 unsigned char * gr_video_memory = (unsigned char *)0xa0000;
35
36 char gr_pal_default[768];
37
38 int gr_installed = 0;
39
40 volatile ubyte * pVideoMode =  (volatile ubyte *)0x449;
41 volatile ushort * pNumColumns = (volatile ushort *)0x44a;
42 volatile ubyte * pNumRows = (volatile ubyte *)0x484;
43 volatile ushort * pCharHeight = (volatile ushort *)0x485;
44 volatile ushort * pCursorPos = (volatile ushort *)0x450;
45 volatile ushort * pCursorType = (volatile ushort *)0x460;
46 volatile ushort * pTextMemory = (volatile ushort *)0xb8000;
47
48 typedef struct screen_save {
49         ubyte   video_mode;
50         ubyte   is_graphics;
51         ushort  char_height;
52         ubyte           width;
53         ubyte           height;
54         ubyte           cursor_x, cursor_y;
55         ubyte           cursor_sline, cursor_eline;
56         ushort * video_memory;
57 } screen_save;
58
59 screen_save gr_saved_screen;
60
61 int gr_show_screen_info = 0;
62 extern int VGA_current_mode;
63
64 void gr_set_cellheight( ubyte height )
65 {
66         ubyte temp;
67
68    outp( 0x3d4, 9 );
69         temp = inp( 0x3d5 );
70    temp &= 0xE0;
71         temp |= height;
72         outp( 0x3d5, temp );
73 }
74
75 void gr_set_linear()
76 {
77         outpw( 0x3c4, 0xE04 );            // enable chain4 mode
78         outpw( 0x3d4, 0x4014 );           // turn on dword mode
79         outpw( 0x3d4, 0xa317 );           // turn off byte mode
80 }
81
82 void gr_16_to_256()
83 {
84         outpw( 0x3ce, 0x4005 );         // set Shift reg to 1
85
86         inp( 0x3da );                                   // dummy input
87
88         outp( 0x3c0, 0x30 );
89         outp( 0x3c0, 0x61 );               // turns on PCS & PCC
90
91         inp( 0x3da );                                   // dummy input
92
93         outp( 0x3c0, 0x33 );
94         outp( 0x3c0, 0 );
95 }
96
97 void gr_turn_screen_off()
98 {
99         ubyte temp;
100         temp = inp( 0x3da );
101         outp( 0x3c0, 0 );
102 }
103
104 void gr_turn_screen_on()
105 {
106         ubyte temp;
107         temp = inp( 0x3da );
108         outp( 0x3c0, 0x20 );
109 }
110
111 void gr_set_misc_mode( uint mode )
112 {
113         union REGS regs;
114
115         memset( &regs, 0, sizeof(regs) );
116         regs.w.ax = mode;
117         int386( 0x10, &regs, &regs );
118
119 }
120
121 void gr_set_3dbios_mode( uint mode )
122 {
123         union REGS regs;
124         memset( &regs, 0, sizeof(regs) );
125         regs.w.ax = 0x4fd0;
126         regs.w.bx = 0x3d00 | (mode & 0xff);
127         int386( 0x10, &regs, &regs );
128 }
129
130
131
132 void gr_set_text_25()
133 {
134         union REGS regs;
135
136         regs.w.ax = 3;
137         int386( 0x10, &regs, &regs );
138
139 }
140
141 void gr_set_text_43()
142 {
143         union REGS regs;
144
145         regs.w.ax = 0x1201;
146         regs.w.bx = 0x30;
147         int386( 0x10, &regs, &regs );
148
149         regs.w.ax = 3;
150         int386( 0x10, &regs, &regs );
151
152         regs.w.ax = 0x1112;
153         regs.w.bx = 0x0;
154         int386( 0x10, &regs, &regs );
155 }
156
157 void gr_set_text_50()
158 {
159         union REGS regs;
160
161         regs.w.ax = 0x1202;
162         regs.w.bx = 0x30;
163         int386( 0x10, &regs, &regs );
164
165         regs.w.ax = 3;
166         int386( 0x10, &regs, &regs );
167
168         regs.w.ax = 0x1112;
169         regs.w.bx = 0x0;
170         int386( 0x10, &regs, &regs );
171 }
172
173 ubyte is_graphics_mode()
174 {
175         byte tmp;
176         tmp = inp( 0x3DA );             // Reset flip-flip
177         outp( 0x3C0, 0x30 );            // Select attr register 10
178         tmp = inp( 0x3C1 );     // Get graphics/text bit
179         return tmp & 1;
180 }
181
182 void gr_setcursor(ubyte x, ubyte y, ubyte sline, ubyte eline)
183 {
184         union REGS regs;
185
186         memset( &regs, 0, sizeof(regs) );
187         regs.w.ax = 0x0200;
188         regs.w.bx = 0;
189         regs.h.dh = y;
190         regs.h.dl = x;
191         int386( 0x10, &regs, &regs );
192
193         memset( &regs, 0, sizeof(regs) );
194         regs.w.ax = 0x0100;
195         regs.h.ch = sline & 0xf;
196         regs.h.cl = eline & 0xf;
197         int386( 0x10, &regs, &regs );
198 }
199
200 void gr_getcursor(ubyte *x, ubyte *y, ubyte * sline, ubyte * eline)
201 {
202         union REGS regs;
203
204         memset( &regs, 0, sizeof(regs) );
205         regs.w.ax = 0x0300;
206         regs.w.bx = 0;
207         int386( 0x10, &regs, &regs );
208         *y = regs.h.dh;
209         *x = regs.h.dl;
210         *sline = regs.h.ch;
211         *eline = regs.h.cl;
212 }
213
214
215 int gr_save_mode()
216 {
217         int i;
218
219         gr_saved_screen.is_graphics = is_graphics_mode();
220         gr_saved_screen.video_mode = *pVideoMode;
221         
222         if (!gr_saved_screen.is_graphics)       {
223                 gr_saved_screen.width = *pNumColumns;
224                 gr_saved_screen.height = *pNumRows+1;
225                 gr_saved_screen.char_height = *pCharHeight;
226                 gr_getcursor(&gr_saved_screen.cursor_x, &gr_saved_screen.cursor_y, &gr_saved_screen.cursor_sline, &gr_saved_screen.cursor_eline );
227                 MALLOC(gr_saved_screen.video_memory,ushort, gr_saved_screen.width*gr_saved_screen.height );
228                 for (i=0; i < gr_saved_screen.width*gr_saved_screen.height; i++ )
229                         gr_saved_screen.video_memory[i] = pTextMemory[i];
230         }
231
232         if (gr_show_screen_info )       {
233                 printf( "Current video mode 0x%x:\n",  gr_saved_screen.video_mode );
234                 if (gr_saved_screen.is_graphics)
235                         printf( "Graphics mode\n" );
236                 else    {
237                         printf( "Text mode\n" );
238                         printf( "( %d columns by %d rows)\n", gr_saved_screen.width, gr_saved_screen.height );
239                         printf( "Char height is %d pixel rows\n", gr_saved_screen.char_height );
240                         printf( "Cursor of type 0x%x,0x%x is at (%d, %d)\n", gr_saved_screen.cursor_sline, gr_saved_screen.cursor_eline,gr_saved_screen.cursor_x, gr_saved_screen.cursor_y );
241                 }
242         }
243
244         return 0;
245 }
246
247 int isvga()
248 {
249         union REGS regs;
250
251         memset( &regs, 0, sizeof(regs) );
252         regs.w.ax = 0x1a00;
253         int386( 0x10, &regs, &regs );
254
255         if ( regs.h.al == 0x1a )
256                  return 1;
257
258         return 0;
259 }
260
261 void gr_restore_mode()
262 {
263         int i;
264
265         //gr_set_text_25(); 
266
267 #ifndef NOGRAPH
268         gr_palette_fade_out( gr_palette, 32, 0 );
269         gr_palette_set_gamma(0);
270         if ( gr_saved_screen.video_mode == 3 )  {
271                 switch( gr_saved_screen.height )          {
272                 case 43:        gr_set_text_43(); break;
273                 case 50:        gr_set_text_50(); break;
274                 default:        gr_set_text_25(); break;
275                 }
276         } else {
277                 gr_set_misc_mode(gr_saved_screen.video_mode);   
278         }
279         if (gr_saved_screen.is_graphics==0)     {
280                 gr_sync_display();
281                 gr_sync_display();
282                 gr_palette_read( gr_pal_default );
283                 gr_palette_clear();
284                 for (i=0; i < gr_saved_screen.width*gr_saved_screen.height; i++ )
285                         pTextMemory[i]=gr_saved_screen.video_memory[i];
286                 gr_setcursor( gr_saved_screen.cursor_x, gr_saved_screen.cursor_y, gr_saved_screen.cursor_sline, gr_saved_screen.cursor_eline );
287                 gr_palette_faded_out = 1;
288                 gr_palette_fade_in( gr_pal_default, 32, 0 );
289         }
290 #endif
291
292 }
293
294 void gr_close()
295 {
296         if (gr_installed==1)
297         {
298                 gr_installed = 0;
299                 gr_restore_mode();
300                 free(grd_curscreen);
301                 if( gr_saved_screen.video_memory ) {
302                         free(gr_saved_screen.video_memory);
303                         gr_saved_screen.video_memory = NULL;
304                 }
305         }
306 }
307
308 #ifndef __DJGPP__
309 int gr_vesa_setmode( int mode )
310 {
311         int retcode;
312
313         retcode=gr_vesa_checkmode( mode );
314         if ( retcode ) return retcode;
315
316         return gr_vesa_setmodea( mode );
317 }
318 #endif
319
320
321 int gr_set_mode(uint32_t mode)
322 {
323         int retcode;
324         unsigned int w,h,t,data, r;
325
326         //JOHNgr_disable_default_palette_loading();
327 #ifdef NOGRAPH
328 return 0;
329 #endif
330         switch(mode)
331         {
332         case SM_ORIGINAL:
333                 return 0;
334         case SM(320,200)://0:
335                 if (!isvga()) return 1;
336                 gr_set_misc_mode(0x13);
337                 w = 320; r = 320; h = 200; t=BM_LINEAR; data = (int)gr_video_memory;
338                 break;
339         case SM(640,400)://SM_640x400V:
340                 retcode = gr_vesa_setmode( 0x100 ); 
341                 if (retcode !=0 ) return retcode;
342                 w = 640; r = 640; h = 400; t=BM_SVGA; data = 0;
343                 break;
344         case SM(640,480)://SM_640x480V:
345                 retcode = gr_vesa_setmode( 0x101 ); 
346                 if (retcode !=0 ) return retcode;
347                 w = 640; r = 640; h = 480; t=BM_SVGA; data = 0;
348                 break;
349         case SM(800,600)://SM_800x600V:
350                 retcode = gr_vesa_setmode( 0x103 ); 
351                 if (retcode !=0 ) return retcode;
352                 w = 800; r = 800; h = 600; t=BM_SVGA; data = 0;
353                 break;
354         case SM(1024,768)://SM_1024x768V:
355                 retcode = gr_vesa_setmode( 0x105 ); 
356                 if (retcode !=0 ) return retcode;
357                 w = 1024; r = 1024; h = 768; t=BM_SVGA; data = 0;
358                 break;
359 /*      case SM_640x480V15:
360                 retcode = gr_vesa_setmode( 0x110 ); 
361                 if (retcode !=0 ) return retcode;
362                 w = 640; r = 640*2; h=480; t=BM_SVGA15; data = 0;
363                 break;
364         case SM_800x600V15:
365                 retcode = gr_vesa_setmode( 0x113 ); 
366                 if (retcode !=0 ) return retcode;
367                 w = 800; r = 800*2; h=600; t=BM_SVGA15; data = 0;
368                 break;*/
369 //      case 19:
370         case SM(320,100):
371                 if (!isvga()) return 1;
372                 gr_set_misc_mode(0x13); 
373 //              {
374 //                      ubyte x;
375 //                      x = inp( 0x3c5 );
376 //                      x |= 8;
377 //                      outp( 0x3c5, x );
378 //              }
379                 gr_set_cellheight( 3 );
380
381                 w = 320; r = 320; h = 100; t=BM_LINEAR; data = (int)gr_video_memory;
382                 break;
383 /*      case 20:
384                 retcode = gr_vesa_setmode( 0x102 ); 
385                 //gr_enable_default_palette_loading();
386                 if (retcode !=0 ) return retcode;
387                 gr_16_to_256();
388                 gr_set_linear();
389                 //gr_set_cellheight( 1 );
390                 gr_vesa_setlogical( 400 );
391                 w = 400; r = 400; h = 600; t=BM_SVGA; data = 0;
392                 break;
393         case 21:
394                 if (!isvga()) return 1;
395                 gr_set_misc_mode(0xd);  
396                 gr_16_to_256();
397                 gr_set_linear();
398                 gr_set_cellheight( 3 );
399                 w = 160; r = 160; h = 100; t=BM_LINEAR; data = (int)gr_video_memory;
400                 break;
401         case //22:                      // 3dmax 320x400
402                 if (!isvga()) return 1;
403                 gr_set_3dbios_mode(0x31);
404                 //w = 320; r = 320/4; h = 400; t=BM_MODEX; data = 0;
405                 w = 320; r = 320; h = 400; t=BM_SVGA; data = 0;
406                 break;*/
407         default:
408                 if (!isvga()) return 1;
409                 if (mode==SM(320,240))
410                         w = gr_modex_setmode( 2 );
411                 else if (mode==SM(320,400))
412                         w = gr_modex_setmode( 6 );
413                 else
414                         Error("unhandled vid mode\n");
415                 //gr_enable_default_palette_loading();
416                 h = w & 0xffff; w = w >> 16; r = w / 4;t = BM_MODEX; data = 0;
417                 break;
418         }
419         gr_palette_clear();
420
421         memset( grd_curscreen, 0, sizeof(grs_screen));
422         grd_curscreen->sc_mode = mode;
423         grd_curscreen->sc_w = w;
424         grd_curscreen->sc_h = h;
425         grd_curscreen->sc_aspect = fixdiv(grd_curscreen->sc_w*3,grd_curscreen->sc_h*4);
426         grd_curscreen->sc_canvas.cv_bitmap.bm_x = 0;
427         grd_curscreen->sc_canvas.cv_bitmap.bm_y = 0;
428         grd_curscreen->sc_canvas.cv_bitmap.bm_w = w;
429         grd_curscreen->sc_canvas.cv_bitmap.bm_h = h;
430         grd_curscreen->sc_canvas.cv_bitmap.bm_rowsize = r;
431         grd_curscreen->sc_canvas.cv_bitmap.bm_type = t;
432         grd_curscreen->sc_canvas.cv_bitmap.bm_data = (unsigned char *)data;
433         VGA_current_mode = mode;
434         gr_set_current_canvas(NULL);
435
436         //gr_enable_default_palette_loading();
437 //        gamefont_choose_game_font(w,h);
438
439         return 0;
440 }
441
442 int gr_init(void)
443 {
444         int org_gamma;
445         int retcode;
446         int mode = SM(320,200);
447
448         // Only do this function once!
449         if (gr_installed==1)
450                 return 3;
451
452 #ifdef __DJGPP__
453         if (!__djgpp_nearptr_enable()) {
454                 printf("nearptr enable=%x\n", __dpmi_error);
455                 return 10;
456         }
457 #ifndef SAVEGR
458         gr_video_memory = (unsigned char *)(__djgpp_conventional_base + 0xa0000);
459 #else
460         gr_video_memory=(unsigned char *)-1;
461 #endif
462         pVideoMode =  (volatile ubyte *)(__djgpp_conventional_base+0x449);
463         pNumColumns = (volatile ushort *)(__djgpp_conventional_base+0x44a);
464         pNumRows = (volatile ubyte *)(__djgpp_conventional_base+0x484);
465         pCharHeight = (volatile ushort *)(__djgpp_conventional_base+0x485);
466         pCursorPos = (volatile ushort *)(__djgpp_conventional_base+0x450);
467         pCursorType = (volatile ushort *)(__djgpp_conventional_base+0x460);
468         pTextMemory = (volatile ushort *)(__djgpp_conventional_base+0xb8000);
469 #endif
470 #ifndef __DJGPP__
471         if (gr_init_A0000())
472                 return 10;
473 #endif
474
475         // Save the current text screen mode
476         if (gr_save_mode()==1)
477                 return 2;
478
479 #ifndef NOGRAPH
480         // Save the current palette, and fade it out to black.
481         gr_palette_read( gr_pal_default );
482         gr_palette_faded_out = 0;
483         org_gamma = gr_palette_get_gamma();
484         gr_palette_set_gamma( 0 );
485         gr_palette_fade_out( gr_pal_default, 32, 0 );
486         gr_palette_clear();
487         gr_palette_set_gamma( org_gamma );
488         gr_sync_display();
489         gr_sync_display();
490 #endif
491
492 #ifdef __DJGPP__
493 #ifdef SAVEGR
494         __djgpp_nearptr_disable();
495 #endif
496 #endif
497
498         MALLOC( grd_curscreen,grs_screen,1 );
499         memset( grd_curscreen, 0, sizeof(grs_screen));
500
501         // Set the mode.
502         if ((retcode=gr_set_mode(mode)))
503         {
504                 gr_restore_mode();
505                 return retcode;
506         }
507         //JOHNgr_disable_default_palette_loading();
508
509         // Set all the screen, canvas, and bitmap variables that
510         // aren't set by the gr_set_mode call:
511         grd_curscreen->sc_canvas.cv_color = 0;
512         grd_curscreen->sc_canvas.cv_drawmode = 0;
513         grd_curscreen->sc_canvas.cv_font = NULL;
514         grd_curscreen->sc_canvas.cv_font_fg_color = 0;
515         grd_curscreen->sc_canvas.cv_font_bg_color = 0;
516         gr_set_current_canvas( &grd_curscreen->sc_canvas );
517
518 #if 0
519         if (!dpmi_allocate_selector( &gr_fade_table, 256*GR_FADE_LEVELS, &gr_fade_table_selector ))
520                 Error( "Error allocating fade table selector!" );
521
522         if (!dpmi_allocate_selector( &gr_palette, 256*3, &gr_palette_selector ))
523                 Error( "Error allocating palette selector!" );
524 #endif
525
526 //      if (!dpmi_allocate_selector( &gr_inverse_table, 32*32*32, &gr_inverse_table_selector ))
527 //              Error( "Error allocating inverse table selector!" );
528
529
530         // Set flags indicating that this is installed.
531         gr_installed = 1;
532 #ifdef __GNUC__
533
534         atexit((void (*)) gr_close);
535 #else
536         atexit(gr_close);
537 #endif
538         return 0;
539 }
540
541 int gr_mode13_checkmode()
542 {
543         if (isvga()) 
544                 return 0;
545         else
546                 return 1;
547 }
548
549 //  0=Mode set OK
550 //  1=No VGA adapter installed
551 //  2=Program doesn't support this VESA granularity
552 //  3=Monitor doesn't support that VESA mode.:
553 //  4=Video card doesn't support that VESA mode.
554 //  5=No VESA driver found.
555 //  6=Bad Status after VESA call/
556 //  7=Not enough DOS memory to call VESA functions.
557 //  8=Error using DPMI.
558 //  9=Error setting logical line width.
559 // 10=Error allocating selector for A0000h
560 // 11=Not a valid mode support by gr.lib
561
562 int gr_check_mode(uint32_t mode)
563 {
564         switch(mode)
565         {
566         case SM(320,100)://19:
567         case SM(320,200):
568         case SM(320,240):
569         case SM(360,200):
570         case SM(360,240):
571         case SM(376,282):
572         case SM(320,400):
573         case SM(320,480):
574         case SM(360,400):
575         case SM(360,480):
576         case SM(360,360):
577         case SM(376,308):
578         case SM(376,564):               return gr_mode13_checkmode();
579         case SM(640,400):               return gr_vesa_checkmode( 0x100 ); 
580         case SM(640,480):       return gr_vesa_checkmode( 0x101 ); 
581         case SM(800,600):       return gr_vesa_checkmode( 0x103 ); 
582         case SM(1024,768):      return gr_vesa_setmode( 0x105 ); 
583 //      case SM_640x480V15:     return gr_vesa_setmode( 0x110 ); 
584 //      case SM_800x600V15:     return gr_vesa_setmode( 0x113 ); 
585         }
586         return 11;
587 }
588
589 /* Palette Stuff Starts Here... */
590
591 void gr_palette_step_up( int r, int g, int b )
592 {
593         int i;
594         ubyte *p;
595         int temp;
596
597         if (gr_palette_faded_out) return;
598
599         if ( (r==last_r) && (g==last_g) && (b==last_b) ) return;
600
601         last_r = r; last_g = g; last_b = b;
602
603         outp( 0x3c6, 0xff );
604         outp( 0x3c8, 0 );
605         p=gr_palette;
606
607         for (i=0; i<256; i++ )  {
608                 temp = (int)(*p++) + r + gr_palette_gamma;
609                 if (temp<0) temp=0;
610                 else if (temp>63) temp=63;
611                 outp( 0x3c9, temp );
612                 temp = (int)(*p++) + g + gr_palette_gamma;
613                 if (temp<0) temp=0;
614                 else if (temp>63) temp=63;
615                 outp( 0x3c9, temp );
616                 temp = (int)(*p++) + b + gr_palette_gamma;
617                 if (temp<0) temp=0;
618                 else if (temp>63) temp=63;
619                 outp( 0x3c9, temp );
620         }
621 }
622
623
624 void gr_palette_clear()
625 {
626         int i;
627         outp( 0x3c6, 0xff );
628         outp( 0x3c8, 0 );
629         for (i=0; i<768; i++ )  {
630                 outp( 0x3c9, 0 );
631         }
632         gr_palette_faded_out = 1;
633 }
634
635 void gr_palette_load( ubyte * pal )
636 {
637         int i;
638         ubyte c;
639         outp( 0x3c6, 0xff );
640         outp( 0x3c8, 0 );
641         for (i=0; i<768; i++ )  {
642                 c = pal[i] + gr_palette_gamma;
643                 if ( c > 63 ) c = 63;
644                 outp( 0x3c9,c);
645                 gr_current_pal[i] = pal[i];
646         }
647         gr_palette_faded_out = 0;
648
649         init_computed_colors();
650 }
651
652
653 int gr_palette_fade_out(ubyte *pal, int nsteps, int allow_keys )
654 {
655         ubyte c;
656         int i,j;
657         fix fade_palette[768];
658         fix fade_palette_delta[768];
659
660         if (gr_palette_faded_out) return 0;
661
662         if (!pal)
663                 pal = gr_current_pal;
664
665         for (i=0; i<768; i++ )  {
666                 fade_palette[i] = i2f(pal[i]+gr_palette_gamma);
667                 fade_palette_delta[i] = fade_palette[i] / nsteps;
668         }
669
670         for (j=0; j<nsteps; j++ )       {
671                 gr_sync_display();
672                 outp( 0x3c6, 0xff );
673                 outp( 0x3c8, 0 );
674                 for (i=0; i<768; i++ )  {
675                         fade_palette[i] -= fade_palette_delta[i];
676                         if (fade_palette[i] < 0 )
677                                 fade_palette[i] = 0;
678                         c = f2i(fade_palette[i]);
679                         if ( c > 63 ) c = 63;
680                         outp( 0x3c9, c );
681                 }
682         }
683         gr_palette_faded_out = 1;
684         return 0;
685 }
686
687 int gr_palette_fade_in(ubyte *pal, int nsteps, int allow_keys)
688 {
689         int i,j;
690         ubyte c;
691         fix fade_palette[768];
692         fix fade_palette_delta[768];
693
694
695         if (!gr_palette_faded_out) return 0;
696
697         for (i=0; i<768; i++ )  {
698                 gr_current_pal[i] = pal[i];
699                 fade_palette[i] = 0;
700                 fade_palette_delta[i] = i2f(pal[i]+gr_palette_gamma) / nsteps;
701         }
702
703         for (j=0; j<nsteps; j++ )       {
704                 gr_sync_display();
705                 outp( 0x3c6, 0xff );
706                 outp( 0x3c8, 0 );
707                 for (i=0; i<768; i++ )  {
708                         fade_palette[i] += fade_palette_delta[i];
709                         if (fade_palette[i] > i2f(pal[i]+gr_palette_gamma) )
710                                 fade_palette[i] = i2f(pal[i]+gr_palette_gamma);
711                         c = f2i(fade_palette[i]);
712                         if ( c > 63 ) c = 63;
713                         outp( 0x3c9, c );
714                 }
715         }
716         gr_palette_faded_out = 0;
717         return 0;
718 }
719
720 void gr_palette_read(ubyte * palette)
721 {
722         int i;
723         outp( 0x3c6, 0xff );
724         outp( 0x3c7, 0 );
725         for (i=0; i<768; i++ )  {
726                 *palette++ = inp( 0x3c9 );
727         }
728 }
729
730 void gr_update(void)
731 { }