1 /* Copyright (c) NetHack PC Development Team 1995 */
2 /* VESA BIOS functions copyright (c) Ray Chason 2016 */
3 /* NetHack may be freely redistributed. See license for details. */
4 /*
5 * vidvesa.c - VGA Hardware video support with VESA BIOS Extensions
6 */
7
8 #include "hack.h"
9
10 #ifdef SCREEN_VESA /* this file is for SCREEN_VESA only */
11 #include <dpmi.h>
12
13 #include "pcvideo.h"
14 #include "tile.h"
15 #include "pctiles.h"
16 #include "vesa.h"
17 #include "wintty.h"
18 #include "tileset.h"
19
20 #define BACKGROUND_VESA_COLOR 1
21 #define FIRST_TEXT_COLOR 240
22
23 static unsigned long FDECL(vesa_SetWindow, (int window, unsigned long offset));
24 static unsigned long FDECL(vesa_ReadPixel32, (unsigned x, unsigned y));
25 static void FDECL(vesa_WritePixel32, (unsigned x, unsigned y,
26 unsigned long color));
27 static void FDECL(vesa_WritePixel, (unsigned x, unsigned y, unsigned color));
28 static unsigned long FDECL(vesa_MakeColor, (unsigned r, unsigned g, unsigned b));
29 static void FDECL(vesa_GetRGB, (
30 unsigned long color,
31 unsigned char *rp, unsigned char *gp, unsigned char *bp));
32 static void FDECL(vesa_FillRect, (
33 unsigned left, unsigned top,
34 unsigned width, unsigned height,
35 unsigned color));
36
37 static void NDECL(vesa_redrawmap);
38 static void FDECL(vesa_cliparound, (int, int));
39 static void FDECL(decal_packed, (const struct TileImage *tile, unsigned special));
40 static void FDECL(vesa_SwitchMode, (unsigned mode));
41 static boolean FDECL(vesa_SetPalette, (const struct Pixel *));
42 static boolean FDECL(vesa_SetHardPalette, (const struct Pixel *));
43 static boolean FDECL(vesa_SetSoftPalette, (const struct Pixel *));
44 static void FDECL(vesa_DisplayCell, (const struct TileImage *tile, int, int));
45 static void FDECL(vesa_DisplayCellInMemory, (const struct TileImage *tile,
46 int, char buf[TILE_Y][640*2]));
47 static unsigned FDECL(vesa_FindMode, (unsigned long mode_addr, unsigned bits));
48 static void FDECL(vesa_WriteChar, (int, int, int, int, BOOLEAN_P));
49 static void FDECL(vesa_WriteCharInMemory, (int, int, char buf[TILE_Y][640*2],
50 int));
51 static void FDECL(vesa_WriteStr, (const char *, int, int, int, int));
52 static char __far *NDECL(vesa_FontPtrs);
53
54 #ifdef POSITIONBAR
55 static void NDECL(positionbar);
56 #endif
57
58 extern int clipx, clipxmax; /* current clipping column from wintty.c */
59 extern int curcol, currow; /* current column and row */
60 extern int g_attribute;
61 extern int attrib_text_normal; /* text mode normal attribute */
62 extern int attrib_gr_normal; /* graphics mode normal attribute */
63 extern int attrib_gr_intense; /* graphics mode intense attribute */
64 extern boolean inmap; /* in the map window */
65 extern boolean restoring;
66
67 /*
68 * Global Variables
69 */
70
71 static unsigned char __far *font;
72
73 static struct map_struct {
74 int glyph;
75 int ch;
76 int attr;
77 unsigned special;
78 } map[ROWNO][COLNO]; /* track the glyphs */
79
80 #define vesa_clearmap() \
81 { \
82 int x, y; \
83 for (y = 0; y < ROWNO; ++y) \
84 for (x = 0; x < COLNO; ++x) { \
85 map[y][x].glyph = cmap_to_glyph(S_stone); \
86 map[y][x].ch = S_stone; \
87 map[y][x].attr = 0; \
88 map[y][x].special = 0; \
89 } \
90 }
91 #define TOP_MAP_ROW 1
92
93 static int viewport_size = 40;
94
95 static const struct Pixel defpalette[] = { /* Colors for text and the position bar */
96 { 0x18, 0x18, 0x18, 0xff }, /* CLR_BLACK */
97 { 0xaa, 0x00, 0x00, 0xff }, /* CLR_RED */
98 { 0x00, 0xaa, 0x00, 0xff }, /* CLR_GREEN */
99 { 0x99, 0x40, 0x00, 0xff }, /* CLR_BROWN */
100 { 0x00, 0x00, 0xaa, 0xff }, /* CLR_BLUE */
101 { 0xaa, 0x00, 0xaa, 0xff }, /* CLR_MAGENTA */
102 { 0x00, 0xaa, 0xaa, 0xff }, /* CLR_CYAN */
103 { 0xaa, 0xaa, 0xaa, 0xff }, /* CLR_GRAY */
104 { 0x55, 0x55, 0x55, 0xff }, /* NO_COLOR */
105 { 0xff, 0x90, 0x00, 0xff }, /* CLR_ORANGE */
106 { 0x00, 0xff, 0x00, 0xff }, /* CLR_BRIGHT_GREEN */
107 { 0xff, 0xff, 0x00, 0xff }, /* CLR_YELLOW */
108 { 0x00, 0x00, 0xff, 0xff }, /* CLR_BRIGHT_BLUE */
109 { 0xff, 0x00, 0xff, 0xff }, /* CLR_BRIGHT_MAGENTA */
110 { 0x00, 0xff, 0xff, 0xff }, /* CLR_BRIGHT_CYAN */
111 { 0xff, 0xff, 0xff, 0xff } /* CLR_WHITE */
112 };
113
114 /* Information about the selected VESA mode */
115 static unsigned short vesa_mode = 0xFFFF; /* Mode number */
116 static unsigned short vesa_x_res; /* X resolution */
117 static unsigned short vesa_y_res; /* Y resolution */
118 static unsigned short vesa_x_center; /* X centering offset */
119 static unsigned short vesa_y_center; /* Y centering offset */
120 static unsigned short vesa_scan_line; /* Bytes per scan line */
121 static int vesa_read_win; /* Select the read window */
122 static int vesa_write_win; /* Select the write window */
123 static unsigned long vesa_win_pos[2]; /* Window position */
124 static unsigned long vesa_win_addr[2]; /* Window physical address */
125 static unsigned long vesa_win_size; /* Window size */
126 static unsigned long vesa_win_gran; /* Window granularity */
127 static unsigned char vesa_pixel_size;
128 static unsigned char vesa_pixel_bytes;
129 static unsigned char vesa_red_pos;
130 static unsigned char vesa_red_size;
131 static unsigned char vesa_green_pos;
132 static unsigned char vesa_green_size;
133 static unsigned char vesa_blue_pos;
134 static unsigned char vesa_blue_size;
135 static unsigned long vesa_palette[256];
136
137 struct OldModeInfo {
138 unsigned mode;
139
140 unsigned short XResolution; /* horizontal resolution in pixels or characters */
141 unsigned short YResolution; /* vertical resolution in pixels or characters */
142 unsigned char BitsPerPixel; /* bits per pixel */
143 unsigned char MemoryModel; /* memory model type */
144 };
145
146 static const struct OldModeInfo old_mode_table[] = {
147 { 0x0101, 640, 480, 8, 4 },
148 { 0x0103, 800, 600, 8, 4 },
149 { 0x0105, 1024, 768, 8, 4 },
150 { 0x0107, 1280, 1024, 8, 4 },
151 { 0x0110, 640, 480, 15, 6 },
152 { 0x0111, 640, 480, 16, 6 },
153 { 0x0112, 640, 480, 24, 6 },
154 { 0x0113, 800, 600, 15, 6 },
155 { 0x0114, 800, 600, 16, 6 },
156 { 0x0115, 800, 600, 24, 6 },
157 { 0x0116, 1024, 768, 15, 6 },
158 { 0x0117, 1024, 768, 16, 6 },
159 { 0x0118, 1024, 768, 24, 6 },
160 { 0x0119, 1280, 1024, 15, 6 },
161 { 0x011A, 1280, 1024, 16, 6 },
162 { 0x011B, 1280, 1024, 24, 6 },
163 };
164
165 /* Retrieve the mode info block */
166 static boolean
vesa_GetModeInfo(mode,info)167 vesa_GetModeInfo(mode, info)
168 unsigned mode;
169 struct ModeInfoBlock *info;
170 {
171 int mode_info_sel = -1; /* custodial */
172 int mode_info_seg;
173 __dpmi_regs regs;
174
175 mode_info_seg = __dpmi_allocate_dos_memory(
176 (sizeof(*info) + 15) / 16,
177 &mode_info_sel);
178 if (mode_info_seg < 0) goto error;
179
180 memset(info, 0, sizeof(*info));
181 dosmemput(info, sizeof(*info), mode_info_seg * 16L);
182
183 memset(®s, 0, sizeof(regs));
184 regs.x.ax = 0x4F01;
185 regs.x.cx = mode;
186 regs.x.di = 0;
187 regs.x.es = mode_info_seg;
188 (void) __dpmi_int(VIDEO_BIOS, ®s);
189
190 if (regs.x.ax != 0x004F) goto error;
191 dosmemget(mode_info_seg * 16L, sizeof(*info), info);
192 if (!(info->ModeAttributes & 0x0001)) goto error;
193
194 if (!(info->ModeAttributes & 0x0002)) {
195 /* Older VESA BIOS that did not return certain mode properties, but
196 that has fixed mode numbers; search the table to find the right
197 mode properties */
198
199 unsigned i;
200
201 for (i = 0; i < SIZE(old_mode_table); ++i) {
202 if (mode == old_mode_table[i].mode) {
203 break;
204 }
205 }
206 if (i >= SIZE(old_mode_table)) goto error;
207
208 info->XResolution = old_mode_table[i].XResolution;
209 info->YResolution = old_mode_table[i].YResolution;
210 info->NumberOfPlanes = 1;
211 info->BitsPerPixel = old_mode_table[i].BitsPerPixel;
212 info->NumberOfBanks = 1;
213 info->MemoryModel = old_mode_table[i].MemoryModel;
214 }
215
216 __dpmi_free_dos_memory(mode_info_sel);
217 return TRUE;
218
219 error:
220 if (mode_info_sel != -1) __dpmi_free_dos_memory(mode_info_sel);
221 return FALSE;
222 }
223
224 /* Set the memory window and return the offset */
225 static unsigned long
vesa_SetWindow(window,offset)226 vesa_SetWindow(window, offset)
227 int window;
228 unsigned long offset;
229 {
230 /* If the desired offset is already within the window, leave the window
231 as it is and return the address based on the current window position.
232 This minimizes the use of the window switch function.
233
234 On the first call to the function, vesa_win_pos[window] == 0xFFFFFFFF,
235 the offset will always be less than this, and the BIOS will always be
236 called. */
237
238 unsigned long pos = vesa_win_pos[window];
239 if (offset < pos || pos + vesa_win_size <= offset) {
240 __dpmi_regs regs;
241
242 memset(®s, 0, sizeof(regs));
243 regs.x.ax = 0x4F05;
244 regs.h.bh = 0x00;
245 regs.h.bl = window;
246 regs.x.dx = offset / vesa_win_gran;
247 pos = regs.x.dx * vesa_win_gran;
248 (void) __dpmi_int(VIDEO_BIOS, ®s);
249 vesa_win_pos[window] = pos;
250 }
251
252 offset = offset - vesa_win_pos[window] + vesa_win_addr[window];
253 /* Keep from crashing the system if some malfunction gives us a bad
254 offset */
255 if (offset < 0xA0000 || offset > 0xBFFFF) {
256 vesa_SwitchMode(MODETEXT);
257 fprintf(stderr, "Abort: offset=%08lX\n", offset);
258 exit(1);
259 }
260 return offset;
261 }
262
263 static unsigned long
vesa_ReadPixel32(x,y)264 vesa_ReadPixel32(x, y)
265 unsigned x, y;
266 {
267 unsigned long offset = y * vesa_scan_line + x * vesa_pixel_bytes;
268 unsigned long addr, color;
269 unsigned i;
270
271 switch (vesa_pixel_size) {
272 case 8:
273 addr = vesa_SetWindow(vesa_read_win, offset);
274 color = _farpeekb(_dos_ds, addr);
275 break;
276
277 case 15:
278 case 16:
279 addr = vesa_SetWindow(vesa_read_win, offset);
280 color = _farpeekw(_dos_ds, addr);
281 break;
282
283 case 24:
284 /* Pixel may cross a window boundary */
285 color = 0;
286 for (i = 0; i < 3; ++i) {
287 addr = vesa_SetWindow(vesa_read_win, offset + i);
288 color |= (unsigned long) _farpeekb(_dos_ds, addr) << (i * 8);
289 }
290 break;
291
292 case 32:
293 addr = vesa_SetWindow(vesa_read_win, offset);
294 color = _farpeekl(_dos_ds, addr);
295 break;
296 }
297 return color;
298 }
299
300 static void
vesa_WritePixel32(x,y,color)301 vesa_WritePixel32(x, y, color)
302 unsigned x, y;
303 unsigned long color;
304 {
305 unsigned long offset = y * vesa_scan_line + x * vesa_pixel_bytes;
306 unsigned long addr;
307 unsigned i;
308
309 switch (vesa_pixel_size) {
310 case 8:
311 addr = vesa_SetWindow(vesa_write_win, offset);
312 _farpokeb(_dos_ds, addr, color);
313 break;
314
315 case 15:
316 case 16:
317 addr = vesa_SetWindow(vesa_write_win, offset);
318 _farpokew(_dos_ds, addr, color);
319 break;
320
321 case 24:
322 /* Pixel may cross a window boundary */
323 for (i = 0; i < 3; ++i) {
324 addr = vesa_SetWindow(vesa_read_win, offset + i);
325 _farpokeb(_dos_ds, addr, (unsigned char) (color >> (i * 8)));
326 }
327 break;
328
329 case 32:
330 addr = vesa_SetWindow(vesa_write_win, offset);
331 _farpokel(_dos_ds, addr, color);
332 break;
333 }
334 }
335
336 static void
vesa_WritePixel(x,y,color)337 vesa_WritePixel(x, y, color)
338 unsigned x, y;
339 unsigned color;
340 {
341 if (vesa_pixel_size == 8) {
342 vesa_WritePixel32(x, y, color);
343 } else {
344 vesa_WritePixel32(x, y, vesa_palette[color & 0xFF]);
345 }
346 }
347
348 static unsigned long
vesa_MakeColor(r,g,b)349 vesa_MakeColor(r, g, b)
350 unsigned r, g, b;
351 {
352 r = (r & 0xFF) >> (8 - vesa_red_size);
353 g = (g & 0xFF) >> (8 - vesa_green_size);
354 b = (b & 0xFF) >> (8 - vesa_blue_size);
355 return ((unsigned long) r << vesa_red_pos)
356 | ((unsigned long) g << vesa_green_pos)
357 | ((unsigned long) b << vesa_blue_pos);
358 }
359
360 static void
vesa_GetRGB(color,rp,gp,bp)361 vesa_GetRGB(color, rp, gp, bp)
362 unsigned long color;
363 unsigned char *rp, *gp, *bp;
364 {
365 unsigned r, g, b;
366
367 r = color >> vesa_red_pos;
368 g = color >> vesa_green_pos;
369 b = color >> vesa_blue_pos;
370 r <<= 8 - vesa_red_size;
371 g <<= 8 - vesa_green_size;
372 b <<= 8 - vesa_blue_size;
373 *rp = (unsigned char) r;
374 *gp = (unsigned char) g;
375 *bp = (unsigned char) b;
376 }
377
378 static void
vesa_FillRect(left,top,width,height,color)379 vesa_FillRect(left, top, width, height, color)
380 unsigned left, top, width, height, color;
381 {
382 unsigned x, y;
383
384 for (y = 0; y < height; ++y) {
385 for (x = 0; x < width; ++x) {
386 vesa_WritePixel(left + x, top + y, color);
387 }
388 }
389 }
390
391 void
vesa_get_scr_size()392 vesa_get_scr_size()
393 {
394 CO = 80;
395 LI = 29;
396 }
397
398 void
vesa_backsp()399 vesa_backsp()
400 {
401 int col, row;
402
403 col = curcol; /* Character cell row and column */
404 row = currow;
405
406 if (col > 0)
407 col = col - 1;
408 vesa_gotoloc(col, row);
409 }
410
411 void
vesa_clear_screen(colour)412 vesa_clear_screen(colour)
413 int colour;
414 {
415 vesa_FillRect(0, 0, vesa_x_res, vesa_y_res, colour);
416 if (iflags.tile_view)
417 vesa_clearmap();
418 vesa_gotoloc(0, 0); /* is this needed? */
419 }
420
421 /* clear to end of line */
422 void
vesa_cl_end(col,row)423 vesa_cl_end(col, row)
424 int col, row;
425 {
426 unsigned left = vesa_x_center + col * 8;
427 unsigned top = vesa_y_center + row * 16;
428 unsigned width = (CO - 1 - col) * 8;
429 unsigned height = 16;
430
431 vesa_FillRect(left, top, width, height, BACKGROUND_VESA_COLOR);
432 }
433
434 /* clear to end of screen */
435 void
vesa_cl_eos(cy)436 vesa_cl_eos(cy)
437 int cy;
438 {
439 int count;
440
441 cl_end();
442 if (cy < LI - 1) {
443 unsigned left = vesa_x_center;
444 unsigned top = vesa_y_center + cy * 16;
445 unsigned width = 640;
446 unsigned height = (LI - 1 - cy) * 16;
447
448 vesa_FillRect(left, top, width, height, BACKGROUND_VESA_COLOR);
449 }
450 }
451
452 void
vesa_tty_end_screen()453 vesa_tty_end_screen()
454 {
455 vesa_clear_screen(BACKGROUND_VESA_COLOR);
456 vesa_SwitchMode(MODETEXT);
457 }
458
459 void
vesa_tty_startup(wid,hgt)460 vesa_tty_startup(wid, hgt)
461 int *wid, *hgt;
462 {
463 /* code to sense display adapter is required here - MJA */
464
465 vesa_get_scr_size();
466 if (CO && LI) {
467 *wid = CO;
468 *hgt = LI;
469 }
470
471 attrib_gr_normal = ATTRIB_VGA_NORMAL;
472 attrib_gr_intense = ATTRIB_VGA_INTENSE;
473 g_attribute = attrib_gr_normal; /* Give it a starting value */
474 }
475
476 /*
477 * Screen output routines (these are heavily used).
478 *
479 * These are the 3 routines used to place information on the screen
480 * in the VGA PC tty port of NetHack. These are the routines
481 * that get called by the general interface routines in video.c.
482 *
483 * vesa_xputs -Writes a c null terminated string at the current location.
484 *
485 * vesa_xputc -Writes a single character at the current location. Since
486 * various places in the code assume that control characters
487 * can be used to control, we are forced to interpret some of
488 * the more common ones, in order to keep things looking correct.
489 *
490 * vesa_xputg -This routine is used to display a graphical representation of a
491 * NetHack glyph (a tile) at the current location. For more
492 * information on NetHack glyphs refer to the comments in
493 * include/display.h.
494 *
495 */
496
497 void
vesa_xputs(s,col,row)498 vesa_xputs(s, col, row)
499 const char *s;
500 int col, row;
501 {
502 if (s != NULL) {
503 vesa_WriteStr(s, strlen(s), col, row, g_attribute);
504 }
505 }
506
507 /* write out character (and attribute) */
508 void
vesa_xputc(ch,attr)509 vesa_xputc(ch, attr)
510 char ch;
511 int attr;
512 {
513 int col, row;
514
515 col = curcol;
516 row = currow;
517
518 switch (ch) {
519 case '\n':
520 col = 0;
521 ++row;
522 break;
523 default:
524 vesa_WriteChar((unsigned char) ch, col, row, attr, FALSE);
525 if (col < (CO - 1))
526 ++col;
527 break;
528 } /* end switch */
529 vesa_gotoloc(col, row);
530 }
531
532 #if defined(USE_TILES)
533 /* Place tile represent. a glyph at current location */
534 void
vesa_xputg(glyphnum,ch,special)535 vesa_xputg(glyphnum, ch,
536 special)
537 int glyphnum;
538 int ch;
539 unsigned special; /* special feature: corpse, invis, detected, pet, ridden -
540 hack.h */
541 {
542 int col, row;
543 int attr;
544 int ry;
545 const struct TileImage *packcell;
546
547 row = currow;
548 col = curcol;
549 if ((col < 0 || col >= COLNO)
550 || (row < TOP_MAP_ROW || row >= (ROWNO + TOP_MAP_ROW)))
551 return;
552 ry = row - TOP_MAP_ROW;
553 map[ry][col].glyph = glyphnum;
554 map[ry][col].ch = ch;
555 map[ry][col].special = special;
556 attr = (g_attribute == 0) ? attrib_gr_normal : g_attribute;
557 map[ry][col].attr = attr;
558 if (iflags.traditional_view) {
559 vesa_WriteChar((unsigned char) ch, col, row, attr, FALSE);
560 } else {
561 if ((col >= clipx) && (col <= clipxmax)) {
562 packcell = get_tile(glyph2tile[glyphnum]);
563 if (!iflags.over_view && map[ry][col].special)
564 decal_packed(packcell, special);
565 vesa_DisplayCell(packcell, col - clipx, row);
566 }
567 }
568 if (col < (CO - 1))
569 ++col;
570 vesa_gotoloc(col, row);
571 }
572 #endif /* USE_TILES */
573
574 /*
575 * Cursor location manipulation, and location information fetching
576 * routines.
577 * These include:
578 *
579 * vesa_gotoloc(x,y) - Moves the "cursor" on screen to the specified x
580 * and y character cell location. This routine
581 * determines the location where screen writes
582 * will occur next, it does not change the location
583 * of the player on the NetHack level.
584 */
585
586 void
vesa_gotoloc(col,row)587 vesa_gotoloc(col, row)
588 int col, row;
589 {
590 curcol = min(col, CO - 1); /* protection from callers */
591 currow = min(row, LI - 1);
592 }
593
594 #if defined(USE_TILES) && defined(CLIPPING)
595 static void
vesa_cliparound(x,y)596 vesa_cliparound(x, y)
597 int x, y;
598 {
599 int oldx = clipx;
600
601 if (!iflags.tile_view || iflags.over_view || iflags.traditional_view)
602 return;
603
604 if (x < clipx + 5) {
605 clipx = max(0, x - (viewport_size / 2));
606 clipxmax = clipx + (viewport_size - 1);
607 } else if (x > clipxmax - 5) {
608 clipxmax = min(COLNO - 1, x + (viewport_size / 2));
609 clipx = clipxmax - (viewport_size - 1);
610 }
611 if (clipx != oldx) {
612 if (on_level(&u.uz0, &u.uz) && !restoring)
613 /* (void) doredraw(); */
614 vesa_redrawmap();
615 }
616 }
617
618 static void
vesa_redrawmap()619 vesa_redrawmap()
620 {
621 int x, y, t;
622 const struct TileImage *packcell;
623
624 /* y here is in screen rows*/
625 /* Build each row in local memory, then write, to minimize use of the
626 window switch function */
627 for (y = 0; y < ROWNO; ++y) {
628 char buf[TILE_Y][640*2];
629
630 for (x = clipx; x <= clipxmax; ++x) {
631 if (iflags.traditional_view) {
632 vesa_WriteCharInMemory((unsigned char) map[y][x].ch, x,
633 buf, map[y][x].attr);
634 } else {
635 t = map[y][x].glyph;
636 packcell = get_tile(glyph2tile[t]);
637 if (!iflags.over_view && map[y][x].special)
638 decal_packed(packcell, map[y][x].special);
639 vesa_DisplayCellInMemory(packcell, x - clipx, buf);
640 }
641 }
642 if (iflags.over_view && vesa_pixel_size != 8) {
643 for (t = 0; t < TILE_Y; ++t) {
644 for (x = 0; x < 640; ++x) {
645 unsigned long c1 = vesa_palette[buf[t][x * 2 + 0]];
646 unsigned long c2 = vesa_palette[buf[t][x * 2 + 1]];
647 unsigned char r1, r2, g1, g2, b1, b2;
648
649 vesa_GetRGB(c1, &r1, &g1, &b1);
650 vesa_GetRGB(c2, &r2, &g2, &b2);
651 r1 = (r1 + r2) / 2;
652 g1 = (g1 + g2) / 2;
653 b1 = (b1 + b2) / 2;
654 vesa_WritePixel32(x, (y + TOP_MAP_ROW) * TILE_Y + t,
655 vesa_MakeColor(r1, g1, b1));
656 }
657 }
658 } else {
659 for (t = 0; t < TILE_Y; ++t) {
660 for (x = 0; x < 640; ++x) {
661 vesa_WritePixel(x, (y + TOP_MAP_ROW) * TILE_Y + t, buf[t][x]);
662 }
663 }
664 }
665 }
666 }
667 #endif /* USE_TILES && CLIPPING */
668
669 void
vesa_userpan(left)670 vesa_userpan(left)
671 boolean left;
672 {
673 int x;
674
675 /* pline("Into userpan"); */
676 if (iflags.over_view || iflags.traditional_view)
677 return;
678 if (left)
679 x = min(COLNO - 1, clipxmax + 10);
680 else
681 x = max(0, clipx - 10);
682 vesa_cliparound(x, 10); /* y value is irrelevant on VGA clipping */
683 positionbar();
684 vesa_DrawCursor();
685 }
686
687 void
vesa_overview(on)688 vesa_overview(on)
689 boolean on;
690 {
691 /* vesa_HideCursor(); */
692 if (on) {
693 iflags.over_view = TRUE;
694 clipx = 0;
695 clipxmax = CO - 1;
696 } else {
697 iflags.over_view = FALSE;
698 clipx = max(0, (curcol - viewport_size / 2));
699 if (clipx > ((CO - 1) - viewport_size))
700 clipx = (CO - 1) - viewport_size;
701 clipxmax = clipx + (viewport_size - 1);
702 }
703 }
704
705 void
vesa_traditional(on)706 vesa_traditional(on)
707 boolean on;
708 {
709 /* vesa_HideCursor(); */
710 if (on) {
711 /* switch_symbols(FALSE); */
712 iflags.traditional_view = TRUE;
713 clipx = 0;
714 clipxmax = CO - 1;
715 } else {
716 iflags.traditional_view = FALSE;
717 if (!iflags.over_view) {
718 clipx = max(0, (curcol - viewport_size / 2));
719 if (clipx > ((CO - 1) - viewport_size))
720 clipx = (CO - 1) - viewport_size;
721 clipxmax = clipx + (viewport_size - 1);
722 }
723 }
724 }
725
726 void
vesa_refresh()727 vesa_refresh()
728 {
729 positionbar();
730 vesa_redrawmap();
731 vesa_DrawCursor();
732 }
733
734 static void
decal_packed(gp,special)735 decal_packed(gp, special)
736 const struct TileImage *gp;
737 unsigned special;
738 {
739 /* FIXME: the tile array is fixed in memory and should not be changed;
740 if we ever implement this, we'll have to copy the pixels */
741 if (special & MG_CORPSE) {
742 } else if (special & MG_INVIS) {
743 } else if (special & MG_DETECT) {
744 } else if (special & MG_PET) {
745 } else if (special & MG_RIDDEN) {
746 }
747 }
748
749 /*
750 * Open tile files,
751 * initialize the SCREEN, switch it to graphics mode,
752 * initialize the pointers to the fonts, clear
753 * the screen.
754 *
755 */
756 void
vesa_Init(void)757 vesa_Init(void)
758 {
759 const struct Pixel *paletteptr;
760 #ifdef USE_TILES
761 const char *tile_file;
762 int tilefailure = 0;
763 /*
764 * Attempt to open the required tile files. If we can't
765 * don't perform the video mode switch, use TTY code instead.
766 *
767 */
768 tile_file = iflags.wc_tile_file;
769 if (tile_file == NULL || *tile_file == '\0') {
770 tile_file = "nhtiles.bmp";
771 }
772 if (!read_tiles(tile_file, FALSE))
773 tilefailure |= 1;
774 if (get_palette() == NULL)
775 tilefailure |= 4;
776
777 if (tilefailure) {
778 raw_printf("Reverting to TTY mode, tile initialization failure (%d).",
779 tilefailure);
780 wait_synch();
781 iflags.usevga = 0;
782 iflags.tile_view = FALSE;
783 iflags.over_view = FALSE;
784 CO = 80;
785 LI = 25;
786 /* clear_screen() */ /* not vesa_clear_screen() */
787 return;
788 }
789 #endif
790
791 if (vesa_mode == 0xFFFF) {
792 vesa_detect();
793 }
794 vesa_SwitchMode(vesa_mode);
795 windowprocs.win_cliparound = vesa_cliparound;
796 #ifdef USE_TILES
797 paletteptr = get_palette();
798 iflags.tile_view = TRUE;
799 iflags.over_view = FALSE;
800 #else
801 paletteptr = defpalette;
802 #endif
803 vesa_SetPalette(paletteptr);
804 g_attribute = attrib_gr_normal;
805 font = vesa_FontPtrs();
806 clear_screen();
807 clipx = 0;
808 clipxmax = clipx + (viewport_size - 1);
809 }
810
811 /*
812 * Switches modes of the video card.
813 *
814 * If mode == MODETEXT (0x03), then the card is placed into text
815 * mode. Otherwise, the card is placed in the mode selected by
816 * vesa_detect. Supported modes are those with packed 8 bit pixels.
817 *
818 */
819 static void
vesa_SwitchMode(mode)820 vesa_SwitchMode(mode)
821 unsigned mode;
822 {
823 __dpmi_regs regs;
824
825 if (mode == MODETEXT) {
826 iflags.grmode = 0;
827 regs.x.ax = mode;
828 (void) __dpmi_int(VIDEO_BIOS, ®s);
829 } else if (mode >= 0x100) {
830 iflags.grmode = 1;
831 regs.x.ax = 0x4F02;
832 regs.x.bx = mode & 0x81FF;
833 (void) __dpmi_int(VIDEO_BIOS, ®s);
834 /* Record that the window position is unknown */
835 vesa_win_pos[0] = 0xFFFFFFFF;
836 vesa_win_pos[1] = 0xFFFFFFFF;
837 } else {
838 iflags.grmode = 0; /* force text mode for error msg */
839 regs.x.ax = MODETEXT;
840 (void) __dpmi_int(VIDEO_BIOS, ®s);
841 g_attribute = attrib_text_normal;
842 impossible("vesa_SwitchMode: Bad video mode requested 0x%X", mode);
843 }
844 }
845
846 /*
847 * This allows grouping of several tasks to be done when
848 * switching back to text mode. This is a public (extern) function.
849 *
850 */
851 void
vesa_Finish(void)852 vesa_Finish(void)
853 {
854 free_tiles();
855 vesa_SwitchMode(MODETEXT);
856 windowprocs.win_cliparound = tty_cliparound;
857 g_attribute = attrib_text_normal;
858 iflags.tile_view = FALSE;
859 }
860
861 /*
862 *
863 * Returns a far pointer (or flat 32 bit pointer under djgpp) to the
864 * location of the appropriate ROM font for the _current_ video mode
865 * (so you must place the card into the desired video mode before
866 * calling this function).
867 *
868 * This function takes advantage of the video BIOS loading the
869 * address of the appropriate character definition table for
870 * the current graphics mode into interrupt vector 0x43 (0000:010C).
871 */
872 static char __far *
vesa_FontPtrs(void)873 vesa_FontPtrs(void)
874 {
875 USHORT __far *tmp;
876 char __far *retval;
877 USHORT fseg, foff;
878 tmp = (USHORT __far *) MK_PTR(((USHORT) FONT_PTR_SEGMENT),
879 ((USHORT) FONT_PTR_OFFSET));
880 foff = READ_ABSOLUTE_WORD(tmp);
881 ++tmp;
882 fseg = READ_ABSOLUTE_WORD(tmp);
883 retval = (char __far *) MK_PTR(fseg, foff);
884 return retval;
885 }
886
887 /*
888 * This will verify the existance of a VGA adapter on the machine.
889 * Video function call 0x4F00 returns 0x004F in AX if successful, and
890 * returns a VbeInfoBlock describing the features of the VESA BIOS.
891 */
892 int
vesa_detect()893 vesa_detect()
894 {
895 int vbe_info_sel = -1; /* custodial */
896 int vbe_info_seg;
897 struct VbeInfoBlock vbe_info;
898 __dpmi_regs regs;
899 unsigned long mode_addr;
900 struct ModeInfoBlock mode_info;
901
902 vbe_info_seg = __dpmi_allocate_dos_memory(
903 (sizeof(vbe_info) + 15) / 16,
904 &vbe_info_sel);
905 if (vbe_info_seg < 0) goto error;
906
907 /* Request VBE 2.0 information if it is available */
908 memset(&vbe_info, 0, sizeof(vbe_info));
909 memcpy(vbe_info.VbeSignature, "VBE2", 4);
910 dosmemput(&vbe_info, sizeof(vbe_info), vbe_info_seg * 16L);
911
912 /* Request VESA BIOS information */
913 regs.x.ax = 0x4F00;
914 regs.x.di = 0;
915 regs.x.es = vbe_info_seg;
916 (void) __dpmi_int(VIDEO_BIOS, ®s);
917
918 /* Check for successful completion of function: is VESA BIOS present? */
919 if (regs.x.ax != 0x004F) goto error;
920 dosmemget(vbe_info_seg * 16L, sizeof(vbe_info), &vbe_info);
921 if (memcmp(vbe_info.VbeSignature, "VESA", 4) != 0) goto error;
922
923 /* Get the address of the mode list */
924 /* The mode list may be within the DOS memory area allocated above.
925 That area must remain allocated and must not be rewritten until
926 we're done here. */
927 mode_addr = (vbe_info.VideoModePtr >> 16) * 16L
928 + (vbe_info.VideoModePtr & 0xFFFF);
929
930 /* Scan the mode list for an acceptable mode */
931 vesa_mode = vesa_FindMode(mode_addr, 32);
932 if (vesa_mode == 0xFFFF)
933 vesa_mode = vesa_FindMode(mode_addr, 24);
934 if (vesa_mode == 0xFFFF)
935 vesa_mode = vesa_FindMode(mode_addr, 16);
936 if (vesa_mode == 0xFFFF)
937 vesa_mode = vesa_FindMode(mode_addr, 15);
938 if (vesa_mode == 0xFFFF)
939 vesa_mode = vesa_FindMode(mode_addr, 8);
940 if (vesa_mode == 0xFFFF)
941 goto error;
942
943 /* Set up the variables for the pixel functions */
944 vesa_GetModeInfo(vesa_mode, &mode_info);
945 vesa_x_res = mode_info.XResolution;
946 vesa_y_res = mode_info.YResolution;
947 vesa_x_center = (vesa_x_res - 640) / 2;
948 vesa_y_center = (vesa_y_res - 480) / 2;
949 vesa_scan_line = mode_info.BytesPerScanLine;
950 vesa_win_size = mode_info.WinSize * 1024L;
951 vesa_win_gran = mode_info.WinGranularity * 1024L;
952 vesa_pixel_size = mode_info.BitsPerPixel;
953 vesa_pixel_bytes = (vesa_pixel_size + 7) / 8;
954 if (vbe_info.VbeVersion >= 0x0300) {
955 vesa_red_pos = mode_info.RedFieldPosition;
956 vesa_red_size = mode_info.RedMaskSize;
957 vesa_green_pos = mode_info.GreenFieldPosition;
958 vesa_green_size = mode_info.GreenMaskSize;
959 vesa_blue_pos = mode_info.BlueFieldPosition;
960 vesa_blue_size = mode_info.BlueMaskSize;
961 } else {
962 switch (vesa_pixel_size) {
963 case 15:
964 vesa_blue_pos = 0;
965 vesa_blue_size = 5;
966 vesa_green_pos = 5;
967 vesa_green_size = 5;
968 vesa_red_pos = 10;
969 vesa_red_size = 5;
970 break;
971
972 case 16:
973 vesa_blue_pos = 0;
974 vesa_blue_size = 5;
975 vesa_green_pos = 5;
976 vesa_green_size = 6;
977 vesa_red_pos = 11;
978 vesa_red_size = 5;
979 break;
980
981 case 24:
982 case 32:
983 vesa_blue_pos = 0;
984 vesa_blue_size = 8;
985 vesa_green_pos = 8;
986 vesa_green_size = 8;
987 vesa_red_pos = 16;
988 vesa_red_size = 8;
989 break;
990 }
991 }
992 vesa_win_addr[0] = mode_info.WinASegment * 16L;
993 vesa_win_addr[1] = mode_info.WinBSegment * 16L;
994 vesa_win_pos[0] = 0xFFFFFFFF; /* position unknown */
995 vesa_win_pos[1] = 0xFFFFFFFF;
996 /* Read window */
997 if (mode_info.WinAAttributes & 0x2) {
998 vesa_read_win = 0;
999 } else if (mode_info.WinBAttributes & 0x2) {
1000 vesa_read_win = 1;
1001 } else {
1002 goto error; /* Shouldn't happen */
1003 }
1004 /* Write window */
1005 if (mode_info.WinAAttributes & 0x4) {
1006 vesa_write_win = 0;
1007 } else if (mode_info.WinBAttributes & 0x4) {
1008 vesa_write_win = 1;
1009 } else {
1010 goto error; /* Shouldn't happen */
1011 }
1012
1013 __dpmi_free_dos_memory(vbe_info_sel);
1014 return TRUE;
1015
1016 error:
1017 if (vbe_info_sel != -1) __dpmi_free_dos_memory(vbe_info_sel);
1018 return FALSE;
1019 }
1020
1021 static unsigned
vesa_FindMode(mode_addr,bits)1022 vesa_FindMode(mode_addr, bits)
1023 unsigned long mode_addr;
1024 unsigned bits;
1025 {
1026 unsigned selected_mode;
1027 struct ModeInfoBlock mode_info0, mode_info;
1028 unsigned model = (bits == 8) ? 4 : 6;
1029
1030 memset(&mode_info, 0, sizeof(mode_info));
1031 selected_mode = 0xFFFF;
1032 while (1) {
1033 unsigned mode = _farpeekw(_dos_ds, mode_addr);
1034 if (mode == 0xFFFF) break;
1035 mode_addr += 2;
1036
1037 /* Query the mode info; skip to next if not in fact supported */
1038 if (!vesa_GetModeInfo(mode, &mode_info0)) continue;
1039
1040 /* Check that the mode is acceptable */
1041 if (mode_info0.XResolution < 640) continue;
1042 if (mode_info0.YResolution < 480) continue;
1043 if (mode_info0.NumberOfPlanes != 1) continue;
1044 if (mode_info0.BitsPerPixel != bits) continue;
1045 if (mode_info0.NumberOfBanks != 1) continue;
1046 if (mode_info0.MemoryModel != model) continue;
1047 if (mode_info0.ModeAttributes & 0x40) continue;
1048
1049 /* The mode is OK. Accept it if it is smaller than any previous mode
1050 or if no previous mode is accepted. */
1051 if (selected_mode == 0xFFFF
1052 || mode_info0.XResolution * mode_info0.YResolution
1053 < mode_info.XResolution * mode_info.YResolution) {
1054 selected_mode = mode;
1055 mode_info = mode_info0;
1056 }
1057 }
1058
1059 return selected_mode;
1060 }
1061
1062 /*
1063 * Write character 'ch', at (x,y) and
1064 * do it using the colour 'colour'.
1065 *
1066 */
1067 static void
vesa_WriteChar(chr,col,row,colour,transparent)1068 vesa_WriteChar(chr, col, row, colour, transparent)
1069 int chr, col, row, colour;
1070 boolean transparent;
1071 {
1072 int i, j;
1073 int pixx, pixy;
1074
1075 unsigned char __far *fp = font;
1076 unsigned char fnt;
1077
1078 pixx = min(col, (CO - 1)) * 8; /* min() protects from callers */
1079 pixy = min(row, (LI - 1)) * 16; /* assumes 8 x 16 char set */
1080 pixx += vesa_x_center;
1081 pixy += vesa_y_center;
1082
1083 for (i = 0; i < MAX_ROWS_PER_CELL; ++i) {
1084 fnt = READ_ABSOLUTE((fp + chr * 16 + i));
1085 for (j = 0; j < 8; ++j) {
1086 if (fnt & (0x80 >> j)) {
1087 vesa_WritePixel(pixx + j, pixy + i, colour + FIRST_TEXT_COLOR);
1088 } else if (!transparent) {
1089 vesa_WritePixel(pixx + j, pixy + i, BACKGROUND_VESA_COLOR);
1090 }
1091 }
1092 }
1093 }
1094
1095 /*
1096 * Like vesa_WriteChar, but draw the character in local memory rather than in
1097 * the VGA frame buffer.
1098 *
1099 * vesa_redrawmap uses this to gather a row of cells in local memory and then
1100 * draw them in strict row-major order, minimizing the use of the VESA
1101 * windowing function.
1102 *
1103 */
1104 static void
vesa_WriteCharInMemory(chr,col,buf,colour)1105 vesa_WriteCharInMemory(chr, col, buf, colour)
1106 int chr, col;
1107 char buf[TILE_Y][640*2];
1108 int colour;
1109 {
1110 int i, j;
1111 int pixx;
1112
1113 unsigned char __far *fp = font;
1114 unsigned char fnt;
1115
1116 pixx = min(col, (CO - 1)) * 8; /* min() protects from callers */
1117
1118 for (i = 0; i < MAX_ROWS_PER_CELL; ++i) {
1119 fnt = READ_ABSOLUTE((fp + chr * 16 + i));
1120 for (j = 0; j < 8; ++j) {
1121 if (fnt & (0x80 >> j)) {
1122 buf[i][pixx + j] = colour + FIRST_TEXT_COLOR;
1123 } else {
1124 buf[i][pixx + j] = BACKGROUND_VESA_COLOR;
1125 }
1126 }
1127 }
1128 }
1129
1130 /*
1131 * This is the routine that displays a high-res "cell" pointed to by 'gp'
1132 * at the desired location (col,row).
1133 *
1134 * Note: (col,row) in this case refer to the coordinate location in
1135 * NetHack character grid terms, (ie. the 40 x 25 character grid),
1136 * not the x,y pixel location.
1137 *
1138 */
1139 static void
vesa_DisplayCell(tile,col,row)1140 vesa_DisplayCell(tile, col, row)
1141 const struct TileImage *tile;
1142 int col, row;
1143 {
1144 int i, j, pixx, pixy;
1145
1146 pixx = col * TILE_X;
1147 pixy = row * TILE_Y;
1148 if (iflags.over_view) {
1149 pixx /= 2;
1150 pixx += vesa_x_center;
1151 pixy += vesa_y_center;
1152 if (vesa_pixel_size != 8) {
1153 for (i = 0; i < TILE_Y; ++i) {
1154 for (j = 0; j < TILE_X; j += 2) {
1155 unsigned index = i * tile->width + j;
1156 unsigned long c1 = vesa_palette[tile->indexes[index + 0]];
1157 unsigned long c2 = vesa_palette[tile->indexes[index + 1]];
1158 unsigned char r1, r2, g1, g2, b1, b2;
1159
1160 vesa_GetRGB(c1, &r1, &g1, &b1);
1161 vesa_GetRGB(c2, &r2, &g2, &b2);
1162 r1 = (r1 + r2) / 2;
1163 g1 = (g1 + g2) / 2;
1164 b1 = (b1 + b2) / 2;
1165 vesa_WritePixel32(pixx + j / 2, pixy + i,
1166 vesa_MakeColor(r1, g1, b1));
1167 }
1168 }
1169 } else {
1170 for (i = 0; i < TILE_Y; ++i) {
1171 for (j = 0; j < TILE_X; j += 2) {
1172 unsigned index = i * tile->width + j;
1173 vesa_WritePixel(pixx + j / 2, pixy + i, tile->indexes[index]);
1174 }
1175 }
1176 }
1177 } else {
1178 pixx += vesa_x_center;
1179 pixy += vesa_y_center;
1180 for (i = 0; i < TILE_Y; ++i) {
1181 for (j = 0; j < TILE_X; ++j) {
1182 unsigned index = i * tile->width + j;
1183 vesa_WritePixel(pixx + j, pixy + i, tile->indexes[index]);
1184 }
1185 }
1186 }
1187 }
1188
1189 /*
1190 * Like vesa_DisplayCell, but draw the tile in local memory rather than in
1191 * the VGA frame buffer.
1192 *
1193 * vesa_redrawmap uses this to gather a row of cells in local memory and then
1194 * draw them in strict row-major order, minimizing the use of the VESA
1195 * windowing function.
1196 *
1197 */
1198 static void
vesa_DisplayCellInMemory(tile,col,buf)1199 vesa_DisplayCellInMemory(tile, col, buf)
1200 const struct TileImage *tile;
1201 int col;
1202 char buf[TILE_Y][640*2];
1203 {
1204 int i, j, pixx;
1205
1206 pixx = col * TILE_X;
1207 if (iflags.over_view && vesa_pixel_size == 8) {
1208 pixx /= 2;
1209 for (i = 0; i < TILE_Y; ++i) {
1210 for (j = 0; j < TILE_X; j += 2) {
1211 unsigned index = i * tile->width + j;
1212 buf[i][pixx + j / 2] = tile->indexes[index];
1213 }
1214 }
1215 } else {
1216 for (i = 0; i < TILE_Y; ++i) {
1217 for (j = 0; j < TILE_X; ++j) {
1218 unsigned index = i * tile->width + j;
1219 buf[i][pixx + j] = tile->indexes[index];
1220 }
1221 }
1222 }
1223 }
1224
1225 /*
1226 * Write the character string pointed to by 's', whose maximum length
1227 * is 'len' at location (x,y) using the 'colour' colour.
1228 *
1229 */
1230 static void
vesa_WriteStr(s,len,col,row,colour)1231 vesa_WriteStr(s, len, col, row, colour)
1232 const char *s;
1233 int len, col, row, colour;
1234 {
1235 const unsigned char *us;
1236 int i = 0;
1237
1238 /* protection from callers */
1239 if (row > (LI - 1))
1240 return;
1241
1242 i = 0;
1243 us = (const unsigned char *) s;
1244 while ((*us != 0) && (i < len) && (col < (CO - 1))) {
1245 vesa_WriteChar(*us, col, row, colour, FALSE);
1246 ++us;
1247 ++i;
1248 ++col;
1249 }
1250 }
1251
1252 /*
1253 * Initialize the VGA palette with the desired colours. This
1254 * must be a series of 720 bytes for use with a card in 256
1255 * colour mode at 640 x 480. The first 240 palette entries are
1256 * used by the tile set; the last 16 are reserved for text.
1257 *
1258 */
1259 static boolean
vesa_SetPalette(palette)1260 vesa_SetPalette(palette)
1261 const struct Pixel *palette;
1262 {
1263 if (vesa_pixel_size == 8) {
1264 vesa_SetHardPalette(palette);
1265 } else {
1266 vesa_SetSoftPalette(palette);
1267 }
1268 }
1269
1270 static boolean
vesa_SetHardPalette(palette)1271 vesa_SetHardPalette(palette)
1272 const struct Pixel *palette;
1273 {
1274 const struct Pixel *p = palette;
1275 int palette_sel = -1; /* custodial */
1276 int palette_seg;
1277 unsigned long palette_ptr;
1278 unsigned i, shift;
1279 unsigned char r, g, b;
1280 unsigned long color;
1281 __dpmi_regs regs;
1282
1283 palette_seg = __dpmi_allocate_dos_memory( 1024 / 16, &palette_sel);
1284 if (palette_seg < 0) goto error;
1285
1286 /* Use 8 bit DACs if we have them */
1287 memset(®s, 0, sizeof(regs));
1288 regs.x.ax = 0x4F08;
1289 regs.h.bl = 0;
1290 regs.h.bh = 8;
1291 (void) __dpmi_int(VIDEO_BIOS, ®s);
1292 if (regs.x.ax != 0x004F) {
1293 shift = 2;
1294 } else if (regs.h.bh > 8) {
1295 shift = 0;
1296 } else {
1297 shift = 8 - regs.h.bh;
1298 }
1299
1300 /* Set the tile set and text colors */
1301 palette_ptr = palette_seg * 16L;
1302 #ifdef USE_TILES
1303 for (i = 0; i < FIRST_TEXT_COLOR; ++i) {
1304 r = p->r >> shift;
1305 g = p->g >> shift;
1306 b = p->b >> shift;
1307 color = ((unsigned long) r << 16)
1308 | ((unsigned long) g << 8)
1309 | ((unsigned long) b << 0);
1310 _farpokel(_dos_ds, palette_ptr, color);
1311 palette_ptr += 4;
1312 ++p;
1313 }
1314 #else
1315 palette_ptr += FIRST_TEXT_COLOR * 4;
1316 #endif
1317 p = defpalette;
1318 for (i = FIRST_TEXT_COLOR; i < 256; ++i) {
1319 r = p->r >> shift;
1320 g = p->g >> shift;
1321 b = p->b >> shift;
1322 color = ((unsigned long) r << 16)
1323 | ((unsigned long) g << 8)
1324 | ((unsigned long) b << 0);
1325 _farpokel(_dos_ds, palette_ptr, color);
1326 palette_ptr += 4;
1327 ++p;
1328 }
1329
1330 memset(®s, 0, sizeof(regs));
1331 regs.x.ax = 0x4F09;
1332 regs.h.bl = 0;
1333 regs.x.cx = 256;
1334 regs.x.dx = 0;
1335 regs.x.di = 0;
1336 regs.x.es = palette_seg;
1337 (void) __dpmi_int(VIDEO_BIOS, ®s);
1338
1339 __dpmi_free_dos_memory(palette_sel);
1340 return TRUE;
1341
1342 error:
1343 if (palette_sel != -1) __dpmi_free_dos_memory(palette_sel);
1344 return FALSE;
1345 }
1346
1347 static boolean
vesa_SetSoftPalette(palette)1348 vesa_SetSoftPalette(palette)
1349 const struct Pixel *palette;
1350 {
1351 const struct Pixel *p;
1352 unsigned i;
1353 unsigned char r, g, b;
1354
1355 /* Set the tile set and text colors */
1356 #ifdef USE_TILES
1357 p = palette;
1358 for (i = 0; i < FIRST_TEXT_COLOR; ++i) {
1359 r = p->r;
1360 g = p->g;
1361 b = p->b;
1362 vesa_palette[i] = vesa_MakeColor(r, g, b);
1363 ++p;
1364 }
1365 #endif
1366 p = defpalette;
1367 for (i = FIRST_TEXT_COLOR; i < 256; ++i) {
1368 r = p->r;
1369 g = p->g;
1370 b = p->b;
1371 vesa_palette[i] = vesa_MakeColor(r, g, b);
1372 ++p;
1373 }
1374 }
1375
1376 #ifdef POSITIONBAR
1377
1378 #define PBAR_ROW (LI - 4)
1379 #define PBAR_COLOR_ON 16 /* slate grey background colour of tiles */
1380 #define PBAR_COLOR_OFF 0 /* bluish grey, used in old style only */
1381 #define PBAR_COLOR_STAIRS CLR_BROWN /* brown */
1382 #define PBAR_COLOR_HERO CLR_WHITE /* creamy white */
1383
1384 static unsigned char pbar[COLNO];
1385
1386 void
vesa_update_positionbar(posbar)1387 vesa_update_positionbar(posbar)
1388 char *posbar;
1389 {
1390 char *p = pbar;
1391 if (posbar)
1392 while (*posbar)
1393 *p++ = *posbar++;
1394 *p = 0;
1395 }
1396
1397 static void
positionbar()1398 positionbar()
1399 {
1400 char *posbar = pbar;
1401 int feature, ucol;
1402 int k, x, y, colour, row;
1403
1404 int startk, stopk;
1405 boolean nowhere = FALSE;
1406 int pixy = (PBAR_ROW * MAX_ROWS_PER_CELL);
1407 int tmp;
1408
1409 if (!iflags.grmode || !iflags.tile_view)
1410 return;
1411 if ((clipx < 0) || (clipxmax <= 0) || (clipx >= clipxmax))
1412 nowhere = TRUE;
1413 if (nowhere) {
1414 #ifdef DEBUG
1415 pline("Would have put bar using %d - %d.", clipx, clipxmax);
1416 #endif
1417 return;
1418 }
1419 #ifdef OLD_STYLE
1420 for (y = pixy; y < (pixy + MAX_ROWS_PER_CELL); ++y) {
1421 for (x = 0; x < 640; ++x) {
1422 k = x / 8;
1423 if ((k < clipx) || (k > clipxmax)) {
1424 colour = PBAR_COLOR_OFF;
1425 } else
1426 colour = PBAR_COLOR_ON;
1427 vesa_WritePixel(x + vesa_x_center, y + vesa_y_center, colour);
1428 }
1429 }
1430 #else
1431 for (y = pixy, row = 0; y < (pixy + MAX_ROWS_PER_CELL); ++y, ++row) {
1432 if ((!row) || (row == (ROWS_PER_CELL - 1))) {
1433 startk = 0;
1434 stopk = SCREENBYTES;
1435 } else {
1436 startk = clipx;
1437 stopk = clipxmax;
1438 }
1439 for (x = 0; x < 640; ++x) {
1440 k = x / 8;
1441 if ((k < startk) || (k > stopk))
1442 colour = BACKGROUND_VGA_COLOR;
1443 else
1444 colour = PBAR_COLOR_ON;
1445 vesa_WritePixel(x + vesa_x_center, y + vesa_y_center, colour);
1446 }
1447 }
1448 #endif
1449 ucol = 0;
1450 if (posbar) {
1451 while (*posbar != 0) {
1452 feature = *posbar++;
1453 switch (feature) {
1454 case '>':
1455 vesa_WriteChar(feature, (int) *posbar++, PBAR_ROW, PBAR_COLOR_STAIRS, TRUE);
1456 break;
1457 case '<':
1458 vesa_WriteChar(feature, (int) *posbar++, PBAR_ROW, PBAR_COLOR_STAIRS, TRUE);
1459 break;
1460 case '@':
1461 ucol = (int) *posbar++;
1462 vesa_WriteChar(feature, ucol, PBAR_ROW, PBAR_COLOR_HERO, TRUE);
1463 break;
1464 default: /* unanticipated symbols */
1465 vesa_WriteChar(feature, (int) *posbar++, PBAR_ROW, PBAR_COLOR_STAIRS, TRUE);
1466 break;
1467 }
1468 }
1469 }
1470 #ifdef SIMULATE_CURSOR
1471 if (inmap) {
1472 tmp = curcol + 1;
1473 if ((tmp != ucol) && (curcol >= 0))
1474 vesa_WriteChar('_', tmp, PBAR_ROW, PBAR_COLOR_HERO, TRUE);
1475 }
1476 #endif
1477 }
1478
1479 #endif /*POSITIONBAR*/
1480
1481 #ifdef SIMULATE_CURSOR
1482
1483 static unsigned long undercursor[TILE_Y][TILE_X];
1484
1485 void
vesa_DrawCursor()1486 vesa_DrawCursor()
1487 {
1488 unsigned x, y, left, top, right, bottom, width;
1489 boolean isrogue = Is_rogue_level(&u.uz);
1490 boolean halfwidth =
1491 (isrogue || iflags.over_view || iflags.traditional_view || !inmap);
1492 int curtyp;
1493
1494 if (!cursor_type && inmap)
1495 return; /* CURSOR_INVIS - nothing to do */
1496
1497 x = min(curcol, (CO - 1)); /* protection from callers */
1498 y = min(currow, (LI - 1)); /* protection from callers */
1499 if (!halfwidth && ((x < clipx) || (x > clipxmax)))
1500 return;
1501 if (inmap)
1502 x -= clipx;
1503 left = x * TILE_X; /* convert to pixels */
1504 top = y * TILE_Y;
1505 if (halfwidth) {
1506 left /= 2;
1507 width = TILE_X / 2;
1508 } else {
1509 width = TILE_X;
1510 }
1511 left += vesa_x_center;
1512 top += vesa_y_center;
1513 right = left + width - 1;
1514 bottom = top + TILE_Y - 1;
1515
1516 for (y = 0; y < ROWS_PER_CELL; ++y) {
1517 for (x = 0; x < width; ++x) {
1518 undercursor[y][x] = vesa_ReadPixel32(left + x, top + y);
1519 }
1520 }
1521
1522 /*
1523 * Now we have a snapshot of the current cell.
1524 * Write the cursor on top of the display.
1525 */
1526
1527 if (inmap)
1528 curtyp = cursor_type;
1529 else
1530 curtyp = CURSOR_UNDERLINE;
1531
1532 switch (curtyp) {
1533 case CURSOR_CORNER:
1534 vesa_WritePixel(left , top , FIRST_TEXT_COLOR + 15);
1535 vesa_WritePixel(left + 1, top , FIRST_TEXT_COLOR + 15);
1536 vesa_WritePixel(right - 1, top , FIRST_TEXT_COLOR + 15);
1537 vesa_WritePixel(right , top , FIRST_TEXT_COLOR + 15);
1538 vesa_WritePixel(left , top + 1, FIRST_TEXT_COLOR + 15);
1539 vesa_WritePixel(right , top + 1, FIRST_TEXT_COLOR + 15);
1540 vesa_WritePixel(left , bottom - 1, FIRST_TEXT_COLOR + 15);
1541 vesa_WritePixel(right , bottom - 1, FIRST_TEXT_COLOR + 15);
1542 vesa_WritePixel(left , bottom , FIRST_TEXT_COLOR + 15);
1543 vesa_WritePixel(left + 1, bottom , FIRST_TEXT_COLOR + 15);
1544 vesa_WritePixel(right - 1, bottom , FIRST_TEXT_COLOR + 15);
1545 vesa_WritePixel(right , bottom , FIRST_TEXT_COLOR + 15);
1546 break;
1547
1548 case CURSOR_UNDERLINE:
1549 for (x = left; x <= right; ++x) {
1550 vesa_WritePixel(x, bottom, FIRST_TEXT_COLOR + 15);
1551 }
1552 break;
1553
1554 case CURSOR_FRAME:
1555
1556 /* fall through */
1557
1558 default:
1559 for (x = left; x <= right; ++x) {
1560 vesa_WritePixel(x, top, FIRST_TEXT_COLOR + 15);
1561 }
1562 for (y = top + 1; y <= bottom - 1; ++y) {
1563 vesa_WritePixel(left , y, FIRST_TEXT_COLOR + 15);
1564 vesa_WritePixel(right, y, FIRST_TEXT_COLOR + 15);
1565 }
1566 for (x = left; x <= right; ++x) {
1567 vesa_WritePixel(x, bottom, FIRST_TEXT_COLOR + 15);
1568 }
1569 break;
1570 }
1571 #ifdef POSITIONBAR
1572 if (inmap)
1573 positionbar();
1574 #endif
1575 }
1576
1577 void
vesa_HideCursor()1578 vesa_HideCursor()
1579 {
1580 unsigned x, y, left, top, width;
1581 boolean isrogue = Is_rogue_level(&u.uz);
1582 boolean halfwidth =
1583 (isrogue || iflags.over_view || iflags.traditional_view || !inmap);
1584 int curtyp;
1585
1586 if (!cursor_type && inmap)
1587 return; /* CURSOR_INVIS - nothing to do */
1588
1589 x = min(curcol, (CO - 1)); /* protection from callers */
1590 y = min(currow, (LI - 1)); /* protection from callers */
1591 if (!halfwidth && ((x < clipx) || (x > clipxmax)))
1592 return;
1593 if (inmap)
1594 x -= clipx;
1595 left = x * TILE_X; /* convert to pixels */
1596 top = y * TILE_Y;
1597 if (halfwidth) {
1598 left /= 2;
1599 width = TILE_X / 2;
1600 } else {
1601 width = TILE_X;
1602 }
1603 left += vesa_x_center;
1604 top += vesa_y_center;
1605
1606 for (y = 0; y < ROWS_PER_CELL; ++y) {
1607 for (x = 0; x < width; ++x) {
1608 vesa_WritePixel32(left + x, top + y, undercursor[y][x]);
1609 }
1610 }
1611 }
1612 #endif /* SIMULATE_CURSOR */
1613 #endif /* SCREEN_VESA */
1614