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