source: abuse/branches/pd/macabuse/imlib/port/dos4gw/video.c @ 636

Last change on this file since 636 was 49, checked in by Sam Hocevar, 15 years ago
  • Imported original public domain release, for future reference.
  • Property svn:keywords set to Id
File size: 11.4 KB
Line 
1// Watcom graphics support
2
3
4#include "globals.hpp"
5#include "system.h"
6#include "video.hpp"
7#include "dos.h"
8#include "macs.hpp"
9#include "bitmap.h"
10#include "image.hpp"
11#include "palette.hpp"
12#include "jmalloc.hpp"
13#include "doscall.hpp"
14#include <conio.h>
15
16extern unsigned long xres, yres;
17#define vga_getgraphmem() ((unsigned char *)VESA_video_mem)
18#define vga_setpage(x) (VESA_set_bank(x))
19#define WinAAttributes() vesa_mode_info[2]
20#define WinBAttributes() vesa_mode_info[3]
21#define WinGranularity() (*((unsigned short *)(vesa_mode_info+4)))
22#define WinSize() (*((unsigned short *)(vesa_mode_info+6)))
23#define WinASegment() (*((unsigned short *)(vesa_mode_info+8)))
24#define WinBSegment() (*((unsigned short *)(vesa_mode_info+10)))
25#define BankSize() vesa_mode_info[0x1c]
26#define WINDOW_A 0
27#define WINDOW_B 1
28#define WINDOW_DEFINED 1
29#define WINDOW_WRITABLE 4
30
31unsigned char current_background;
32
33extern palette *lastl;
34int vmode,VESA_write_window=0;
35image *screen;
36unsigned char *VESA_video_mem;
37char *dos_pal_memory=NULL;
38unsigned char *vesa_mode_info=NULL;
39int write_bank;
40int gran_shift=0;
41
42#include <i86.h>
43
44#define MKPTR(x)  ((   (((unsigned long)x)&0xffff0000)>>12)+  (((unsigned long)x)&0xffff))
45
46#pragma pack( 1 ) // pack to bytes boundardy
47
48
49/* VESA video card capabilities block  */
50struct  ModeInfoBlock {
51        short  ModeAttributes;
52        char WinAAttributes;
53        char WinBAttributes;
54        unsigned short WinGranularity;
55        unsigned short  WinSize;
56        unsigned short  WinASegment;
57        unsigned short  WinBSegment;
58        unsigned long *WinFuncPtr;
59        short  BytesPerScanLine;
60        short  XResolution;
61        short  YResolution;
62        char XCharSize;
63        char YCharSize;
64        char NumberOfPlanes;
65        char BitsPerPixel;
66        char NumberOfBanks;
67        char MemoryModel;
68        char BankSize;
69        char NumberOfImagePages;
70        char SizeOfBank;
71        char RedMaskSize;
72        char RedFieldPosition;
73        char GreenMaskSize;
74        char GreenFieldPosition;
75        char BlueMaskSize;
76        char BlueFieldPosition;
77        char RsvdMaskSize;
78        char RsvdFieldPosition;
79        char DirectColorModeInfo;
80        char Reserved[216];
81        } vesa_info;
82
83struct VgaInfoBlock
84{
85  unsigned char       VESASignature[4];
86  unsigned short      ver;
87  unsigned long       OEMStringPtr;
88  unsigned char       Capabilities[4];
89  unsigned long       VideoModePtr;
90  unsigned short      TotalMemory;
91  unsigned char       Reserved[236];
92} ;
93
94#pragma pack( ) // pack back to normal
95
96
97void get_VESA_mode_info(ModeInfoBlock *s, unsigned short mode)
98{
99  int size=sizeof(ModeInfoBlock)<256 ? 256 : sizeof(ModeInfoBlock);
100  ModeInfoBlock *k=(ModeInfoBlock *)alloc_low_memory(size);
101  if (!k)
102  {
103    printf("Memory error : could not alloc low memory for VESA mode info structure\n");
104    exit(0);
105  } 
106
107  rminfo rm;
108  memset(&rm,0,sizeof(rm));
109  rm.eax=0x4f01;
110  rm.ecx=mode;
111  rm.es=((long)(k))>>4;
112  rm.edi=0;       
113  RM_intr(0x10,&rm);
114
115  memcpy(s,k,sizeof(ModeInfoBlock));
116 
117  free_low_memory(k);
118}
119
120int usable_mode(ModeInfoBlock *m)
121{
122
123  if ((m->ModeAttributes&1)==1 &&        // mode available?
124      (m->ModeAttributes&8)==8 &&        // color mode?
125      (m->ModeAttributes&16)==16 &&        // graphics mode?
126      (m->NumberOfPlanes==1)   &&        // packed pixel form
127      (m->BitsPerPixel==8)     &&        // 256 color mode
128      (m->MemoryModel==4)                // VESA packed pixel
129      )
130    return 1;
131  else return 0;
132}
133
134int get_VESA_mode(char **s)
135{
136  int get_xres,get_yres,show_menu=1,found=0;
137
138  if (sscanf(s[0],"%d",&get_xres)!=1 || sscanf(s[1],"%d",&get_yres)!=1)
139  {
140    show_menu=1;
141    found=1;
142  }
143
144  VgaInfoBlock *b=(VgaInfoBlock *)alloc_low_memory(sizeof(VgaInfoBlock));
145
146  if (!b)
147  {
148    printf("Memory error : could not alloc low memory for VESA mode info structure\n");
149    exit(0);
150  } 
151 
152  rminfo rm;
153  memset(&rm,0,sizeof(rm));
154  rm.eax=0x4f00;
155  rm.es=((long)(b))>>4;
156  rm.edi=0;       
157  RM_intr(0x10,&rm);
158
159  if (memcmp(b->VESASignature,"VESA",4))
160  {
161    printf("No VESA driver detected.  You need to install a VESA TSR.\n");
162    free_low_memory(b);
163    exit(0);
164  }
165  if ((b->ver>>8)==0 || (b->ver&&0xff)>2)
166  {
167    printf("Your VESA driver is out dated, please upgrade.\n");
168    free_low_memory(b);
169    exit(0);
170  }
171
172  VESA_video_mem=(unsigned char *)MKPTR(b->VideoModePtr);
173 
174  printf("Video card info : %s\n",(char *)MKPTR(b->OEMStringPtr));
175  short *modes=(short *)MKPTR(b->VideoModePtr);   // type cast low mem pointer
176
177  while (*modes!=-1 && !found)
178  {
179    struct ModeInfoBlock m;
180    get_VESA_mode_info(&m,*modes);
181    if (usable_mode(&m))
182    {                     // this is a usable mode
183      if (m.XResolution==get_xres && m.YResolution==get_yres)
184      {
185        free_low_memory(b);
186        return *modes;
187      }
188    }   
189    modes++;
190  }
191
192  if (show_menu)
193  {
194    int i=1;
195    printf("Bad resoultion size or size not supported by VESA driver\n"
196           "Please choice one of the below :\n");
197    modes=(short *)MKPTR(b->VideoModePtr);
198    while (*modes!=-1)            // list all chosable modes
199    {
200      struct ModeInfoBlock m;
201      get_VESA_mode_info(&m,*modes);
202
203      if (usable_mode(&m))
204      {
205        printf("%d) %d X %d\n",i,m.XResolution,m.YResolution);
206        i++;
207      }
208      modes++;
209    }
210
211    int d=0;
212    do
213    {
214      fprintf(stderr,"Enter mode # (1-%d)>",i-1);
215      char ln[100];
216      fgets(ln,100,stdin);
217      if (!sscanf(ln,"%d",&d))
218        d=0;
219    } while (!d);
220    d--;
221
222    modes=(short *)MKPTR(b->VideoModePtr);
223    while (*modes!=-1)
224    {
225      struct ModeInfoBlock m;
226      get_VESA_mode_info(&m,*modes);
227      if (usable_mode(&m))
228      {
229        if (d) d--;
230        else return *modes;
231      }
232      modes++;
233    }
234
235    printf("Your VESA driver is reporting incorrect information, try getting\n"
236           "univbe or univesa from any simtel mirror ftp site such as\n"
237           "wuarchive.wustl.edu.\n");
238    free_low_memory(b);
239    exit(0);
240  }
241
242  free_low_memory(b);
243  return found;
244}
245
246void VESA_set_bank(int x)
247{
248  if (vmode!=0x13)
249  {
250    rminfo rm;
251    memset(&rm,0,sizeof(rm));
252    rm.eax=0x4f05;
253    rm.ebx=VESA_write_window;
254    rm.edx=x<<gran_shift;
255    RM_intr(0x10,&rm);
256  }
257}
258
259int VESA_get_mode()
260{
261  rminfo rm;
262  memset(&rm,0,sizeof(rm));
263  rm.eax=0x4f03;
264  RM_intr(0x10,&rm);
265  return rm.ebx&0xffff;
266}
267
268int VESA_set_mode(int mode)
269{
270  rminfo rm;
271  memset(&rm,0,sizeof(rm));
272  if (mode!=19 && mode!=3)
273  {
274    rm.eax=0x4f02;
275    rm.ebx=mode;
276    RM_intr(0x10,&rm);
277    vmode=mode;
278
279    if (VESA_get_mode()==mode)
280    {
281      get_VESA_mode_info(&vesa_info,mode);
282
283      if ((vesa_info.WinAAttributes & WINDOW_DEFINED) &&
284          (vesa_info.WinAAttributes & WINDOW_WRITABLE))
285      {
286        VESA_write_window=WINDOW_A;
287        VESA_video_mem=(unsigned char *)((long)vesa_info.WinASegment<<4);
288      }
289      else if ((vesa_info.WinBAttributes & WINDOW_DEFINED) &&         
290               (vesa_info.WinBAttributes & WINDOW_WRITABLE))
291      {
292        VESA_write_window=WINDOW_B;
293        VESA_video_mem=(unsigned char *)((long)vesa_info.WinBSegment<<4);
294      }
295      else VESA_video_mem=(unsigned char *)0xa0000;
296
297      xres=vesa_info.XResolution-1;
298      yres=vesa_info.YResolution-1;
299
300      if (vesa_info.WinGranularity==1)  // 1K pages
301        gran_shift=6;
302      else if (vesa_info.WinGranularity==2)  // 2K pages
303        gran_shift=5;
304      else if (vesa_info.WinGranularity==4)  // 4K pages
305        gran_shift=4;
306      else if (vesa_info.WinGranularity==8)  // 8K pages
307        gran_shift=3;
308      else if (vesa_info.WinGranularity==16)  // 16K pages
309        gran_shift=2;
310      else if (vesa_info.WinGranularity==32)  // 16K pages
311        gran_shift=1;
312      else if (vesa_info.WinGranularity==64)  // 16K pages
313        gran_shift=0;
314      else
315      {
316        printf("VESA : window granularity not supported (%d)\n",vesa_info.WinGranularity);
317        exit(0);
318      }
319
320     
321
322//      exit(0);
323      return 1;
324    } else return 0;
325  }
326  else
327  {
328    vmode=mode;
329    rm.eax=mode;
330    RM_intr(0x10,&rm);
331    VESA_video_mem=(unsigned char *)0xa0000;
332    VESA_write_window=WINDOW_A;
333    xres=320-1;
334    yres=200-1;
335    return 1;
336  }
337}
338
339void set_mode(video_mode lmode, int argc, char **argv)
340{
341  int i,j;
342  int mode;
343
344  if (lmode==VMODE_320x200)
345  {
346    mode=19;
347    xres=320; yres=200;
348  }
349  else
350  {
351    char *prm []={"640","480"};
352    mode=get_VESA_mode(prm);
353  }
354
355
356  if (!VESA_set_mode(mode))
357  {
358    printf("Unable to set video mode.  The correct VESA driver is not loaded\n"
359           "or it does not support this video mode.\n");
360    exit(1);
361  }
362
363  screen=new image(xres+1,yres+1,NULL,2);
364  screen->clear();
365  update_dirty(screen);
366
367}
368
369int get_vmode()
370{ return vmode; }
371
372void close_graphics()
373{
374  if (lastl)
375    delete lastl;
376  lastl=NULL;
377  VESA_set_mode(3);  // switch to text mode
378  delete screen;
379}
380
381void put_part(image *im, int x, int y, int x1, int y1, int x2, int y2)
382{
383  unsigned short screen_off;
384  int i,ys,ye,xs,xe,page,last_page=-1,yy;
385  long breaker;
386  unsigned char *screen_addr,*line_addr;
387
388  if (y>(int)yres || x>(int)xres) return ;
389  CHECK(y1>=0 && y2>=y1 && x1>=0 && x2>=x1);
390
391
392  if (y<0)
393  { y1+=-y; y=0; }
394  ys=y1;
395  if (y+(y2-y1)>=(int)yres)
396    ye=(int)yres-y+y1-1;
397  else ye=y2;
398
399  if (x<0)
400  { x1+=-x; x=0; }
401  xs=x1;
402  if (x+(x2-x1)>=(int)xres)
403    xe=(int)xres-x+x1-1;
404  else xe=x2;
405  if (xs>xe || ys>ye) return ;
406
407  int virtual_screen_width=im->width();
408  line_addr=im->scan_line(ys)+xs;
409
410  for (yy=ys;yy<=ye;yy++)
411  {
412    page=(long)y*(long)(xres+1)>>16;
413    if (page!=last_page)
414    { last_page=page;
415      vga_setpage(page);
416    }
417
418    // find the memory offset for the scan line of interest
419    screen_off=((long)y*(long)(xres+1))&0xffff;
420
421    // breaker is the number of bytes beofer the page split
422    breaker=(long)0xffff-(long)screen_off+1;
423
424    if (breaker>x+xe-xs)
425      memcpy(vga_getgraphmem()+screen_off+x,line_addr,xe-xs+1);
426    else if (breaker<=x)
427    { last_page++;
428      vga_setpage(last_page);
429      memcpy(vga_getgraphmem()+x-breaker,line_addr,xe-xs+1);
430    }
431    else
432    {
433      memcpy(vga_getgraphmem()+screen_off+x,line_addr,breaker-x);
434      last_page++;
435      vga_setpage(last_page);
436      memcpy(vga_getgraphmem(),line_addr+breaker-x,xe-xs-(breaker-x)+1);
437    }
438    y++;
439    line_addr+=virtual_screen_width;
440  }
441}
442
443void put_image(image *im, int x, int y)
444{ put_part(im,x,y,0,0,im->width()-1,im->height()-1); }
445
446
447void update_dirty(image *im, int xoff, int yoff)
448{
449
450  int count,x1,y1,x2,y2;
451  dirty_rect *dr,*q;
452  image *Xim;
453  CHECK(im->special);  // make sure the image has the ablity to contain dirty areas
454  if (im->special->keep_dirt==0)
455    put_image(im,0,0);
456  else
457  {
458    count=im->special->dirties.number_nodes();
459    if (!count) return;  // if nothing to update, return
460    dr=(dirty_rect *)im->special->dirties.first();
461    while (count>0)
462    {
463/*      if (dr->dx1+xoff<0) dr->dx1=0-xoff;
464      if (dr->dy1+yoff<0) dr->dy1=0-yoff;
465      if (dr->dx2+xoff>xres) dr->dx2=xres-xoff;
466      if (dr->dy2+yres>yres) dr->dy2=yres-yoff;
467      if (dr->dx1<=dr->dx2 && dr->dy1<=dr->dy2) */
468      put_part(im,dr->dx1+xoff,dr->dy1+yoff,dr->dx1,dr->dy1,dr->dx2,dr->dy2);
469      q=dr;
470      dr=(dirty_rect *)dr->next();
471      im->special->dirties.unlink((linked_node *)q);
472      delete q;
473      count--;
474    }
475  }
476}
477
478
479void palette::load()
480{
481  int i;
482  unsigned char *a=(unsigned char *)addr();
483  if (lastl)
484    delete lastl;
485  lastl=copy();
486
487  outp(0x3c8,0);
488  for (i=0;i<768;i++,a++)
489    outp(0x3c9,(*a)>>2);
490
491}
492
493void palette::load_nice()
494{ load(); }
495
496
497void image::make_page(short width, short height, unsigned char *page_buffer)
498{
499  if (page_buffer)
500    data=page_buffer;
501  else data=(unsigned char *)jmalloc(width*height,"image::data");
502}
503
504void image::delete_page()
505{
506  if (!special || !special->static_mem)
507    jfree(data);     
508}
509
510
511void switch_mode(video_mode new_mode)
512{
513  close_graphics();
514  char *empty[]= {"game"};
515  set_mode(new_mode,1,empty);
516}
Note: See TracBrowser for help on using the repository browser.