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

Last change on this file since 528 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.2 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
16
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;
32extern unsigned int xres,yres;
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(int mode, int argc, char **argv)
340{
341  int i,j;
342 
343  xres=320; yres=200;
344
345  for (i=1;i<argc;i++)
346    if (!strcmp(argv[i],"-size"))
347      mode=get_VESA_mode(argv+i+1);
348
349
350  if (!VESA_set_mode(mode))
351  {
352    printf("Unable to set video mode.  The correct VESA driver is not loaded\n"
353           "or it does not support this video mode.\n");
354    exit(1);
355  }
356
357  screen=new image(xres+1,yres+1,NULL,2);
358  screen->clear();
359  update_dirty(screen);
360
361}
362
363int get_vmode()
364{ return vmode; }
365
366void close_graphics()
367{
368  if (lastl)
369    delete lastl;
370  lastl=NULL;
371  VESA_set_mode(3);  // switch to text mode
372  delete screen;
373}
374
375void put_part(image *im, int x, int y, int x1, int y1, int x2, int y2)
376{
377  unsigned short screen_off;
378  int i,ys,ye,xs,xe,page,last_page=-1,yy;
379  long breaker;
380  unsigned char *screen_addr,*line_addr;
381
382  if (y>(int)yres || x>(int)xres) return ;
383  CHECK(y1>=0 && y2>=y1 && x1>=0 && x2>=x1);
384
385
386  if (y<0)
387  { y1+=-y; y=0; }
388  ys=y1;
389  if (y+(y2-y1)>=(int)yres)
390    ye=(int)yres-y+y1-1;
391  else ye=y2;
392
393  if (x<0)
394  { x1+=-x; x=0; }
395  xs=x1;
396  if (x+(x2-x1)>=(int)xres)
397    xe=(int)xres-x+x1-1;
398  else xe=x2;
399  if (xs>xe || ys>ye) return ;
400
401  int virtual_screen_width=im->width();
402  line_addr=im->scan_line(ys)+xs;
403
404  for (yy=ys;yy<=ye;yy++)
405  {
406    page=(long)y*(long)(xres+1)>>16;
407    if (page!=last_page)
408    { last_page=page;
409      vga_setpage(page);
410    }
411
412    // find the memory offset for the scan line of interest
413    screen_off=((long)y*(long)(xres+1))&0xffff;
414
415    // breaker is the number of bytes beofer the page split
416    breaker=(long)0xffff-(long)screen_off+1;
417
418    if (breaker>x+xe-xs)
419      memcpy(vga_getgraphmem()+screen_off+x,line_addr,xe-xs+1);
420    else if (breaker<=x)
421    { last_page++;
422      vga_setpage(last_page);
423      memcpy(vga_getgraphmem()+x-breaker,line_addr,xe-xs+1);
424    }
425    else
426    {
427      memcpy(vga_getgraphmem()+screen_off+x,line_addr,breaker-x);
428      last_page++;
429      vga_setpage(last_page);
430      memcpy(vga_getgraphmem(),line_addr+breaker-x,xe-xs-(breaker-x)+1);
431    }
432    y++;
433    line_addr+=virtual_screen_width;
434  }
435}
436
437void put_image(image *im, int x, int y)
438{ put_part(im,x,y,0,0,im->width()-1,im->height()-1); }
439
440
441void update_dirty(image *im, int xoff, int yoff)
442{
443
444  int count,x1,y1,x2,y2;
445  dirty_rect *dr,*q;
446  image *Xim;
447  CHECK(im->special);  // make sure the image has the ablity to contain dirty areas
448  if (im->special->keep_dirt==0)
449    put_image(im,0,0);
450  else
451  {
452    count=im->special->dirties.number_nodes();
453    if (!count) return;  // if nothing to update, return
454    dr=(dirty_rect *)im->special->dirties.first();
455    while (count>0)
456    {
457/*      if (dr->dx1+xoff<0) dr->dx1=0-xoff;
458      if (dr->dy1+yoff<0) dr->dy1=0-yoff;
459      if (dr->dx2+xoff>xres) dr->dx2=xres-xoff;
460      if (dr->dy2+yres>yres) dr->dy2=yres-yoff;
461      if (dr->dx1<=dr->dx2 && dr->dy1<=dr->dy2) */
462      put_part(im,dr->dx1+xoff,dr->dy1+yoff,dr->dx1,dr->dy1,dr->dx2,dr->dy2);
463      q=dr;
464      dr=(dirty_rect *)dr->next();
465      im->special->dirties.unlink((linked_node *)q);
466      delete q;
467      count--;
468    }
469  }
470}
471
472
473void palette::load()
474{
475  int i;
476  unsigned char *a=(unsigned char *)addr();
477  if (lastl)
478    delete lastl;
479  lastl=copy();
480
481  outp(0x3c8,0);
482  for (i=0;i<768;i++,a++)
483    outp(0x3c9,(*a)>>2);
484
485}
486
487void palette::load_nice()
488{ load(); }
489
490
491void image::make_page(short width, short height, unsigned char *page_buffer)
492{
493  if (page_buffer)
494    data=page_buffer;
495  else data=(unsigned char *)jmalloc(width*height,"image::data");
496}
497
498void image::delete_page()
499{
500  if (!special || !special->static_mem)
501    jfree(data);     
502}
503
504
Note: See TracBrowser for help on using the repository browser.