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,®s,®s);
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,®s,®s);
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,®s,®s);
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, ®s);
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, ®s);
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,®s,®s);
339 }
340
jtp_DOSActivateMouse()341 void jtp_DOSActivateMouse()
342 {
343 union REGS regs;
344 regs.w.ax=32;
345 int86(0x33,®s,®s);
346 }
347
jtp_DOSShowMouse()348 void jtp_DOSShowMouse()
349 {
350 union REGS regs;
351 regs.w.ax=1;
352 int86(0x33,®s,®s);
353 }
354
jtp_DOSInvisMouse()355 void jtp_DOSInvisMouse()
356 {
357 union REGS regs;
358 regs.w.ax=2;
359 int86(0x33,®s,®s);
360 }
361
jtp_DOSReadMouseButtons()362 void jtp_DOSReadMouseButtons()
363 {
364 union REGS regs;
365 regs.w.ax=3;
366 int86(0x33,®s,®s);
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,®s,®s);
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,®s,®s);
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