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