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, &regs);
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, &regs);    /* 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, &regs);       /* 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, &regs);            /* 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