1 /* File: main-ibm.c */
2
3 /* Purpose: Visual Display Support for "term.c", for the IBM */
4
5
6 /*
7 * Original code by "Billy Tanksley (wtanksle@ucsd.edu)"
8 * Use "Makefile.ibm" to compile Angband using this file.
9 *
10 * Support for DJGPP v2 by "Scott Egashira (egashira@u.washington.edu)"
11 *
12 * Extensive modifications by "Ben Harrison (benh@voicenet.com)",
13 * including "collation" of the Watcom C/C++ and DOS-286 patches.
14 *
15 * Watcom C/C++ changes by "David Boeren (akemi@netcom.com)"
16 * Use "Makefile.wat" to compile this file with Watcom C/C++, and
17 * be sure to define "USE_IBM" and "USE_WAT".
18 *
19 * DOS-286 (conio.h) changes by (Roland Jay Roberts (jay@map.com)
20 * Use "Makefile.286" (not ready) to compile this file for DOS-286,
21 * and be sure to define "USE_IBM", "USE_WAT", and "USE_286". Also,
22 * depending on your compiler, you may need to define "USE_CONIO".
23 *
24 * True color palette support by "Mike Marcelais (mrmarcel@eos.ncsu.edu)",
25 * with interface to the "color_table" array by Ben Harrison.
26 *
27 * Both "shift" keys are treated as "identical", and all the modifier keys
28 * (control, shift, alt) are ignored when used with "normal" keys, unless
29 * they modify the underlying "ascii" value of the key. You must use the
30 * new "user pref files" to be able to interact with the keypad and such.
31 *
32 * The "lib/user/pref-ibm.prf" file contains macro definitions and possible
33 * alternative color set definitions. The "lib/user/font-ibm.prf" contains
34 * attr/char mappings for walls and floors and such.
35 *
36 * Note the "Term_user_ibm()" function hook, which could allow the user
37 * to interact with the "main-ibm.c" visual system. Currently this hook
38 * is unused, but, for example, it could allow the user to toggle "sound"
39 * or "graphics" modes, or to select the number of screen rows, with the
40 * extra screen rows being used for the mirror window.
41 */
42
43
44 #include "c-angband.h"
45
46
47 #ifdef USE_IBM
48
49
50 /*
51 * Use a "virtual" screen to "buffer" screen writes.
52 */
53 #define USE_VIRTUAL
54
55
56 #include <bios.h>
57 #include <dos.h>
58
59 #ifdef USE_WAT
60
61 # include <conio.h>
62
63 # ifndef USE_CONIO
64
65 # include <graph.h>
66
67 # define bioskey(C) _bios_keybrd(C)
68
69 # endif
70
71 # ifndef USE_286
72 # define int86(a,b,c) int386(a,b,c)
73 # endif
74
75 # define inportb(x) inp(x)
76 # define outportb(x,y) outp(x,y)
77
78 #else /* USE_WAT */
79
80 # if __DJGPP__ > 1
81
82 # include <pc.h>
83 # include <osfcn.h>
84
85 # else /* __DJGPP__ > 1 */
86 # ifdef __DJGPP__
87 # error "Upgrade to version 2.0 of DJGPP"
88 # endif /* __DJGPP__ */
89 # endif /* __DJGPP__ > 1 */
90
91 #endif /* USE_WAT */
92
93
94 #ifdef USE_CONIO
95
96 # include <conio.h>
97
98 /*
99 * Hack -- write directly to video card
100 */
101 extern int directvideo = 1;
102
103 /*
104 * Hack -- no virtual screen
105 */
106 # undef USE_VIRTUAL
107
108 #endif /* USE_CONIO */
109
110
111 /*
112 * Keypress input modifier flags (hard-coded by DOS)
113 */
114 #define K_RSHIFT 0 /* Right shift key down */
115 #define K_LSHIFT 1 /* Left shift key down */
116 #define K_CTRL 2 /* Ctrl key down */
117 #define K_ALT 3 /* Alt key down */
118 #define K_SCROLL 4 /* Scroll lock on */
119 #define K_NUM 5 /* Num lock on */
120 #define K_CAPS 6 /* Caps lock on */
121 #define K_INSERT 7 /* Insert on */
122
123
124 /*
125 * Foreground color bits (hard-coded by DOS)
126 */
127 #define VID_BLACK 0x00
128 #define VID_BLUE 0x01
129 #define VID_GREEN 0x02
130 #define VID_CYAN 0x03
131 #define VID_RED 0x04
132 #define VID_MAGENTA 0x05
133 #define VID_YELLOW 0x06
134 #define VID_WHITE 0x07
135
136 /*
137 * Bright text (hard-coded by DOS)
138 */
139 #define VID_BRIGHT 0x08
140
141 /*
142 * Background color bits (hard-coded by DOS)
143 */
144 #define VUD_BLACK 0x00
145 #define VUD_BLUE 0x10
146 #define VUD_GREEN 0x20
147 #define VUD_CYAN 0x30
148 #define VUD_RED 0x40
149 #define VUD_MAGENTA 0x50
150 #define VUD_YELLOW 0x60
151 #define VUD_WHITE 0x70
152
153 /*
154 * Blinking text (hard-coded by DOS)
155 */
156 #define VUD_BRIGHT 0x80
157
158
159 /*
160 * Screen Size
161 */
162 static int rows = 25;
163 static int cols = 80;
164
165
166 /*
167 * Physical Screen
168 */
169 #ifdef USE_286
170 # define PhysicalScreen ((byte *)MK_FP(0xB800,0x0000))
171 #else
172 # define PhysicalScreen ((byte *)(0xB800 << 4))
173 #endif
174
175
176 #ifdef USE_VIRTUAL
177
178 /*
179 * Virtual Screen Contents
180 */
181 static byte *VirtualScreen;
182
183 #else
184
185 /*
186 * Physical screen access
187 */
188 #define VirtualScreen PhysicalScreen
189
190 #endif
191
192
193 /*
194 * Hack -- the cursor "visibility"
195 */
196 static int saved_cur_v;
197 static int saved_cur_high;
198 static int saved_cur_low;
199
200
201 #ifndef USE_CONIO
202
203 /*
204 * This array is used for "wiping" the screen
205 */
206 static byte wiper[160];
207
208 #endif
209
210
211 /*
212 * The main screen (currently the only screen)
213 */
214 static term term_screen_body;
215
216
217 /*
218 * Choose between the "complex" and "simple" color methods
219 */
220 static byte use_color_complex = FALSE;
221
222
223 /*
224 * The "complex" color set
225 *
226 * This table is used by the "palette" code to instantiate the proper
227 * Angband colors when using hardware capable of displaying "complex"
228 * colors, see "activate_complex_color" below.
229 *
230 * The values used below are taken from the values in "main-mac.c",
231 * gamma corrected based on the tables in "io.c", and then "tweaked"
232 * until they "looked good" on the monitor of "Mike Marcelais".
233 *
234 * The entries are given as "0xBBGGRR" where each of the "blue", "green",
235 * and "red" components range from "0x00" to "0x3F". Note that this is
236 * the opposite of many systems which give the values as "0xRRGGBB", and
237 * is the opposite of the "R,G,B" codes in the comments.
238 */
239 static long ibm_color_complex[16] =
240 {
241 0x000000L, /* 0 0 0 Dark */
242 0x3f3f3fL, /* 4 4 4 White */
243 0x232323L, /* 2 2 2 Slate */
244 0x00233fL, /* 4 2 0 Orange */
245 0x000035L, /* 3 0 0 Red */
246 0x112300L, /* 0 2 1 Green */
247 0x3f0000L, /* 0 0 4 Blue */
248 0x001123L, /* 2 1 0 Umber */
249 0x111111L, /* 1 1 1 Lt. Dark */
250 0x353535L, /* 3 3 3 Lt. Slate */
251 0x3f003fL, /* 4 0 4 Purple */
252 0x003f3fL, /* 4 4 0 Yellow */
253 0x00003fL, /* 4 0 0 Lt. Red */
254 0x003f00L, /* 0 4 0 Lt. Green */
255 0x3f3f00L, /* 0 4 4 Lt. Blue */
256 0x112335L /* 3 2 1 Lt. Umber */
257 };
258
259
260 /*
261 * The "simple" color set
262 *
263 * This table is used by the "color" code to instantiate the "approximate"
264 * Angband colors using the only colors available on crappy monitors.
265 *
266 * The entries below are taken from the "color bits" defined above.
267 *
268 * Note that values from 16 to 255 are extremely ugly.
269 *
270 * The values below came from various sources, if you do not like them,
271 * get a better monitor, or edit "pref-ibm.prf" to use different codes.
272 *
273 * Note that many of the choices below suck, but so do crappy monitors.
274 */
275 static byte ibm_color_simple[16] =
276 {
277 VID_BLACK, /* Dark */
278 VID_WHITE, /* White */
279 VID_CYAN, /* Slate XXX */
280 VID_RED | VID_BRIGHT, /* Orange XXX */
281 VID_RED, /* Red */
282 VID_GREEN, /* Green */
283 VID_BLUE, /* Blue */
284 VID_YELLOW, /* Umber XXX */
285 VID_BLACK | VID_BRIGHT, /* Light Dark */
286 VID_CYAN | VID_BRIGHT, /* Light Slate XXX */
287 VID_MAGENTA, /* Violet */
288 VID_YELLOW | VID_BRIGHT, /* Yellow */
289 VID_MAGENTA | VID_BRIGHT, /* Light Red XXX */
290 VID_GREEN | VID_BRIGHT, /* Light Green */
291 VID_BLUE | VID_BRIGHT, /* Light Blue */
292 VID_YELLOW /* Light Umber XXX */
293 };
294
295
296
297 /*
298 * Activate the "ibm_color_complex" palette information.
299 *
300 * Code by Mike Marcelais, with help from "The programmer's guide
301 * to the EGA and VGA video cards" [Farraro].
302 *
303 * On VGA cards, colors go through a double-indirection when looking
304 * up the `real' color when in 16 color mode. The color value in the
305 * attribute is looked up in the EGA color registers. Then that value
306 * is looked up in the VGA color registers. Then the color is displayed.
307 * This is done for compatability. However, the EGA registers are
308 * initialized by default to 0..5, 14, 7, 38..3F and not 0..F which means
309 * that unless these are reset, the VGA setpalette function will not
310 * update the correct palette register!
311 *
312 * DJGPP's GrSetColor() does _not_ set the EGA palette list, only the
313 * VGA color list.
314 *
315 * Note that the "traditional" method, using "int86(0x10)", is very slow
316 * when called in protected mode, so we use a faster method using video
317 * ports instead.
318 *
319 * On Watcom machines, we could simply use the special "_remapallpalette()"
320 * function, which not only sets both palette lists (see below) but also
321 * checks for legality of the monitor mode, but, if we are doing bitmapped
322 * graphics, that function forgets to set the EGA registers for some reason.
323 */
activate_color_complex(void)324 static void activate_color_complex(void)
325 {
326 int i;
327
328 #if 1
329
330 /* Edit the EGA palette */
331 inportb(0x3da);
332
333 /* Edit the colors */
334 for (i = 0; i < 16; i++)
335 {
336 /* Set color "i" */
337 outportb(0x3c0, i);
338
339 /* To value "i" */
340 outportb(0x3c0, i);
341 };
342
343 /* Use that EGA palette */
344 outportb(0x3c0, 0x20);
345
346 /* Edit VGA palette, starting at color zero */
347 outportb(0x3c8, 0);
348
349 /* Send the colors */
350 for (i = 0; i < 16; i++)
351 {
352 /* Send the red, green, blue components */
353 outportb(0x3c9, ((ibm_color_complex[i]) & 0xFF));
354 outportb(0x3c9, ((ibm_color_complex[i] >> 8) & 0xFF));
355 outportb(0x3c9, ((ibm_color_complex[i] >> 16) & 0xFF));
356 }
357
358 #else /* 1 */
359
360 /* Set the colors */
361 for (i = 0; i < 16; i++)
362 {
363 union REGS r;
364
365 /* Set EGA color */
366 r.h.ah = 0x10;
367 r.h.al = 0x00;
368
369 /* Set color "i" */
370 r.h.bl = i;
371
372 /* To value "i" */
373 r.h.bh = i;
374
375 /* Do it */
376 int86(0x10, &r, &r);
377
378 /* Set VGA color */
379 r.h.ah = 0x10;
380 r.h.al = 0x10;
381
382 /* Set color "i" */
383 r.h.bh = 0x00;
384 r.h.bl = i;
385
386 /* Use this "green" value */
387 r.h.ch = ((ibm_color_complex[i] >> 8) & 0xFF);
388
389 /* Use this "blue" value */
390 r.h.cl = ((ibm_color_complex[i] >> 16) & 0xFF);
391
392 /* Use this "red" value */
393 r.h.dh = ((ibm_color_complex[i]) & 0xFF);
394
395 /* Do it */
396 int86(0x10, &r, &r);
397 }
398
399 #endif /* 1 */
400
401 };
402
403
404 /*
405 * Note the use of "(x >> 2)" to convert an 8 bit value to a 6 bit value
406 * without losing much precision.
407 */
Term_xtra_ibm_react(void)408 static int Term_xtra_ibm_react(void)
409 {
410 int i;
411
412 /* Complex method */
413 if (use_color_complex)
414 {
415 long rv, gv, bv, code;
416
417 bool change = FALSE;
418
419 /* Save the default colors */
420 for (i = 0; i < 16; i++)
421 {
422 /* Extract desired values */
423 rv = color_table[i][1] >> 2;
424 gv = color_table[i][2] >> 2;
425 bv = color_table[i][3] >> 2;
426
427 /* Extract a full color code */
428 code = ((rv) | (gv << 8) | (bv << 16));
429
430 /* Activate changes */
431 if (ibm_color_complex[i] != code)
432 {
433 /* Note the change */
434 change = TRUE;
435
436 /* Apply the desired color */
437 ibm_color_complex[i] = code;
438 }
439 }
440
441 /* Activate the palette if needed */
442 if (change) activate_color_complex();
443 }
444
445 /* Simple method */
446 else
447 {
448 /* Save the default colors */
449 for (i = 0; i < 16; i++)
450 {
451 /* Simply accept the desired colors */
452 ibm_color_simple[i] = color_table[i][0];
453 }
454 }
455
456 /* Success */
457 return (0);
458 }
459
460
461
462 /*
463 * Hack -- set the cursor "visibility"
464 */
curs_set(int v)465 static void curs_set(int v)
466 {
467 /* If needed */
468 if (saved_cur_v != v)
469 {
470 union REGS r;
471
472 /* Set cursor */
473 r.h.ah = 1;
474
475 /* Visible */
476 if (v)
477 {
478 /* Use the saved values */
479 r.h.ch = saved_cur_high;
480 r.h.cl = saved_cur_low;
481 }
482
483 /* Invisible */
484 else
485 {
486 /* Make it invisible */
487 r.h.ch = 0x20;
488 r.h.cl = 0x00;
489 }
490
491 /* Make the call */
492 int86(0x10, &r, &r);
493
494 /* Save the cursor state */
495 saved_cur_v = v;
496 }
497 }
498
499
500
501 /*
502 * Process an event (check for a keypress)
503 *
504 * The keypress processing code is often the most system dependant part
505 * of Angband, since sometimes even the choice of compiler is important.
506 *
507 * For the IBM, we divide all keypresses into two catagories, first, the
508 * "normal" keys, including all keys required to play Angband, and second,
509 * the "special" keys, such as keypad keys, function keys, and various keys
510 * used in combination with various modifier keys.
511 *
512 * To simplify this file, we use Angband's "macro processing" ability, in
513 * combination with a specialized "pref-ibm.prf" file, to handle most of the
514 * "special" keys, instead of attempting to fully analyze them here. This
515 * file only has to determine when a "special" key has been pressed, and
516 * translate it into a simple string which signals the use of a "special"
517 * key, the set of modifiers used, if any, and the hardware scan code of
518 * the actual key which was pressed. To simplify life for the user, we
519 * treat both "shift" keys as identical modifiers.
520 *
521 * The final encoding is "^_MMMxSS\r", where "MMM" encodes the modifiers
522 * ("C" for control, "S" for shift, "A" for alt, or any ordered combination),
523 * and "SS" encodes the keypress (as the two "digit" hexidecimal encoding of
524 * the scan code of the key that was pressed), and the "^_" and "x" and "\r"
525 * delimit the encoding for recognition by the macro processing code.
526 *
527 * Some important facts about scan codes follow. All "normal" keys use
528 * scan codes from 1-58. The "function" keys use 59-68 (and 133-134).
529 * The "keypad" keys use 69-83. Escape uses 1. Enter uses 28. Control
530 * uses 29. Left Shift uses 42. Right Shift uses 54. PrtScrn uses 55.
531 * Alt uses 56. Space uses 57. CapsLock uses 58. NumLock uses 69.
532 * ScrollLock uses 70. The "keypad" keys which use scan codes 71-83
533 * are ordered KP7,KP8,KP9,KP-,KP4,KP5,KP6,KP+,KP1,KP2,KP3,INS,DEL.
534 *
535 * Using "bioskey(0x10)" instead of "bioskey(0)" apparently provides more
536 * information, including better access to the keypad keys in combination
537 * with various modifiers, but only works on "PC's after 6/1/86", and there
538 * is no way to determine if the function is provided on a machine. I have
539 * been told that without it you cannot detect, for example, control-left.
540 * The basic scan code + ascii value pairs returned by the keypad follow,
541 * with values in parentheses only available to "bioskey(0x10)".
542 *
543 * / * - + 1 2 3 4
544 * Norm: 352f 372a 4a2d 4e2b 4f00 5000 5100 4b00
545 * Shft: 352f 372a 4a2d 4e2b 4f31 5032 5133 4b34
546 * Ctrl: (9500) (9600) (8e00) (9000) 7500 (9100) 7600 7300
547 *
548 * 5 6 7 8 9 0 . Enter
549 * Norm: (4c00) 4d00 4700 4800 4900 5200 5300 (e00d)
550 * Shft: 4c35 4d36 4737 4838 4939 5230 532e (e00d)
551 * Ctrl: (8f00) 7400 7700 (8d00) 8400 (9200) (9300) (e00a)
552 *
553 * See "pref-ibm.prf" for the "standard" macros for various keys.
554 *
555 * Certain "bizarre" keypad keys (such as "enter") return a "scan code"
556 * of "0xE0", and a "usable" ascii value. These keys should be treated
557 * like the normal keys, see below. XXX XXX XXX Note that these "special"
558 * keys could be prefixed with an optional "ctrl-^" which would allow them
559 * to be used in macros without hurting their use in normal situations.
560 */
Term_xtra_ibm_event(int v)561 static errr Term_xtra_ibm_event(int v)
562 {
563 int i, k, s;
564
565 bool mc = FALSE;
566 bool ms = FALSE;
567 bool ma = FALSE;
568
569
570 /* Hack -- Check for a keypress */
571 if (!v && !bioskey(1)) return (1);
572
573 /* Wait for a keypress */
574 k = bioskey(0x10);
575
576 /* Access the "modifiers" */
577 i = bioskey(2);
578
579 /* Extract the "scan code" */
580 s = ((k >> 8) & 0xFF);
581
582 /* Extract the "ascii value" */
583 k = (k & 0xFF);
584
585 /* Process "normal" keys */
586 if ((s <= 58) || (s == 0xE0))
587 {
588 /* Enqueue it */
589 if (k) Term_keypress(k);
590
591 /* Success */
592 return (0);
593 }
594
595 /* Extract the modifier flags */
596 if (i & (1 << K_CTRL)) mc = TRUE;
597 if (i & (1 << K_LSHIFT)) ms = TRUE;
598 if (i & (1 << K_RSHIFT)) ms = TRUE;
599 if (i & (1 << K_ALT)) ma = TRUE;
600
601
602 /* Begin a "macro trigger" */
603 Term_keypress(31);
604
605 /* Hack -- Send the modifiers */
606 if (mc) Term_keypress('C');
607 if (ms) Term_keypress('S');
608 if (ma) Term_keypress('A');
609
610 /* Introduce the hexidecimal scan code */
611 Term_keypress('x');
612
613 /* Encode the hexidecimal scan code */
614 Term_keypress(hexsym[s/16]);
615 Term_keypress(hexsym[s%16]);
616
617 /* End the "macro trigger" */
618 Term_keypress(13);
619
620 /* Success */
621 return (0);
622 }
623
624
625 /*
626 * Handle a "special request"
627 *
628 * The given parameters are "valid".
629 */
Term_xtra_ibm(int n,int v)630 static errr Term_xtra_ibm(int n, int v)
631 {
632 int i;
633
634 /* Analyze the request */
635 switch (n)
636 {
637 /* Make a "bell" noise */
638 case TERM_XTRA_NOISE:
639
640 /* Make a bell noise */
641 (void)write(1, "\007", 1);
642
643 /* Success */
644 return (0);
645
646 /* Set the cursor shape */
647 case TERM_XTRA_SHAPE:
648
649 /* Set cursor shape */
650 curs_set(v);
651
652 /* Success */
653 return (0);
654
655 #ifdef USE_VIRTUAL
656
657 /* Flush one line of output */
658 case TERM_XTRA_FROSH:
659
660 # ifdef USE_WAT
661
662 /* Copy the virtual screen to the physical screen */
663 memcpy(PhysicalScreen + (v*160), VirtualScreen + (v*160), 160);
664
665 # else /* USE_WAT */
666
667 /* Apply the virtual screen to the physical screen */
668 ScreenUpdateLine(VirtualScreen + ((v*cols) << 1), v);
669
670 # endif /* USE_WAT */
671
672 /* Success */
673 return (0);
674
675 #endif /* USE_VIRTUAL */
676
677 /* Clear the screen */
678 case TERM_XTRA_CLEAR:
679
680 #ifdef USE_CONIO
681
682 /* Clear the screen */
683 clrscr();
684
685 #else /* USE_CONIO */
686
687 /* Clear each line (virtual or physical) */
688 for (i = 0; i < rows; i++)
689 {
690 /* Clear the line */
691 memcpy((VirtualScreen + ((i*cols) << 1)), wiper, (cols << 1));
692 }
693
694 # ifdef USE_VIRTUAL
695
696 # ifdef USE_WAT
697
698 /* Copy the virtual screen to the physical screen */
699 memcpy(PhysicalScreen, VirtualScreen, 25*80*2);
700
701 # else /* USE_WAT */
702
703 /* Erase the physical screen */
704 ScreenClear();
705
706 # endif /* USE_WAT */
707
708 # endif /* USE_VIRTUAL */
709
710 #endif /* USE_CONIO */
711
712 /* Success */
713 return (0);
714
715 /* Process events */
716 case TERM_XTRA_EVENT:
717
718 /* Process one event */
719 return (Term_xtra_ibm_event(v));
720
721 /* Flush events */
722 case TERM_XTRA_FLUSH:
723
724 /* Strip events */
725 while (!Term_xtra_ibm_event(FALSE));
726
727 /* Success */
728 return (0);
729
730 /* React to global changes */
731 case TERM_XTRA_REACT:
732
733 /* React to "color_table" changes */
734 return (Term_xtra_ibm_react());
735
736 /* Delay for some milliseconds */
737 case TERM_XTRA_DELAY:
738
739 /* Delay if needed */
740 if (v > 0) delay(v);
741
742 /* Success */
743 return (0);
744 }
745
746 /* Unknown request */
747 return (1);
748 }
749
750
751
752 /*
753 * Move the cursor
754 *
755 * The given parameters are "valid".
756 */
Term_curs_ibm(int x,int y)757 static errr Term_curs_ibm(int x, int y)
758 {
759
760 #ifdef USE_WAT
761
762 # ifdef USE_CONIO
763
764 /* Place the cursor */
765 gotoxy(x+1, y+1);
766
767 # else /* USE_CONIO */
768
769 union REGS r;
770
771 r.h.ah = 2;
772 r.h.bh = 0;
773 r.h.dl = x;
774 r.h.dh = y;
775
776 /* Place the cursor */
777 int86(0x10, &r, &r);
778
779 # endif /* USE_CONIO */
780
781 #else /* USE_WAT */
782
783 /* Move the cursor */
784 ScreenSetCursor(y, x);
785
786 #endif /* USE_WAT */
787
788 /* Success */
789 return (0);
790 }
791
792
793 /*
794 * Erase a block of the screen
795 *
796 * The given parameters are "valid".
797 */
Term_wipe_ibm(int x,int y,int n)798 static errr Term_wipe_ibm(int x, int y, int n)
799 {
800
801 #ifdef USE_CONIO
802
803 /* Wipe the region */
804 window(x+1, y+1, x+n, y+1);
805 clrscr();
806 window(1, 1, cols, rows);
807
808 #else /* USE_CONIO */
809
810 /* Wipe part of the virtual (or physical) screen */
811 memcpy(VirtualScreen + ((cols*y + x)<<1), wiper, n<<1);
812
813 #endif /* USE_CONIO */
814
815 /* Success */
816 return (0);
817 }
818
819
820 /*
821 * Place some text on the screen using an attribute
822 *
823 * The given parameters are "valid". Be careful with "a".
824 * The string "s" is null terminated, and has length "n".
825 */
Term_text_ibm(int x,int y,int n,byte a,cptr s)826 static errr Term_text_ibm(int x, int y, int n, byte a, cptr s)
827 {
828 register byte attr;
829 register byte *dest;
830
831
832 /* Handle "complex" color */
833 if (use_color_complex)
834 {
835 /* Extract a color index */
836 attr = (a & 0x0F);
837 }
838
839 /* Handle "simple" color */
840 else
841 {
842 /* Extract a color value */
843 attr = ibm_color_simple[a & 0x0F];
844 }
845
846 #ifdef USE_CONIO
847
848 /* Set the attribute */
849 textattr(attr);
850
851 /* Place the cursor */
852 gotoxy(x+1, y+1);
853
854 /* Dump the text */
855 for (; *s; s++) putch(*s);
856
857 #else /* USE_CONIO */
858
859 /* Access the virtual (or physical) screen */
860 dest = VirtualScreen + (((cols * y) + x) << 1);
861
862 /* Save the data */
863 while (*s)
864 {
865 *dest++ = *s++;
866 *dest++ = attr;
867 }
868
869 #endif /* USE_CONIO */
870
871 /* Success */
872 return (0);
873 }
874
875
876 /*
877 * Init a Term
878 */
Term_init_ibm(term * t)879 static void Term_init_ibm(term *t)
880 {
881 /* XXX Nothing */
882 }
883
884
885 /*
886 * Nuke a Term
887 */
Term_nuke_ibm(term * t)888 static void Term_nuke_ibm(term *t)
889 {
890 union REGS r;
891
892 /* Move the cursor to the bottom of the screen */
893 Term_curs_ibm(0, rows-1);
894
895 #ifdef USE_WAT
896 /* Restore the original video mode */
897 _setvideomode(_DEFAULTMODE);
898 #else
899 /* Restore the original video mode */
900 r.h.ah = 0x00;
901 r.h.al = 0x03;
902 int86(0x10, &r, &r);
903 #endif
904
905 /* Make the cursor visible */
906 curs_set(1);
907 }
908
909
910
911 #ifdef USE_GRAPHICS
912
913 #ifdef USE_286
914
915 /*
916 * In 286 mode we don't need to worry about translating from a 32bit
917 * pointer to a 16 bit pointer so we just call the interrupt function
918 *
919 * Note the use of "intr()" instead of "int86()" so we can pass
920 * segment registers.
921 */
enable_graphic_font(void * font)922 void enable_graphic_font(void *font)
923 {
924 union REGPACK regs =
925 {0};
926
927 regs.h.ah = 0x11; /* Text font function */
928 regs.h.bh = 0x10; /* Size of a character -- 16 bytes */
929 regs.h.cl = 0xFF; /* Last character in font */
930 regs.x.es = FP_SEG(font); /* Pointer to font */
931 regs.x.bp = FP_OFF(font);
932 intr(0x10, ®s);
933 };
934
935 #else /* USE_286 */
936
937 #ifdef USE_WAT
938
939 /*
940 * This structure is used by the DMPI function to hold registers when
941 * doing a real mode interrupt call. (Stolen from the DJGPP <dpmi.h>
942 * header file).
943 */
944
945 typedef union
946 {
947 struct
948 {
949 unsigned long edi;
950 unsigned long esi;
951 unsigned long ebp;
952 unsigned long res;
953 unsigned long ebx;
954 unsigned long edx;
955 unsigned long ecx;
956 unsigned long eax;
957 } d;
958 struct
959 {
960 unsigned short di, di_hi;
961 unsigned short si, si_hi;
962 unsigned short bp, bp_hi;
963 unsigned short res, res_hi;
964 unsigned short bx, bx_hi;
965 unsigned short dx, dx_hi;
966 unsigned short cx, cx_hi;
967 unsigned short ax, ax_hi;
968 unsigned short flags;
969 unsigned short es;
970 unsigned short ds;
971 unsigned short fs;
972 unsigned short gs;
973 unsigned short ip;
974 unsigned short cs;
975 unsigned short sp;
976 unsigned short ss;
977 } x;
978 struct
979 {
980 unsigned char edi[4];
981 unsigned char esi[4];
982 unsigned char ebp[4];
983 unsigned char res[4];
984 unsigned char bl, bh, ebx_b2, ebx_b3;
985 unsigned char dl, dh, edx_b2, edx_b3;
986 unsigned char cl, ch, ecx_b2, ecx_b3;
987 unsigned char al, ah, eax_b2, eax_b3;
988 } h;
989 } __dpmi_regs;
990
__dpmi_allocate_dos_memory(int size,unsigned * selector)991 unsigned __dpmi_allocate_dos_memory(int size, unsigned *selector)
992 {
993 union REGPACK regs =
994 {0};
995
996 regs.w.ax = 0x100; /* DPMI function -- allocate low memory */
997 regs.w.bx = size; /* Number of Paragraphs to allocate */
998 intr(0x31, ®s); /* DPMI interface */
999
1000 *selector = regs.w.dx;
1001 return (regs.w.ax);
1002 };
1003
__dpmi_free_dos_memory(unsigned sel)1004 void __dpmi_free_dos_memory(unsigned sel)
1005 {
1006 union REGPACK regs =
1007 {0};
1008
1009 regs.w.ax = 0x101; /* DPMI function -- free low memory */
1010 regs.x.edx = sel; /* PM selector for memory block */
1011 intr(0x31, ®s); /* DPMI interface */
1012 };
1013
__dpmi_int(int intno,__dpmi_regs * dblock)1014 void __dpmi_int(int intno, __dpmi_regs *dblock)
1015 {
1016 union REGPACK regs =
1017 {0};
1018
1019 regs.w.ax = 0x300; /* DPMI function -- real mode interrupt */
1020 regs.h.bl = intno; /* interrupt 0x10 */
1021 regs.x.edi = FP_OFF(dblock); /* Pointer to dblock (offset and segment) */
1022 regs.x.es = FP_SEG(dblock);
1023 intr(0x31, ®s); /* DPMI interface */
1024 };
1025
1026 unsigned short __dpmi_sel = 0x0000;
1027 #define _farsetsel(x) __dpmi_sel=(x)
1028 extern void _farnspokeb(unsigned long offset, unsigned char value);
1029 #pragma aux _farnspokeb = \
1030 "push fs" \
1031 "mov fs,__dpmi_sel" \
1032 "mov fs:[eax],bl" \
1033 "pop fs" \
1034 parm [eax] [bl];
1035
1036 #else /* USE_WAT */
1037
1038 #include <dpmi.h>
1039 #include <go32.h>
1040 #include <sys/farptr.h>
1041
1042 #endif /* USE_WAT */
1043
1044 /*
1045 * Since you cannot send 32bit pointers to a 16bit interrupt handler
1046 * and the video BIOS wants a (16bit) pointer to the font, we have
1047 * to allocate a block of dos memory, copy the font into it, then
1048 * translate a 32bit pointer into a 16bit pointer to that block.
1049 *
1050 * DPMI - Dos Protected Mode Interface provides functions that let
1051 * us do that.
1052 */
enable_graphic_font(const char * font)1053 void enable_graphic_font(const char *font)
1054 {
1055 __dpmi_regs dblock =
1056 {
1057 {0}};
1058
1059 unsigned seg, sel, i;
1060
1061 /*
1062 * Allocate a block of memory 4096 bytes big in `low memory' so a real
1063 * mode interrupt can access it. Real mode pointer is returned as seg:0
1064 * Protected mode pointer is sel:0.
1065 */
1066 seg = __dpmi_allocate_dos_memory(256, &sel);
1067
1068 /* Copy the information into low memory buffer, by copying one byte at
1069 * a time. According to the info in <sys/farptr.h>, the functions
1070 * _farsetsel() and _farnspokeb() will optimise away completely
1071 */
1072 _farsetsel(sel); /* Set the selector to write to */
1073 for (i = 0; i<4096; i++)
1074 {
1075 _farnspokeb(i, *font++); /* Copy 1 byte into low (far) memory */
1076 }
1077
1078 /*
1079 * Now we use DPMI as a jumper to call the real mode interrupt. This
1080 * is needed because loading `es' while in protected mode with a real
1081 * mode pointer will cause an Protection Fault and calling the interrupt
1082 * directly using the protected mode pointer will result in garbage
1083 * being received by the interrupt routine
1084 */
1085 dblock.d.eax = 0x1100; /* BIOS function -- set font */
1086 dblock.d.ebx = 0x1000; /* bh = size of a letter; bl = 0 (reserved) */
1087 dblock.d.ecx = 0x00FF; /* Last character in font */
1088 dblock.x.es = seg; /* Pointer to font segment */
1089 dblock.d.ebp = 0x0000; /* Pointer to font offset */
1090
1091 __dpmi_int(0x10, &dblock);
1092
1093 /* We're done with the low memory, free it */
1094 __dpmi_free_dos_memory(sel);
1095 };
1096
1097 #endif /* USE_286 */
1098
1099 #endif /* ALLOW_GRAPH */
1100
1101
1102
1103 /*
1104 * Initialize the IBM "visual module"
1105 *
1106 * Hack -- we assume that "blank space" should be "white space"
1107 * (and not "black space" which might make more sense).
1108 *
1109 * Note the use of "((x << 2) | (x >> 4))" to "expand" a 6 bit value
1110 * into an 8 bit value, without losing much precision, by using the 2
1111 * most significant bits as the least significant bits in the new value.
1112 */
init_ibm(void)1113 errr init_ibm(void)
1114 {
1115 int i;
1116 int mode;
1117 int rv, gv, bv;
1118 bool want_graphics;
1119
1120 term *t = &term_screen_body;
1121
1122 union REGS r;
1123
1124 /* Check for "Windows" */
1125 if (getenv("windir"))
1126 {
1127 r.h.ah = 0x16; /* Windows API Call -- Set device focus */
1128 r.h.al = 0x8B; /* Causes Dos boxes to become fullscreen */
1129 r.h.bh = r.h.bl = 0x00; /* 0x0000 = current Dos box */
1130 int86(0x2F, &r, &r); /* Call the Windows API */
1131 };
1132
1133 #ifdef USE_WAT
1134
1135 /* Set the video mode */
1136 if (_setvideomode(_VRES16COLOR))
1137 {
1138 mode = 0x13;
1139 }
1140
1141 /* Wimpy monitor */
1142 else
1143 {
1144 mode = 0x03;
1145 }
1146
1147 /* Force 25 line mode */
1148 _setvideomode(_TEXTC80);
1149 _settextrows(25);
1150
1151 #else /* USE_WAT */
1152
1153 /* Set video mode */
1154 r.h.ah = 0x00;
1155 r.h.al = 0x13; /* VGA only mode */
1156 int86(0x10, &r, &r);
1157
1158 /* Get video mode */
1159 r.h.ah = 0x0F;
1160 int86(0x10, &r, &r);
1161 mode = r.h.al;
1162
1163 /* Set video mode */
1164 r.h.ah = 0x00;
1165 r.h.al = 0x03; /* Color text mode */
1166 int86(0x10, &r, &r);
1167
1168 #endif /* USE_WAT */
1169
1170 /* Check video mode */
1171 if (mode == 0x13)
1172 {
1173 /* Remember the mode */
1174 use_color_complex = TRUE;
1175
1176 /* Instantiate the color set */
1177 activate_color_complex();
1178 }
1179
1180 /* Graphics request */
1181 want_graphics = use_graphics;
1182
1183 /* No graphics */
1184 use_graphics = FALSE;
1185
1186 #ifdef USE_GRAPHICS
1187
1188 /* Try to activate bitmap graphics */
1189 if (want_graphics && use_color_complex)
1190 {
1191 FILE *f;
1192
1193 char buf[4096];
1194
1195 /* Build the filename */
1196 path_build(buf, 1024, ANGBAND_DIR_XTRA, "angband.fnt");
1197
1198 /* Open the file */
1199 f = fopen(buf, "rb");
1200
1201 /* Okay */
1202 if (f)
1203 {
1204 /* Load the bitmap data */
1205 if (fread(buf, 1, 4096, f) != 4096)
1206 {
1207 quit("Corrupt 'angband.fnt' file");
1208 }
1209
1210 /* Close the file */
1211 fclose(f);
1212
1213 /* Enable graphics */
1214 enable_graphic_font(buf);
1215
1216 /* Enable colors (again) */
1217 activate_color_complex();
1218
1219 /* Use graphics */
1220 use_graphics = TRUE;
1221 }
1222 }
1223
1224 #endif
1225
1226 /* Initialize "color_table" */
1227 for (i = 0; i < 16; i++)
1228 {
1229 /* Extract the "complex" codes */
1230 rv = ((ibm_color_complex[i]) & 0xFF);
1231 gv = ((ibm_color_complex[i] >> 8) & 0xFF);
1232 bv = ((ibm_color_complex[i] >> 16) & 0xFF);
1233
1234 /* Save the "complex" codes */
1235 color_table[i][0] = ibm_color_simple[i];
1236 color_table[i][1] = ((rv << 2) | (rv >> 4));
1237 color_table[i][2] = ((gv << 2) | (gv >> 4));
1238 color_table[i][3] = ((bv << 2) | (bv >> 4));
1239 }
1240
1241
1242 #ifndef USE_CONIO
1243
1244 /* Build a "wiper line" */
1245 for (i = 0; i < 80; i++)
1246 {
1247 /* Space */
1248 wiper[2*i] = ' ';
1249
1250 /* Black */
1251 wiper[2*i+1] = 0;
1252 }
1253
1254 #endif
1255
1256
1257 #ifdef USE_VIRTUAL
1258
1259 /* Make the virtual screen */
1260 C_MAKE(VirtualScreen, rows * cols * 2, byte);
1261
1262 #endif
1263
1264
1265 /* Erase the screen */
1266 Term_xtra_ibm(TERM_XTRA_CLEAR, 0);
1267
1268
1269 /* Place the cursor */
1270 Term_curs_ibm(0, 0);
1271
1272
1273 /* Access the "default" cursor info */
1274 r.h.ah = 3;
1275 r.h.bh = 0;
1276
1277 /* Make the call */
1278 int86(0x10, &r, &r);
1279
1280 /* Extract the standard cursor info */
1281 saved_cur_v = 1;
1282 saved_cur_high = r.h.ch;
1283 saved_cur_low = r.h.cl;
1284
1285
1286 /* Initialize the term */
1287 term_init(t, 80, 24, 256);
1288
1289 /* Prepare the init/nuke hooks */
1290 t->init_hook = Term_init_ibm;
1291 t->nuke_hook = Term_nuke_ibm;
1292
1293 /* Connect the hooks */
1294 t->xtra_hook = Term_xtra_ibm;
1295 t->curs_hook = Term_curs_ibm;
1296 t->wipe_hook = Term_wipe_ibm;
1297 t->text_hook = Term_text_ibm;
1298
1299 /* Save it */
1300 term_screen = t;
1301
1302 /* Activate it */
1303 Term_activate(term_screen);
1304
1305 /* Success */
1306 return 0;
1307 }
1308
1309
1310 #endif /* USE_IBM */
1311
1312