OSDN Git Service

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