1 /*	SCCS Id: @(#)jtp_dos.c	3.0	2000/11/12	*/
2 /* Copyright (c) Jaakko Peltonen, 2000				  */
3 /* NetHack may be freely redistributed.  See license for details. */
4 
5 #ifndef _jtp_dos_c_
6 #define _jtp_dos_c_
7 
8 #include "jtp_def.h"
9 #include <stdlib.h>
10 #include <string.h>
11 #include <pc.h>
12 #include <dos.h>
13 #include <go32.h>         /* DJGPP specific file */
14 #include <dpmi.h>         /* DJGPP specific file */
15 #include <sys/nearptr.h>  /* DJGPP specific file */
16 #include "jtp_gra.h"      /* For jtp_screen_t structure definition */
17 #include "jtp_dos.h"
18 
19 #define PACKED __attribute__ ((packed))
20 #pragma pack(1)
21 
22 /*------------------------------------
23  SuperVGA controller information block
24 -------------------------------------*/
25 typedef struct {
26   char    VESASignature[4]      PACKED; /* VESA 4-byte signature              */
27   jtp_uint2   VESAVersion       PACKED; /* VBE version number                 */
28   jtp_uint4   OEMStringPtr      PACKED; /* Pointer to OEM string              */
29   jtp_uchar   Capabilities[4]   PACKED; /* Capabilities of video card         */
30   jtp_uint4   VideoModePtr      PACKED; /* Pointer to supported modes         */
31   jtp_uint2   TotalMemory       PACKED; /* Number of 64kb memory blocks       */
32   jtp_uint2   OEMSoftwareRev    PACKED; /* VBE software revision              */
33   jtp_uint4   OEMVendorNamePtr  PACKED; /* Pointer to vendor name string      */
34   jtp_uint4   OEMProductNamePtr PACKED; /* Pointer to product name string     */
35   jtp_uint4   OEMProductRevPtr  PACKED; /* Pointer to product revision string */
36   char    Reserved[222]         PACKED; /* Reserved as working space          */
37   char    OEMData[256]          PACKED; /* Data area for OEM strings          */
38 } jtp_dos_vbe_vgainfo;
39 
40 
41 /*------------------------------------
42 SuperVGA mode information block
43 -------------------------------------*/
44 typedef struct {
45   short   ModeAttributes;         /* Mode attributes                  */
46   char    WinAAttributes;         /* Window A attributes              */
47   char    WinBAttributes;         /* Window B attributes              */
48   short   WinGranularity;         /* Window granularity in k          */
49   short   WinSize;                /* Window size in k                 */
50   short   WinASegment;            /* Window A segment                 */
51   short   WinBSegment;            /* Window B segment                 */
52   void    *WinFuncPtr;            /* Pointer to window function       */
53   short   BytesPerScanLine;       /* Bytes per scanline               */
54   short   XResolution;            /* Horizontal resolution            */
55   short   YResolution;            /* Vertical resolution              */
56   char    XCharSize;              /* Character cell width             */
57   char    YCharSize;              /* Character cell height            */
58   char    NumberOfPlanes;         /* Number of memory planes          */
59   char    BitsPerPixel;           /* Bits per pixel                   */
60 
61   char    NumberOfBanks;          /* Number of CGA style banks        */
62   char    MemoryModel;            /* Memory model type                */
63   char    BankSize;               /* Size of CGA style banks          */
64   char    NumberOfImagePages;     /* Number of images pages           */
65   char    res1;                   /* Reserved                         */
66   char    RedMaskSize;            /* Size of direct color red mask    */
67   char    RedFieldPosition;       /* Bit posn of lsb of red mask      */
68   char    GreenMaskSize;          /* Size of direct color green mask  */
69   char    GreenFieldPosition;     /* Bit posn of lsb of green mask    */
70   char    BlueMaskSize;           /* Size of direct color blue mask   */
71   char    BlueFieldPosition;      /* Bit posn of lsb of blue mask     */
72   char    RsvdMaskSize;           /* Size of direct color res mask    */
73   char    RsvdFieldPosition;      /* Bit posn of lsb of res mask      */
74   char    DirectColorModeInfo;    /* Direct color mode attributes     */
75 
76   /* VESA 2.0 variables */
77   long    PhysBasePtr;            /* physical address for flat frame buffer */
78   long    OffScreenMemOffset;     /* pointer to start of off screen memory */
79   short   OffScreenMemSize;       /* amount of off screen memory in 1k units */
80   char    res2[206];              /* Pad to 256 byte block size       */
81 } jtp_dos_vbe_modeinfo;
82 
83 #pragma pack()
84 
85 
86 unsigned char * jtp_dos_console;
87 short int jtp_dos_mousex = 100, jtp_dos_mousey = 100, jtp_dos_mouseb = 0;
88 short int jtp_dos_oldmx = 100, jtp_dos_oldmy = 100, jtp_dos_oldmb = 0;
89 
90 /*--------------------------------------------------------------------------
91  DOS-specific Palette handling
92 ----------------------------------------------------------------------------*/
jtp_DOSSetColor(unsigned char cindex,unsigned char redval,unsigned char greenval,unsigned char blueval)93 void jtp_DOSSetColor
94 (
95   unsigned char cindex,
96   unsigned char redval,
97   unsigned char greenval,
98   unsigned char blueval
99 )
100 {
101   outp(0x03c6, 0xFF);
102   outp(0x03c8, cindex);
103   outp(0x03c9, redval);
104   outp(0x03c9, greenval);
105   outp(0x03c9, blueval);
106 }
107 
108 /*------------------------------------------------------------------------
109  DOS-specific graphics initialization and closing (using VESA SVGA modes)
110 --------------------------------------------------------------------------*/
111 
jtp_DOSGoBackToTextMode()112 void jtp_DOSGoBackToTextMode()
113 {
114   union REGS regs;
115   regs.w.ax=3;
116   int86(0x10,&regs,&regs);
117 }
118 
jtp_DOSSetGDisplayMode(jtp_uint4 disp_mode)119 void jtp_DOSSetGDisplayMode(jtp_uint4 disp_mode)
120 {
121   union REGS regs;
122   regs.x.eax=0x4f02;
123   regs.x.ebx=disp_mode;
124   int86(0x10,&regs,&regs);
125 }
126 
jtp_DOSSetWindow(jtp_uint4 w_num)127 void jtp_DOSSetWindow(jtp_uint4 w_num)
128 {
129   union REGS regs;
130   regs.x.eax=0x4f05;
131   regs.x.ebx=0;
132   regs.x.edx=w_num;
133   int86(0x10,&regs,&regs);
134 }
135 
136 /*-------------------------------------------------
137 Detects precence of VESA controller.
138 Returns 0 on success, an error code on failure.
139 --------------------------------------------------*/
jtp_DOSDetectVBE(jtp_dos_vbe_vgainfo * vbeinfo)140 int jtp_DOSDetectVBE
141 (
142   jtp_dos_vbe_vgainfo *vbeinfo
143 )
144 {
145    __dpmi_regs regs;
146 
147    strncpy(vbeinfo->VESASignature, "VBE2", 4);
148    regs.x.ax = 0x4F00;
149    regs.x.di = __tb & 0x0F;
150    regs.x.es = (__tb >> 4) & 0xFFFF;
151    dosmemput(vbeinfo, sizeof(jtp_dos_vbe_vgainfo), __tb);
152    __dpmi_int(0x10, &regs);
153    dosmemget(__tb, sizeof(jtp_dos_vbe_vgainfo), vbeinfo);
154 
155    return(regs.h.ah);
156 }
157 
158 /*-------------------------------------------------
159 Retrieves info on a VESA videomode into a pointer.
160 Returns 0 on success, an error code on failure.
161 --------------------------------------------------*/
jtp_DOSGetVBEModeInfo(unsigned short mode,jtp_dos_vbe_modeinfo * modeinfo)162 int jtp_DOSGetVBEModeInfo
163 (
164   unsigned short mode,
165   jtp_dos_vbe_modeinfo *modeinfo
166 )
167 {
168    __dpmi_regs regs;
169 
170    regs.x.ax=0x4F01;
171    regs.x.cx=mode;
172    regs.x.di=__tb & 0x0F;
173    regs.x.es=(__tb >> 4) & 0xFFFF;
174    __dpmi_int(0x10, &regs);
175    dosmemget(__tb, sizeof(jtp_dos_vbe_modeinfo), modeinfo);
176 
177    return(regs.h.ah);
178 }
179 
180 /*---------------------------------------------------
181 Finds the VESA mode number corresponding to the given
182 resolution and color settings. Color settings are:
183 8  = 256 colors (8 bit)
184 16 = highcolor (16 bit)
185 24 = truecolor (24 bit)
186 32 = truecolor (32 bit)
187 -----------------------------------------------------*/
188 #define JTP_MAX_VBEMODES 1000
jtp_DOSGetVBEModeNumber(int xres,int yres,int bitsperpixel)189 int jtp_DOSGetVBEModeNumber(int xres, int yres, int bitsperpixel)
190 {
191   jtp_dos_vbe_vgainfo  vbeinfo;
192   jtp_dos_vbe_modeinfo modeinfo;
193   jtp_uint2 vbemodes[JTP_MAX_VBEMODES];
194   int       i = 0;
195   char      oembuffer[200];
196 
197   if (jtp_DOSDetectVBE(&vbeinfo) != 0) return(0);
198 
199   while (i < 0xFFFF)
200   {
201     jtp_DOSGetVBEModeInfo(i, &modeinfo);
202     if ((modeinfo.XResolution == xres)&&
203         (modeinfo.YResolution == yres)&&
204         (modeinfo.BitsPerPixel == bitsperpixel))
205       { return(i); }
206     i++;
207   }
208   return(0);
209 }
210 
211 
jtp_DOSSetMode(int screen_width,int screen_height,int screen_bitdepth)212 void jtp_DOSSetMode(int screen_width, int screen_height, int screen_bitdepth)
213 {
214   int modenumber;
215 
216   /* Find requested mode and activate it */
217   modenumber = jtp_DOSGetVBEModeNumber(screen_width, screen_height, screen_bitdepth);
218   if (!modenumber)
219   {
220     printf("Could not find graphics mode [%dx%d, %d-bit].\n",
221            screen_width, screen_height, screen_bitdepth);
222     printf("Please check your settings. If necessary, use a VESA driver.\n");
223     exit(1);
224   }
225 
226   jtp_DOSSetGDisplayMode(modenumber);
227 
228   /* Set pointer to start of video memory area */
229   jtp_dos_console = (unsigned char *)(0xA0000 + __djgpp_conventional_base);
230 }
231 
232 
233 
234 /*-------------------------------------------------------------------------
235  DOS-specific display updating
236 ---------------------------------------------------------------------------*/
237 
jtp_DOSRefresh(jtp_screen_t * newscreen)238 void jtp_DOSRefresh(jtp_screen_t *newscreen)
239 {
240  int i, npixels, tempwin;
241  unsigned char * isource;
242 
243  tempwin = 0;
244  npixels = newscreen->width*newscreen->height;
245  isource = newscreen->vpage;
246  while (npixels > 0)
247  {
248    jtp_DOSSetWindow(tempwin);
249    if (npixels > 65536)
250      memcpy(jtp_dos_console,isource,65536);
251    else
252      memcpy(jtp_dos_console,isource,npixels);
253    npixels -= 65536;
254    isource += 65536;
255    tempwin++;
256  }
257 }
258 
259 
jtp_DOSRefreshRegion(int x1,int y1,int x2,int y2,jtp_screen_t * newscreen)260 void jtp_DOSRefreshRegion
261 (
262   int x1, int y1,
263   int x2, int y2,
264   jtp_screen_t *newscreen
265 )
266 {
267   int curwindow = 0;
268   int i,j;
269   int osplus;
270   int con_ofs;
271   int buf_ofs;
272 
273   if ((x2 < 0) || (y2 < 0) || (x1 > jtp_screen.width-1) || (y1 > jtp_screen.height-1))
274     return;
275 
276   if (x2 > newscreen->width-1) x2 = newscreen->width-1;
277   if (y2 > newscreen->height-1) y2 = newscreen->height-1;
278   if (x1 < 0) x1 = 0;
279   if (y1 < 0) y1 = 0;
280 
281   con_ofs = newscreen->width*y1+x1; /* Start offset in console window */
282   buf_ofs = newscreen->width*y1+x1; /* Start offset in buffer */
283   x2 = x2-x1+1;        /* Width of refresh area */
284   osplus = newscreen->width-x2;     /* Difference between end of refresh row and start of next */
285 
286   while (con_ofs > 65535)
287   {
288     curwindow++;
289     con_ofs -= 65536;
290   }
291   jtp_DOSSetWindow(curwindow);
292 
293   for (i = y1; i <= y2; i++)
294   {
295     if (con_ofs > 65535)
296     {
297       con_ofs -= 65536;
298       curwindow++;
299       jtp_DOSSetWindow(curwindow);
300     }
301 
302     if (x2+con_ofs > 65536) /* Row straddles a window boundary */
303     {
304       x1 = x2 + con_ofs - 65536;
305       /* Show part of row in old window */
306       memcpy(jtp_dos_console + con_ofs, newscreen->vpage + buf_ofs, 65536-con_ofs);
307       buf_ofs += 65536-con_ofs;
308 
309       /* Change to next window */
310       curwindow++;
311       jtp_DOSSetWindow(curwindow);
312 
313       /* Show part of row in new window */
314       memcpy(jtp_dos_console, newscreen->vpage + buf_ofs, x1);
315       buf_ofs += x1;
316       con_ofs = x1;
317     }
318     else
319     {
320       memcpy(jtp_dos_console + con_ofs, newscreen->vpage + buf_ofs, x2);
321       buf_ofs += x2;
322       con_ofs += x2;
323     }
324 
325     con_ofs += osplus;
326     buf_ofs += osplus;
327   }
328 }
329 
330 /*---------------------------------------------------
331  DOS-specific Mouse functions
332 ---------------------------------------------------*/
333 
jtp_DOSResetMouse()334 void jtp_DOSResetMouse()
335 {
336   union REGS regs;
337   regs.w.ax=0;
338   int86(0x33,&regs,&regs);
339 }
340 
jtp_DOSActivateMouse()341 void jtp_DOSActivateMouse()
342 {
343   union REGS regs;
344   regs.w.ax=32;
345   int86(0x33,&regs,&regs);
346 }
347 
jtp_DOSShowMouse()348 void jtp_DOSShowMouse()
349 {
350   union REGS regs;
351   regs.w.ax=1;
352   int86(0x33,&regs,&regs);
353 }
354 
jtp_DOSInvisMouse()355 void jtp_DOSInvisMouse()
356 {
357   union REGS regs;
358   regs.w.ax=2;
359   int86(0x33,&regs,&regs);
360 }
361 
jtp_DOSReadMouseButtons()362 void jtp_DOSReadMouseButtons()
363 {
364   union REGS regs;
365   regs.w.ax=3;
366   int86(0x33,&regs,&regs);
367   jtp_dos_mouseb=regs.w.bx;
368 }
369 
jtp_DOSReadMouseDelta()370 void jtp_DOSReadMouseDelta()
371 {
372   union REGS regs;
373   regs.w.ax=0x000B;
374   int86(0x33,&regs,&regs);
375   jtp_dos_mousex=regs.w.cx;
376   jtp_dos_mousey=regs.w.dx;
377 }
378 
379 
jtp_DOSSetMouse(int new_mx,int new_my)380 void jtp_DOSSetMouse(int new_mx,int new_my)
381 {
382   union REGS regs;
383   regs.x.eax=4;
384   regs.x.ecx=new_mx;
385   regs.x.edx=new_my;
386   int86(0x33,&regs,&regs);
387 }
388 
jtp_DOSReadMouse(jtp_screen_t * newscreen)389 void jtp_DOSReadMouse(jtp_screen_t *newscreen)
390 {
391   jtp_dos_oldmx = jtp_dos_mousex;
392   jtp_dos_oldmy = jtp_dos_mousey;
393   jtp_dos_oldmb = jtp_dos_mouseb;
394   jtp_DOSReadMouseButtons();
395   jtp_DOSReadMouseDelta();
396   jtp_dos_mousex = jtp_dos_oldmx+jtp_dos_mousex/2;
397   jtp_dos_mousey = jtp_dos_oldmy+jtp_dos_mousey/2;
398 
399   if (jtp_dos_mousex < 0) jtp_dos_mousex = 0;
400   if (jtp_dos_mousey < 0) jtp_dos_mousey = 0;
401   if (jtp_dos_mousex >= newscreen->width) jtp_dos_mousex = newscreen->width-1;
402   if (jtp_dos_mousey >= newscreen->height) jtp_dos_mousey = newscreen->height-1;
403   jtp_DOSSetMouse(100,100);
404 }
405 
406 /*---------------------------------------------------
407  DOS-specific keyboard functions
408 ---------------------------------------------------*/
jtp_DOSGetch()409 int jtp_DOSGetch()
410 {
411   return(getch());
412 }
413 
jtp_DOSKbHit()414 int jtp_DOSKbHit()
415 {
416   return(kbhit());
417 }
418 
419 
420 /*----------------------------------------------------------
421  Interface to graphics initialization
422 -----------------------------------------------------------*/
jtp_DOSEnterGraphicsMode(jtp_screen_t * newscreen)423 jtp_DOSEnterGraphicsMode(jtp_screen_t *newscreen)
424 {
425   jtp_DOSSetMode(newscreen->width, newscreen->height, 8);
426   __djgpp_nearptr_enable();
427   jtp_DOSSetMouse(100,100); /* Just to make sure */
428 }
429 
jtp_DOSExitGraphicsMode()430 jtp_DOSExitGraphicsMode()
431 {
432   __djgpp_nearptr_disable();
433   jtp_DOSGoBackToTextMode();
434 }
435 
436 #endif
437