1 /*
2  *	gfx.cc
3  *	Graphics routines.
4  *	BW & RQ sometime in 1993 or 1994.
5  */
6 
7 
8 /*
9 This file is part of Yadex.
10 
11 Yadex incorporates code from DEU 5.21 that was put in the public domain in
12 1994 by Rapha�l Quinet and Brendon Wyber.
13 
14 The rest of Yadex is Copyright � 1997-2003 Andr� Majorel and others.
15 
16 This program is free software; you can redistribute it and/or modify it under
17 the terms of the GNU General Public License as published by the Free Software
18 Foundation; either version 2 of the License, or (at your option) any later
19 version.
20 
21 This program is distributed in the hope that it will be useful, but WITHOUT
22 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
23 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
24 
25 You should have received a copy of the GNU General Public License along with
26 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
27 Place, Suite 330, Boston, MA 02111-1307, USA.
28 */
29 
30 
31 #include "yadex.h"
32 #include <math.h>
33 #ifdef Y_X11
34 #include <X11/Xlib.h>
35 #include <X11/Xutil.h>
36 #endif
37 #include "acolours.h"
38 #include "gcolour1.h"
39 #include "gcolour2.h"
40 #include "gcolour3.h"
41 #include "gfx.h"
42 #include "levels.h"  /* Level */
43 #include "x11.h"
44 
45 #ifdef Y_DOS
46 #include <direct.h>
47 #endif
48 
49 
50 
51 // If your graphics driver doesn't like circles, draw squares instead
52 #if defined NO_CIRCLES && defined Y_BGI
53 #define circle (x, y, r)	line (x - r, y - r, x - r, y + r); \
54 				line (x - r, y + r, x + r, y + r); \
55 				line (x + r, y + r, x + r, y - r); \
56 				line (x + r, y - r, x - r, y - r)
57 #endif  /* NO_CIRCLES */
58 
59 /* Parameters set by the command line args and config file */
60 const char *BGIDriver = "VESA";	// BGI: default extended BGI driver
61 bool  CirrusCursor = false;	// use HW cursor on Cirrus Logic VGA cards
62 bool  FakeCursor = false;	// use a "fake" mouse cursor
63 const char *font_name = NULL;	// X: the name of the font to load
64 Win_dim initial_window_width ("90%");	// X: the name says it all
65 Win_dim initial_window_height ("90%");	// X: the name says it all
66 int   no_pixmap;		// X: use no pixmap -- direct window output
67 int   VideoMode = 2;		// BGI: default video mode for VESA cards
68 
69 /* Global variables */
70 int GfxMode = 0;	// graphics mode number, or 0 for text
71 			// 1 = 320x200, 2 = 640x480, 3 = 800x600, 4 = 1kx768
72 			// positive = 16 colors, negative = 256 colors
73 int OrigX;		// Map X-coord of centre of screen/window
74 int OrigY;		// Map Y-coord of centre of screen/window
75 float Scale;		// the scale value
76 int ScrMaxX;		// Maximum display X-coord of screen/window
77 int ScrMaxY;		// Maximum display Y-coord of screen/window
78 int ScrCenterX;		// Display X-coord of centre of screen/window
79 int ScrCenterY;		// Display Y-coord of centre of screen/window
80 unsigned FONTH;
81 unsigned FONTW;
82 int font_xofs;
83 int font_yofs;
84 
85 
86 #ifdef Y_X11
87 Display *dpy;		// The X display
88 int      scn;		// The X screen number
89 Colormap cmap = 0;	// The X colormap
90 GC       gc;		// Default GC as set by set_colour(), SetDrawingMode()
91                         // and SetLineThickness()
92 GC       pixmap_gc;	// The GC used to clear the pixmap
93 Window   win;		// The X window
94 Pixmap   pixmap;	// The X pixmap (if any)
95 Drawable drw;		// Points to either <win> or <pixmap>
96 int      drw_mods;	// Number of modifications to drw since last call to
97 			// update_display(). Number of modifications to drw
98 			// plus 1 since last call to ClearScreen().
99 Visual  *win_vis;	// The visual for win */
100 xpv_t    win_r_mask;	// The RGB masks for win's visual */
101 xpv_t    win_g_mask;
102 xpv_t    win_b_mask;
103 int      win_r_bits;	// The RGB masks' respective lengths */
104 int      win_g_bits;
105 int      win_b_bits;
106 int      win_r_ofs;	// The RGB masks' respective offsets relative to b0 */
107 int      win_g_ofs;
108 int      win_b_ofs;
109 int      win_ncolours;	// The number of possible colours for win's visual.
110 			// If win_vis_class is TrueColor or DirectColor,
111 			// it's the number of bits in the biggest subfield.
112 int      win_vis_class;	// The class of win's visual
113 VisualID win_vis_id;	// The ID of win's visual
114 int      win_depth;	// The depth of win in bits
115 int      x_server_big_endian = 0;	// Is the X server big endian ?
116 int      ximage_bpp;	// Number of bytes per pixels in XImages
117 int      ximage_quantum;// Pad XImages lines to a multiple of that many bytes
118 static pcolour_t *app_colour = 0;	// Pixel values for the app. colours
119 static int DrawingMode    = 0;		// 0 = copy, 1 = xor
120 static int LineThickness  = 0;		// 0 = thin, 1 = thick
121 int      text_dot         = 0;		// DrawScreenText() debug flag
122 #endif
123 static acolour_t colour_stack[4];
124 static int       colour_stack_pointer = 0;
125 static Font      font_xfont;
126 static bool      default_font = true;
127 
128 #if defined Y_BGI && defined CIRRUS_PATCH
129 char mp[256];
130 char HWCursor[] =
131 {
132   0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
133   0x30, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00,
134   0x1F, 0x00, 0x00, 0x00, 0x1F, 0xC0, 0x00, 0x00,
135   0x0F, 0xF0, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00,
136   0x07, 0xC0, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00,
137   0x03, 0x70, 0x00, 0x00, 0x02, 0x38, 0x00, 0x00,
138   0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
139   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
140   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
141   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
142   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
143   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
144   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
145   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
146   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
147   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
148   0x3F, 0xFF, 0xFF, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF,
149   0x83, 0xFF, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF,
150   0xC0, 0x3F, 0xFF, 0xFF, 0xC0, 0x0F, 0xFF, 0xFF,
151   0xE0, 0x07, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xFF,
152   0xF0, 0x1F, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF,
153   0xF8, 0x07, 0xFF, 0xFF, 0xF8, 0x83, 0xFF, 0xFF,
154   0xFD, 0xC7, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF,
155   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
156   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
157   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
158   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
159   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
160   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
161   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
162   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
163   0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
164 };
165 #endif  /* Y_BGI && CIRRUS_PATCH */
166 
167 
168 /*
169  *	Prototypes
170  */
171 #ifdef Y_BGI
172 static int cooked_installuserdriver (const char far *__name,
173                              int huge (*detect)(void));
174 #endif
175 
176 /*
177  *	InitGfx - initialize the graphics display
178  *
179  *	Return 0 on success, non-zero on failure
180  */
InitGfx(void)181 int InitGfx (void)
182 {
183   // Initialization is in fact not necessary
184   int width;
185   int height;
186 
187 #if defined Y_BGI
188   static bool firsttime = true;
189   static int  gdriver;
190   static int  gmode;
191   int         errorcode = grNoInitGraph;
192 
193   verbmsg ("Switching to graphics mode...\n");
194 #if defined Y_BGI && defined CIRRUS_PATCH
195   if (CirrusCursor)
196     SetHWCursorMap (HWCursor);
197 #endif  /* Y_BGI && CIRRUS_PATCH */
198   if (firsttime)
199   {
200     if (VideoMode > 0)
201     {
202       gdriver = cooked_installuserdriver (BGIDriver, NULL);
203       gmode = VideoMode;
204       initgraph (&gdriver, &gmode, install_dir);
205       errorcode = graphresult ();
206     }
207     if (errorcode != grOk)
208     {
209       gdriver = VGA;
210       gmode = VGAHI;
211     }
212   }
213   if (gdriver == VGA || !firsttime)
214   {
215     initgraph (&gdriver, &gmode, install_dir);
216     errorcode = graphresult ();
217     if (errorcode != grOk)
218       fatal_error ("graphics error: %s", grapherrormsg (errorcode));
219   }
220   if (gdriver == VGA)
221     GfxMode = 2;  // 640x480x16
222   else
223   {
224     GfxMode = -gmode;  // 640x480x256, 800x600x256, or 1024x768x256
225     SetDoomPalette (0);
226   }
227   verbmsg ("GfxMode=%d\n", GfxMode);
228   setlinestyle (0, 0, 1);
229   setbkcolor (TranslateToDoomColor (BLACK));
230   settextstyle (0, 0, 1);
231   firsttime = false;
232   width = getmaxx () + 1;
233   height = getmaxy () + 1;
234 
235 #elif defined Y_X11
236 
237   /*
238    *	Open display and get screen number
239    */
240   dpy = XOpenDisplay (0);
241   if (! dpy)
242   {
243     err ("Can't open display");
244     return 1;
245   }
246   scn = DefaultScreen (dpy);
247   {
248     verbmsg ("X: server endianness: ");
249     int r = ImageByteOrder (dpy);
250     if (r == LSBFirst)
251     {
252       verbmsg ("little-endian\n");
253       x_server_big_endian = 0;
254     }
255     else if (r == MSBFirst)
256     {
257       verbmsg ("big-endian\n");
258       x_server_big_endian = 1;
259     }
260     else					// Can't happen
261     {
262       verbmsg ("unknown\n");
263       warn ("don't understand X server's endianness code %d\n", r);
264       warn ("assuming same endianness as CPU.\n");
265       x_server_big_endian = cpu_big_endian;
266     }
267   }
268   int screen_width  = DisplayWidth  (dpy, scn);
269   int screen_height = DisplayHeight (dpy, scn);
270   // On QNX 6, XFree returns silly values. Use a plausible default instead.
271   if (screen_width == 16383 && screen_height == 16383)
272   {
273     warn ("QNX XFree bug detected (width %d, height %d)\n",
274 	screen_width, screen_height);
275     screen_width  = 1024;
276     screen_height = 768;
277   }
278 
279 
280   /*
281    *	Create the window
282    */
283   width  = initial_window_width.pixels  (screen_width);
284   height = initial_window_height.pixels (screen_height);
285   win = XCreateSimpleWindow (dpy, DefaultRootWindow (dpy),
286     10, 10, width, height, 0, 0, 0);
287   //win = DefaultRootWindow (dpy);
288   {
289     XWindowAttributes wa;
290     XVisualInfo model;
291     XVisualInfo *vis_info;
292     int nvisuals;
293 
294     XGetWindowAttributes (dpy, win, &wa);
295     win_vis   = wa.visual;
296     win_depth = wa.depth;
297     verbmsg ("X: window depth: %d b\n", win_depth);
298 
299     /*
300      *	Retrieve info regarding win's visual
301      */
302     model.visualid = XVisualIDFromVisual (win_vis);
303     vis_info = XGetVisualInfo (dpy, VisualIDMask, &model, &nvisuals);
304     if (! vis_info)
305       fatal_error ("XGetVisualInfo returned NULL for ID %d", model.visualid);
306     if (nvisuals != 1)
307       fatal_error ("XGetVisualInfo returned %d visuals", nvisuals);
308     if (vis_info->depth != win_depth)
309       fatal_error ("Visual depth %d <> win depth %d", vis_info->depth, win_depth);
310     win_vis_id    = vis_info->visualid;
311 #if defined _cplusplus || defined __cplusplus
312     win_vis_class = vis_info->c_class;
313 #elif
314     win_vis_class = vis_info->class;
315 #endif
316     win_ncolours  = vis_info->colormap_size;
317     win_r_mask    = vis_info->red_mask;
318     win_g_mask    = vis_info->green_mask;
319     win_b_mask    = vis_info->blue_mask;
320     XFree (vis_info);
321     verbmsg ("X: visual: id %xh, class ", (unsigned) win_vis_id);
322     if (win_vis_class == PseudoColor)
323       verbmsg ("PseudoColor");
324     else if (win_vis_class == TrueColor)
325       verbmsg ("TrueColor");
326     else if (win_vis_class == DirectColor)
327       verbmsg ("DirectColor");
328     else if (win_vis_class == StaticColor)
329       verbmsg ("StaticColor");
330     else if (win_vis_class == GrayScale)
331       verbmsg ("GrayScale");
332     else if (win_vis_class == StaticGray)
333       verbmsg ("StaticGray");
334     else
335       verbmsg ("unknown (%d)", win_vis_class);
336     verbmsg (", colours %d, masks %08lX %08lX %08lX\n",
337       win_ncolours, win_r_mask, win_g_mask, win_b_mask);
338 
339     // Compute win_[rgb]_bits and win_[rgb]_ofs
340     /* FIXME can enter infinite loop if MSb of either mask is set
341        and >> sign extends. */
342     if (win_r_mask)
343     {
344       xpv_t mask;
345       for (mask = win_r_mask, win_r_ofs = 0; ! (mask & 1); mask >>= 1)
346 	 win_r_ofs++;
347       for (win_r_bits = 0; mask & 1; mask >>= 1)
348 	 win_r_bits++;
349     }
350     if (win_g_mask)
351     {
352       xpv_t mask;
353       for (mask = win_g_mask, win_g_ofs = 0; ! (mask & 1); mask >>= 1)
354 	 win_g_ofs++;
355       for (win_g_bits = 0; mask & 1; mask >>= 1)
356 	 win_g_bits++;
357     }
358     if (win_b_mask)
359     {
360       xpv_t mask;
361       for (mask = win_b_mask, win_b_ofs = 0; ! (mask & 1); mask >>= 1)
362 	 win_b_ofs++;
363       for (win_b_bits = 0; mask & 1; mask >>= 1)
364 	 win_b_bits++;
365     }
366     verbmsg ("X: visual: "
367 	     "r_ofs %d, r_bits %d, ", win_r_ofs, win_r_bits);
368     verbmsg ("g_ofs %d, g_bits %d, ", win_g_ofs, win_g_bits);
369     verbmsg ("b_ofs %d, b_bits %d\n", win_b_ofs, win_b_bits);
370   }
371 
372   /*
373    *	Get info relevant to XImages
374    */
375   ximage_bpp     = 0;
376   ximage_quantum = 0;
377   {
378     int nformats = 0;
379     XPixmapFormatValues *format = XListPixmapFormats (dpy, &nformats);
380     if (format == 0 || nformats < 1)
381     {
382       warn ("XListPixmapFormats() trouble (ret=%p, n=%d).\n", format, nformats);
383       goto ximage_done;
384     }
385     /* Pick the best possible pixmap format. Prefer one that has the
386        same depth as the drawable, as it is likely to be the fastest
387        one. Should there be several formats that satisfy that
388        requirement (I don't think that ever happens), prefer the one
389        where the line quantum is equal to the number of bits per
390        pixel, as that is easier to work with. */
391     {
392       const XPixmapFormatValues *best = 0;
393       for (int n = 0; n < nformats; n++)
394       {
395 	const XPixmapFormatValues *current = format + n;
396 	verbmsg ("X: pixmap format:"
397 	    " #%d, depth %2d, bits_per_pixel %2d, scanline_pad %2d\n",
398 	    n, current->depth, current->bits_per_pixel, current->scanline_pad);
399 	if (best == 0)
400 	{
401 	  best = current;
402 	  continue;
403 	}
404 	int cgoodness = 2 * (current->depth == win_depth)
405 		      + 1 * (current->scanline_pad == current->bits_per_pixel);
406 	int bgoodness = 2 * (best->depth == win_depth)
407 		      + 1 * (best->scanline_pad == best->bits_per_pixel);
408 	if (cgoodness > bgoodness)
409 	  best = current;
410       }
411       verbmsg ("X: pixmap format: best is #%d\n", int (best - format));
412       if (best != 0)
413       {
414 	int bits_per_pixel = best->bits_per_pixel;
415 	if (bits_per_pixel % 8)  // Paranoia
416 	 {
417 	   round_up (bits_per_pixel, 8);
418 	   warn ("XImage format has bad bits_per_pixel %d. Rounding up to %d.\n",
419 	      best->bits_per_pixel, bits_per_pixel);
420 	 }
421 	int scanline_pad = best->scanline_pad;
422 	if (best->scanline_pad % 8)  // Paranoia
423 	 {
424 	   round_up (scanline_pad, 8);
425 	   warn ("XImage format has bad scanline_pad %d. Rounding up to %d.\n",
426 	      best->scanline_pad, scanline_pad);
427 	 }
428 	ximage_bpp     = bits_per_pixel / 8;
429 	ximage_quantum = scanline_pad   / 8;
430       }
431     }
432     if (ximage_bpp == 0 || ximage_quantum == 0)
433     {
434       warn ("XListPixmapFormats() returned no suitable formats.\n");
435       goto ximage_done;
436     }
437     ximage_done:
438     if (format != 0)
439       XFree (format);
440   }
441   /* Could not obtain authoritative/good values. Warn and guess
442      plausible values. */
443   if (ximage_bpp == 0 || ximage_quantum == 0)
444   {
445     if (ximage_bpp == 0)
446       ximage_bpp = (win_depth + 7) / 8;
447     if (ximage_quantum == 0)
448       ximage_quantum = 4;
449     warn ("guessing format. Images will probably not be displayed correctly\n");
450   }
451   verbmsg ("X: pixmap format: %d B per pixel, %d B quantum.\n",
452     ximage_bpp, ximage_quantum);
453 
454   /*
455    *	Further configure the window
456    */
457 #if 0
458   {
459     XSetWindowAttributes wa;
460     wa.win_gravity = CenterGravity;
461     XChangeWindowAttributes (dpy, win, CWWinGravity, &wa);
462   }
463 #endif
464 
465   XStoreName (dpy, win, "Yadex");  // Temporary name -- will be overwritten
466   XSelectInput (dpy, win,
467     KeyPressMask | KeyReleaseMask
468     | ButtonPressMask | ButtonReleaseMask
469     | PointerMotionMask
470     | EnterWindowMask | LeaveWindowMask
471     | ExposureMask
472     | StructureNotifyMask);
473 
474   /*
475    *	Possibly load and query the font
476    */
477   {
478     XFontStruct *xqf;
479 
480     // Load the font or use the default font.
481     default_font = true;
482     if (font_name != NULL)
483     {
484       x_catch_on ();  // Catch errors in XLoadFont()
485       font_xfont = XLoadFont (dpy, font_name);
486       if (const char *err_msg = x_error ())
487       {
488 	warn ("can't load font \"%s\" (%s).\n", font_name, err_msg);
489 	warn ("using default font instead.\n");
490       }
491       else
492 	 default_font = false;
493       x_catch_off ();
494     }
495 
496     // Query the font we'll use for FONTW, FONTH and FONTYOFS.
497     xqf = XQueryFont (dpy,
498       default_font ? XGContextFromGC (DefaultGC (dpy, scn)) : font_xfont);
499     if (xqf->direction != FontLeftToRight)
500       warn ("this font is not left-to-right !\n");
501     if (xqf->min_byte1 != 0 || xqf->max_byte1 != 0)
502       warn ("this is not a single-byte font !\n");
503     if (xqf->min_char_or_byte2 > 32 || xqf->max_char_or_byte2 < 126)
504       warn ("this font does not support the ASCII character set !\n");
505     if (xqf->min_bounds.width != xqf->max_bounds.width)
506       warn ("this is not a fixed-width font !\n");
507     FONTW     = xqf->max_bounds.width;
508     FONTH     = xqf->ascent + xqf->descent;
509     font_xofs = xqf->min_bounds.lbearing;
510     font_yofs = xqf->max_bounds.ascent;
511     XFreeFontInfo (NULL, xqf, 1);
512     verbmsg ("X: font: metrics: %dx%d, xofs %d, yofs %d\n",
513       FONTW, FONTH, font_xofs, font_yofs);
514   }
515 
516   /*
517    *	Get/create the colormap
518    *	and allocate the colours.
519    */
520   if (win_vis_class == PseudoColor)
521   {
522     verbmsg ("X: running on PseudoColor visual, using private Colormap\n");
523     cmap = XCreateColormap (dpy, win, win_vis, AllocNone);
524   }
525   else
526     cmap = DefaultColormap (dpy, scn);
527 
528   XSetWindowColormap (dpy, win, cmap);
529   game_colour = alloc_game_colours (0);
530   app_colour = commit_app_colours ();
531   if (win_depth == 24)
532     game_colour_24.refresh (game_colour, x_server_big_endian);
533 
534   /*
535    *	Create the GC
536    */
537   {
538     XGCValues gcv;
539     unsigned long mask;
540 
541     mask = GCForeground | GCFunction | GCLineWidth;
542     if (! default_font)
543     {
544       mask |= GCFont;
545       gcv.font = font_xfont;
546     }
547     gcv.foreground = app_colour[0];  // Default colour
548     gcv.line_width = 0;
549     gcv.function   = GXcopy;
550     gc = XCreateGC (dpy, win, mask, &gcv);
551     if (gc == 0)
552       fatal_error ("XCreateGC() returned NULL");
553   }
554 
555 
556   /*
557    *	More stuff
558    */
559   XSetWindowBackground (dpy, win, app_colour[0]);
560   XMapWindow (dpy, win);
561 
562   // Unless no_pixmap is set, create the pixmap and its own pet GC.
563   if (no_pixmap)
564     drw = win;
565   else
566   {
567     XGCValues gcv;
568 
569     pixmap = XCreatePixmap (dpy, win, width, height, win_depth);
570     gcv.foreground = app_colour[0];
571     gcv.graphics_exposures = False;  // We don't want NoExpose events
572     pixmap_gc = XCreateGC (dpy, pixmap, GCForeground | GCGraphicsExposures,
573 	&gcv);
574     drw = win;
575     drw_mods = 0;  // Force display the first time
576   }
577   XSync (dpy, False);
578   GfxMode = - VideoMode;
579 #endif
580 
581   SetWindowSize (width, height);
582   return 0;
583 }
584 
585 
586 /*
587  *	TermGfx - terminate the graphics display
588  */
TermGfx()589 void TermGfx ()
590 {
591   verbmsg ("TermGfx: GfxMode=%d\n", GfxMode);
592   if (GfxMode)
593   {
594 #if defined Y_BGI
595     closegraph ();
596 #elif defined Y_X11
597     int r;
598 
599     if (! no_pixmap)
600     {
601       XFreePixmap (dpy, pixmap);
602       XFreeGC     (dpy, pixmap_gc);
603     }
604     r = XDestroyWindow (dpy, win);
605     verbmsg ("X: XDestroyWindow returned %d\n", r);
606     free_game_colours (game_colour);
607     game_colour = 0;
608     uncommit_app_colours (app_colour);
609     app_colour = 0;
610     if (cmap != DefaultColormap (dpy, scn))
611     {
612       verbmsg ("X: freeing Colormap\n");
613       XFreeColormap  (dpy, cmap);
614     }
615     if (! default_font)
616     {
617       verbmsg ("X: unloading font\n");
618       XUnloadFont (dpy, font_xfont);
619     }
620     XFreeGC (dpy, gc);
621     gc = 0;
622     // FIXME there is surely more to do...
623     XCloseDisplay (dpy);
624 #endif
625     GfxMode = 0;
626   }
627 }
628 
629 
630 /*
631  *	SetWindowSize - set the size of the edit window
632  */
SetWindowSize(int width,int height)633 void SetWindowSize (int width, int height)
634 {
635   // Am I called uselessly ?
636   if (width == ScrMaxX + 1 && height == ScrMaxY + 1)
637     return;
638 
639   ScrMaxX = width - 1;
640   ScrMaxY = height - 1;
641   ScrCenterX = ScrMaxX / 2;
642   ScrCenterY = ScrMaxY / 2;
643 #ifdef Y_X11
644   // Replace the old pixmap by another of the new size
645   if (! no_pixmap)
646   {
647     XFreePixmap (dpy, pixmap);
648     pixmap = XCreatePixmap (dpy, win, width, height, win_depth);
649     drw = pixmap;
650   }
651 #endif
652 }
653 
654 
655 /*
656  *	SwitchToVGA256 - switch from VGA 16 colours to VGA 256 colours
657  *
658  *	This function does something only in the BGI version and
659  *	if the current mode is 16 colours (typically because the
660  *	video card is a plain VGA one (as opposed to an SVGA
661  *	one) so the only 256-colour mode is 320x200).
662  *
663  *	If compiled with Y_X11, this function is a no-op.
664  */
SwitchToVGA256(void)665 void SwitchToVGA256 (void)
666 {
667 #if defined Y_X11
668   return;
669 #elif defined Y_BGI
670   static int gdriver = -1;
671   int gmode, errorcode;
672 
673   if (GfxMode > 0 && gdriver != VGA) /* if 16 colors and not failed before */
674   {
675   if (gdriver == -1)
676   {
677     gdriver = cooked_installuserdriver ("VGA256", NULL);
678     errorcode = graphresult ();
679   }
680   HideMousePointer ();
681   closegraph ();
682   gmode = 0;
683   initgraph (&gdriver, &gmode, install_dir);
684   errorcode = graphresult ();
685   if (errorcode != grOk)
686   {
687     // Failed for 256 colors - back to 16 colors
688     gdriver = VGA;
689     gmode = VGAHI;
690     initgraph (&gdriver, &gmode, install_dir);
691     errorcode = graphresult ();
692   }
693   if (errorcode != grOk)  // Shouldn't happen
694     fatal_error ("graphics error: %s", grapherrormsg (errorcode));
695   ShowMousePointer ();
696   GfxMode = -1;  // 320x200x256
697   SetDoomPalette (0);
698   ScrMaxX = getmaxx ();
699   ScrMaxY = getmaxy ();
700   ScrCenterX = ScrMaxX / 2;
701   ScrCenterY = ScrMaxY / 2;
702   }
703 #endif
704 }
705 
706 
707 /*
708  *	SwitchToVGA16 -  switch from VGA 256 colours to VGA 16 colours
709  *
710  *	See comments for SwitchToVGA256().
711  */
SwitchToVGA16(void)712 void SwitchToVGA16 (void)
713 {
714 #if defined Y_X11
715   return;
716 #elif defined Y_BGI
717   int gdriver, gmode, errorcode;
718 
719   if (GfxMode == -1)  // Switch only if we are in 320x200x256 colors
720   {
721     HideMousePointer ();
722     closegraph ();
723     gdriver = VGA;
724     gmode = VGAHI;
725     initgraph (&gdriver, &gmode, install_dir);
726     errorcode = graphresult ();
727     if (errorcode != grOk)  // Shouldn't happen
728       fatal_error ("graphics error: %s", grapherrormsg (errorcode));
729     ShowMousePointer ();
730     GfxMode = 2;  // 640x480x16
731     ScrMaxX = getmaxx ();
732     ScrMaxY = getmaxy ();
733     ScrCenterX = ScrMaxX / 2;
734     ScrCenterY = ScrMaxY / 2;
735   }
736 #else
737   ;
738 #endif
739 }
740 
741 
742 /*
743  *	ClearScreen - clear the screen
744  */
ClearScreen()745 void ClearScreen ()
746 {
747 #if defined Y_BGI
748   cleardevice ();
749 #elif defined Y_X11
750   if (no_pixmap)
751     XClearWindow (dpy, win);
752   else
753   {
754     XFillRectangle (dpy, pixmap, pixmap_gc, 0, 0, ScrMaxX + 1, ScrMaxY + 1);
755     drw = pixmap;  // Redisplaying from scratch so let's use the pixmap
756   }
757 #else
758   ;
759 #endif
760 }
761 
762 
763 /*
764  *	update_display - update the physical display
765  *
766  *	Make sure the physical bitmap display (the X window)
767  *	is up to date WRT the logical bitmap display (the X
768  *	pixmap).
769  *
770  *	If <drw> == <win>, it means that only partial
771  *	changes were made and that they were made directly on
772  *	the window, not on the pixmap so no need to copy the
773  *	pixmap onto the window.
774  */
update_display()775 void update_display ()
776 {
777 #if defined Y_BGI
778   ;  // Nothing ; with BGI, screen output is synchronous
779 #elif defined Y_X11
780   //if (drw_mods == 0)  // Nothing to do, display is already up to date
781   //   return;
782   //printf (" [");
783   //fflush (stdout);
784   if (! no_pixmap && drw == pixmap)
785   {
786     //putchar ('*');
787     XCopyArea (dpy, pixmap, win, pixmap_gc, 0, 0, ScrMaxX+1, ScrMaxY+1, 0, 0);
788   }
789   XFlush (dpy);
790   //printf ("] ");
791   //fflush (stdout);
792   drw_mods = 0;
793   drw = win;  // If they don't like it, they can call ClearScreen() [HHOS]
794 #else
795   ;
796 #endif
797 }
798 
799 
800 /*
801  *	force_window_not_pixmap - force graphic ops to use window
802  *
803  *	Redirect graphic output to window, not pixmap. Used only
804  *	in yadex.cc, before calling the sprite viewer.
805  *
806  *	FIXME this is not a clean way to do things.
807  */
force_window_not_pixmap()808 void force_window_not_pixmap ()
809 {
810   drw = win;
811 }
812 
813 
814 /*
815  *	set_pcolour - set the current drawing colour
816  *
817  *	<colour> must be an physical colour number (a.k.a. pixel value).
818  */
set_pcolour(pcolour_t colour)819 void set_pcolour (pcolour_t colour)
820 {
821   XSetForeground (dpy, gc, (xpv_t) colour);
822 }
823 
824 
825 // Last application colour set by set_colour()
826 static acolour_t current_acolour = 0;
827 #ifdef Y_BGI
828 static int current_bgicolour = 0;
829 #endif
830 
831 
832 /*
833  *	get_colour - get the current drawing colour
834  */
get_colour()835 acolour_t get_colour ()
836 {
837   return current_acolour;
838 }
839 
840 
841 /*
842  *	set_colour - set the current drawing colour
843  *
844  *	<colour> must be an application colour number.
845  */
set_colour(acolour_t colour)846 void set_colour (acolour_t colour)
847 {
848 #if defined Y_BGI
849   if (colour != current_acolour)
850   {
851     current_acolour = colour;
852     current_bgicolour = (GfxMode < 0) ? TranslateToDoomColor (colour) : colour;
853     setcolor (current_bgicolour);
854   }
855 #elif defined Y_X11
856   if (colour != current_acolour)
857   {
858     current_acolour = colour;
859     XSetForeground (dpy, gc, app_colour[colour]);
860   }
861 #endif
862 }
863 
864 
865 /*
866  *	push_colour - push a colour into the colour stack
867  *
868  *	Like set_colour() except that it will only last until
869  *	the next call to pop_colour().
870  */
push_colour(acolour_t colour)871 void push_colour (acolour_t colour)
872 {
873   if (colour_stack_pointer >= (int) (sizeof colour_stack / sizeof *colour_stack))
874   {
875     nf_bug ("Colour stack overflow");
876     return;
877   }
878   colour_stack[colour_stack_pointer] = current_acolour;
879   colour_stack_pointer++;
880   set_colour (colour);
881 }
882 
883 
884 /*
885  *	pop_colour - pop the colour stack
886  *
887  *	Cancel the effect of the last call to push_colour().
888  */
pop_colour(void)889 void pop_colour (void)
890 {
891   if (colour_stack_pointer < 1)
892   {
893     nf_bug ("Colour stack underflow");
894     return;
895   }
896   colour_stack_pointer--;
897   set_colour (colour_stack[colour_stack_pointer]);
898 }
899 
900 
901 /*
902  *	SetLineThickness - set the line style (thin or thick)
903  */
SetLineThickness(int thick)904 void SetLineThickness (int thick)
905 {
906 #if defined Y_BGI
907   setlinestyle (SOLID_LINE, 0, thick ? THICK_WIDTH : NORM_WIDTH);
908 #elif defined Y_X11
909   if (!! thick != LineThickness)
910   {
911     LineThickness = !! thick;
912     XGCValues gcv;
913     gcv.line_width = LineThickness ? 3 : (DrawingMode ? 1 : 0);
914     // ^ It's important to use a line_width of 1 when in xor mode.
915     // See note (1) in the hacker's guide.
916     XChangeGC (dpy, gc, GCLineWidth, &gcv);
917   }
918 #endif
919 }
920 
921 
922 /*
923  *	SetDrawingMode - set the drawing mode (copy or xor)
924  */
SetDrawingMode(int _xor)925 void SetDrawingMode (int _xor)
926 {
927 #if defined Y_BGI
928   setwritemode (_xor ? XOR_PUT : COPY_PUT);
929 #elif defined Y_X11
930   if (!! _xor != DrawingMode)
931   {
932     DrawingMode = !! _xor;
933     XGCValues gcv;
934     gcv.function = DrawingMode ? GXxor : GXcopy;
935     gcv.line_width = LineThickness ? 3 : (DrawingMode ? 1 : 0);
936     // ^ It's important to use a line_width of 1 when in xor mode.
937     // See note (1) in the hacker's guide.
938     XChangeGC (dpy, gc, GCFunction | GCLineWidth, &gcv);
939   }
940 #endif
941 }
942 
943 
944 /*
945  *	draw_point - draw a point at display coordinates
946  *
947  *	The point is drawn at display coordinates (<x>, <y>).
948  */
draw_point(int x,int y)949 void draw_point (int x, int y)
950 {
951 #if defined Y_BGI
952   putpixel (x, y, current_bgicolour);
953 #elif defined Y_X11
954   XDrawPoint (dpy, drw, gc, x, y);
955 #endif
956 }
957 
958 
959 /*
960  *	draw_map_point - draw a point at map coordinates
961  *
962  *	The point is drawn at map coordinates (<mapx>, <mapy>)
963  */
draw_map_point(int mapx,int mapy)964 void draw_map_point (int mapx, int mapy)
965 {
966 #if defined Y_BGI
967   putpixel (SCREENX (mapx), SCREENY (mapy), current_bgicolour);
968 #elif defined Y_X11
969   XDrawPoint (dpy, drw, gc, SCREENX (mapx), SCREENY (mapy));
970   drw_mods++;
971 #endif
972 }
973 
974 
975 /*
976  *	DrawMapLine - draw a line on the screen from map coords
977  */
DrawMapLine(int mapx1,int mapy1,int mapx2,int mapy2)978 void DrawMapLine (int mapx1, int mapy1, int mapx2, int mapy2)
979 {
980 #if defined Y_BGI
981   line (SCREENX (mapx1), SCREENY (mapy1), SCREENX (mapx2), SCREENY (mapy2));
982 #elif defined Y_X11
983   XDrawLine (dpy, drw, gc, SCREENX (mapx1), SCREENY (mapy1),
984 			   SCREENX (mapx2), SCREENY (mapy2));
985   drw_mods++;
986 #endif
987 }
988 
989 
990 /*
991  *	DrawMapCircle - draw a circle on the screen from map coords
992  */
DrawMapCircle(int mapx,int mapy,int mapradius)993 void DrawMapCircle (int mapx, int mapy, int mapradius)
994 {
995 #if defined Y_BGI
996   circle (SCREENX (mapx), SCREENY (mapy), (int) (mapradius * Scale));
997 #elif defined Y_X11
998   XDrawArc (dpy, drw, gc, SCREENX (mapx - mapradius), SCREENY (mapy + mapradius),
999     (unsigned int) (2 * mapradius * Scale),
1000     (unsigned int) (2 * mapradius * Scale), 0, 360*64);
1001   drw_mods++;
1002 #endif
1003 }
1004 
1005 
1006 
1007 /*
1008  *	DrawMapVector - draw an arrow on the screen from map coords
1009  */
DrawMapVector(int mapx1,int mapy1,int mapx2,int mapy2)1010 void DrawMapVector (int mapx1, int mapy1, int mapx2, int mapy2)
1011 {
1012   int    scrx1   = SCREENX (mapx1);
1013   int    scry1   = SCREENY (mapy1);
1014   int    scrx2   = SCREENX (mapx2);
1015   int    scry2   = SCREENY (mapy2);
1016   double r       = hypot ((double) (scrx1 - scrx2), (double) (scry1 - scry2));
1017 #if 0
1018   /* AYM 19980216 to avoid getting huge arrowheads when zooming in */
1019   int    scrXoff = (r >= 1.0) ? (int) ((scrx1 - scrx2) * 8.0 / r * (Scale < 1 ? Scale : 1)) : 0;
1020   int    scrYoff = (r >= 1.0) ? (int) ((scry1 - scry2) * 8.0 / r * (Scale < 1 ? Scale : 1)) : 0;
1021 #else
1022   int    scrXoff = (r >= 1.0) ? (int) ((scrx1 - scrx2) * 8.0 / r * (Scale / 2)) : 0;
1023   int    scrYoff = (r >= 1.0) ? (int) ((scry1 - scry2) * 8.0 / r * (Scale / 2)) : 0;
1024 #endif
1025 
1026 #if defined Y_BGI
1027   line (scrx1, scry1, scrx2, scry2);
1028   scrx1 = scrx2 + 2 * scrXoff;
1029   scry1 = scry2 + 2 * scrYoff;
1030   line (scrx1 - scrYoff, scry1 + scrXoff, scrx2, scry2);
1031   line (scrx1 + scrYoff, scry1 - scrXoff, scrx2, scry2);
1032 #elif defined Y_X11
1033   XDrawLine (dpy, drw, gc, scrx1, scry1, scrx2, scry2);
1034   scrx1 = scrx2 + 2 * scrXoff;
1035   scry1 = scry2 + 2 * scrYoff;
1036   XDrawLine (dpy, drw, gc, scrx1 - scrYoff, scry1 + scrXoff, scrx2, scry2);
1037   XDrawLine (dpy, drw, gc, scrx1 + scrYoff, scry1 - scrXoff, scrx2, scry2);
1038   drw_mods++;
1039 #endif
1040 }
1041 
1042 
1043 /*
1044  *	DrawMapArrow - draw an arrow on the screen from map coords and angle (0 - 65535)
1045  */
DrawMapArrow(int mapx1,int mapy1,unsigned angle)1046 void DrawMapArrow (int mapx1, int mapy1, unsigned angle)
1047 {
1048   int    mapx2   = mapx1 + (int) (50 * cos (angle / 10430.37835));
1049   int    mapy2   = mapy1 + (int) (50 * sin (angle / 10430.37835));
1050   int    scrx1   = SCREENX (mapx1);
1051   int    scry1   = SCREENY (mapy1);
1052   int    scrx2   = SCREENX (mapx2);
1053   int    scry2   = SCREENY (mapy2);
1054   double r       = hypot (scrx1 - scrx2, scry1 - scry2);
1055 #if 0
1056   int    scrXoff = (r >= 1.0) ? (int) ((scrx1 - scrx2) * 8.0 / r * (Scale < 1 ? Scale : 1)) : 0;
1057   int    scrYoff = (r >= 1.0) ? (int) ((scry1 - scry2) * 8.0 / r * (Scale < 1 ? Scale : 1)) : 0;
1058 #else
1059   int    scrXoff = (r >= 1.0) ? (int) ((scrx1 - scrx2) * 8.0 / r * (Scale / 2)) : 0;
1060   int    scrYoff = (r >= 1.0) ? (int) ((scry1 - scry2) * 8.0 / r * (Scale / 2)) : 0;
1061 #endif
1062 
1063 #if defined Y_BGI
1064   line (scrx1, scry1, scrx2, scry2);
1065   scrx1 = scrx2 + 2 * scrXoff;
1066   scry1 = scry2 + 2 * scrYoff;
1067   line (scrx1 - scrYoff, scry1 + scrXoff, scrx2, scry2);
1068   line (scrx1 + scrYoff, scry1 - scrXoff, scrx2, scry2);
1069 #elif defined Y_X11
1070   XDrawLine (dpy, drw, gc, scrx1, scry1, scrx2, scry2);
1071   scrx1 = scrx2 + 2 * scrXoff;
1072   scry1 = scry2 + 2 * scrYoff;
1073   XDrawLine (dpy, drw, gc, scrx1 - scrYoff, scry1 + scrXoff, scrx2, scry2);
1074   XDrawLine (dpy, drw, gc, scrx1 + scrYoff, scry1 - scrXoff, scrx2, scry2);
1075   drw_mods++;
1076 #endif
1077 }
1078 
1079 
1080 /*
1081  *	DrawScreenLine - draw a line on the screen from screen coords
1082  */
DrawScreenLine(int Xstart,int Ystart,int Xend,int Yend)1083 void DrawScreenLine (int Xstart, int Ystart, int Xend, int Yend)
1084 {
1085 #if defined Y_BGI
1086   line (Xstart, Ystart, Xend, Yend);
1087 #elif defined Y_X11
1088   XDrawLine (dpy, drw, gc, Xstart, Ystart, Xend, Yend);
1089   drw_mods++;
1090 #endif
1091 }
1092 
1093 
1094 /*
1095  *	DrawScreenLineLen - draw a line on the screen
1096  */
DrawScreenLineLen(int x,int y,int width,int height)1097 void DrawScreenLineLen (int x, int y, int width, int height)
1098 {
1099 #if defined Y_BGI
1100   line (x, y, x + width - 1, y + height - 1);
1101 #elif defined Y_X11
1102   if (width > 0)
1103     width--;
1104   else if (width < 0)
1105     width++;
1106   if (height > 0)
1107     height--;
1108   else if (height < 0)
1109     height++;
1110   XDrawLine (dpy, drw, gc, x, y, x + width, y + height);
1111   drw_mods++;
1112 #endif
1113 }
1114 
1115 
1116 /*
1117  *	DrawScreenRect - draw a rectangle
1118  *
1119  *	Unlike most functions here, the 3rd and 4th parameters
1120  *	specify lengths, not coordinates.
1121  */
DrawScreenRect(int x,int y,int width,int height)1122 void DrawScreenRect (int x, int y, int width, int height)
1123 {
1124 #if defined Y_BGI
1125   rectangle (x, y, x + width - 1, y + height - 1);
1126 #elif defined Y_X11
1127   XDrawRectangle (dpy, drw, gc, x, y, width - 1, height - 1);
1128   drw_mods++;
1129 #endif
1130 }
1131 
1132 
1133 /*
1134  *	DrawScreenBox - draw a filled in box on the screen from screen coords
1135  *
1136  *	(scrx1, scry1) is the top left corner
1137  *	(scrx2, scry2) is the bottom right corner
1138  *	If scrx2 < scrx1 or scry2 < scry1, the function does nothing.
1139  */
DrawScreenBox(int scrx1,int scry1,int scrx2,int scry2)1140 void DrawScreenBox (int scrx1, int scry1, int scrx2, int scry2)
1141 {
1142   if (scrx2 < scrx1 || scry2 < scry1)
1143     return;
1144 #if defined Y_BGI
1145   setfillstyle (1, getcolor ());
1146   bar (scrx1, scry1, scrx2, scry2);
1147 #elif defined Y_X11
1148   // FIXME missing gc fill_style
1149   XFillRectangle (dpy, drw, gc, scrx1, scry1,
1150     scrx2 - scrx1 + 1, scry2 - scry1 + 1);
1151   drw_mods++;
1152 #endif
1153 }
1154 
1155 
1156 /*
1157  *	DrawScreenBoxwh - draw a filled rectangle of width x height pixels
1158  *
1159  *	(scrx0, scry0) is the top left corner
1160  *	(width, height) is the obvious
1161  *	If width < 1 or height < 1, does nothing.
1162  */
DrawScreenBoxwh(int scrx0,int scry0,int width,int height)1163 void DrawScreenBoxwh (int scrx0, int scry0, int width, int height)
1164 {
1165   if (width < 1 || height < 1)
1166     return;
1167 #if defined Y_BGI
1168   setfillstyle (1, getcolor ());
1169   bar (scrx0, scry0, scrx0 + width - 1, scry0 + height - 1);
1170 #elif defined Y_X11
1171   // FIXME missing gc fill_style
1172   XFillRectangle (dpy, drw, gc, scrx0, scry0, width, height);
1173   drw_mods++;
1174 #endif
1175 }
1176 
1177 
1178 /*
1179  *	DrawScreenBox3D - draw a filled-in 3D box on the screen
1180  *
1181  *	The 3D border is rather wide (BOX_BORDER pixels wide).
1182  */
DrawScreenBox3D(int scrx1,int scry1,int scrx2,int scry2)1183 void DrawScreenBox3D (int scrx1, int scry1, int scrx2, int scry2)
1184 {
1185   DrawScreenBox3DShallow (scrx1, scry1, scrx2, scry2);
1186   push_colour (WINBG_DARK);
1187 #if defined Y_BGI
1188   line (scrx1 + 1, scry2 - 1, scrx2 - 1, scry2 - 1);
1189   line (scrx2 - 1, scry1 + 1, scrx2 - 1, scry2 - 1);
1190 #elif defined Y_X11
1191   XDrawLine (dpy, drw, gc, scrx1 + 1, scry2 - 1, scrx2 - 1, scry2 - 1);
1192   XDrawLine (dpy, drw, gc, scrx2 - 1, scry1 + 1, scrx2 - 1, scry2 - 1);
1193 #endif
1194   set_colour (WINBG_LIGHT);
1195 #if defined Y_BGI
1196   line (scrx1 + 1, scry1 + 1, scrx1 + 1, scry2 - 1);
1197   line (scrx1 + 1, scry1 + 1, scrx2 - 1, scry1 + 1);
1198 #elif defined Y_X11
1199   XDrawLine (dpy, drw, gc, scrx1 + 1, scry1 + 1, scrx1 + 1, scry2 - 1);
1200   XDrawLine (dpy, drw, gc, scrx1 + 1, scry1 + 1, scrx2 - 1, scry1 + 1);
1201   drw_mods++;
1202 #endif
1203   pop_colour ();
1204 }
1205 
1206 
1207 /*
1208  *	DrawScreenBox3DShallow - draw a filled-in 3D box on the screen
1209  *
1210  *	Same thing as DrawScreenBox3D but shallow (the 3D border
1211  *	is NARROW_BORDER pixels wide).
1212  */
DrawScreenBox3DShallow(int scrx1,int scry1,int scrx2,int scry2)1213 void DrawScreenBox3DShallow (int scrx1, int scry1, int scrx2, int scry2)
1214 {
1215 #if defined Y_BGI
1216   setfillstyle (1, TranslateToDoomColor (LIGHTGREY));
1217   bar (scrx1 + 1, scry1 + 1, scrx2 - 1, scry2 - 1);
1218   push_colour (WINBG_DARK);
1219   line (scrx1, scry2, scrx2, scry2);
1220   line (scrx2, scry1, scrx2, scry2);
1221   set_colour (WINBG_LIGHT);
1222   line (scrx1, scry1, scrx2, scry1);
1223   line (scrx1, scry1, scrx1, scry2);
1224   pop_colour ();
1225 
1226 #elif defined Y_X11
1227   push_colour (WINBG);
1228   XFillRectangle (dpy, drw, gc, scrx1+1, scry1+1, scrx2-scrx1, scry2-scry1);
1229   set_colour (WINBG_DARK);
1230   XDrawLine (dpy, drw, gc, scrx1, scry2, scrx2, scry2);
1231   XDrawLine (dpy, drw, gc, scrx2, scry1, scrx2, scry2);
1232   set_colour (WINBG_LIGHT);
1233   XDrawLine (dpy, drw, gc, scrx1, scry1, scrx2, scry1);
1234   XDrawLine (dpy, drw, gc, scrx1, scry1, scrx1, scry2);
1235   drw_mods++;
1236   pop_colour ();
1237 #endif
1238 }
1239 
1240 
1241 /*
1242  *	draw_box_border - draw the 3D border of a box.
1243  *
1244  *	(x, y) is the outer top left corner.
1245  *	(width, height) are the outer dimensions.
1246  *	(thickness) is the thickness of the border in pixels.
1247  *	(raised) is zero for depressed, non-zero for raised.
1248  */
draw_box_border(int x,int y,int width,int height,int thickness,int raised)1249 void draw_box_border (int x, int y, int width, int height,
1250   int thickness, int raised)
1251 {
1252 #if defined Y_BGI
1253 #error "You need to write the BGI version of draw_box_border()"
1254 #elif defined Y_X11
1255   int n;
1256   XPoint points[3];
1257 
1258   // We want offsets, not distances
1259   width--;
1260   height--;
1261 
1262   // Draw the right and bottom edges
1263   push_colour (raised ? WINBG_DARK : WINBG_LIGHT);
1264   points[0].x = x + width;
1265   points[0].y = y;
1266   points[1].x = 0;
1267   points[1].y = height;
1268   points[2].x = -width;
1269   points[2].y = 0;
1270   for (n = 0; n < thickness; n++)
1271   {
1272     XDrawLines (dpy, drw, gc, points, 3, CoordModePrevious);
1273     points[0].x--;
1274     points[0].y++;
1275     points[1].y--;
1276     points[2].x++;
1277   }
1278 
1279   // Draw the left and top edges
1280   set_colour (raised ? WINBG_LIGHT : WINBG_DARK);
1281   points[0].x = x;
1282   points[0].y = y + height;
1283   points[1].x = 0;
1284   points[1].y = -height;
1285   points[2].x = width;
1286   points[2].y = 0;
1287   for (n = 0; n < thickness; n++)
1288   {
1289     XDrawLines (dpy, drw, gc, points, 3, CoordModePrevious);
1290     points[0].x++;
1291     points[0].y--;
1292     points[1].y++;
1293     points[2].x--;
1294   }
1295 
1296   pop_colour ();
1297 #endif
1298 }
1299 
1300 
1301 /*
1302  *	DrawScreenBoxHollow - draw a hollow 3D box on the screen
1303  *
1304  *	The 3D border is HOLLOW_BORDER pixels wide.
1305  */
DrawScreenBoxHollow(int scrx1,int scry1,int scrx2,int scry2,acolour_t colour)1306 void DrawScreenBoxHollow (int scrx1, int scry1, int scrx2, int scry2, acolour_t colour)
1307 {
1308 #if defined Y_BGI
1309   setfillstyle (1, TranslateToDoomColor (colour));
1310   bar (scrx1 + HOLLOW_BORDER, scry1 + HOLLOW_BORDER,
1311        scrx2 - HOLLOW_BORDER, scry2 - HOLLOW_BORDER);
1312   push_colour (WINBG_LIGHT);
1313   line (scrx1, scry2, scrx2, scry2);
1314   line (scrx2, scry1, scrx2, scry2);
1315   set_colour (WINBG_DARK);
1316   line (scrx1, scry1, scrx2, scry1);
1317   line (scrx1, scry1, scrx1, scry2);
1318   pop_colour ();
1319 
1320 #elif defined Y_X11
1321   push_colour (colour);
1322   XFillRectangle (dpy, drw, gc,
1323       scrx1 + HOLLOW_BORDER, scry1 + HOLLOW_BORDER,
1324       scrx2 + 1 - scrx1 - 2 * HOLLOW_BORDER, scry2 + 1 - scry1 - 2 * HOLLOW_BORDER);
1325   set_colour (WINBG_LIGHT);
1326   XDrawLine (dpy, drw, gc, scrx1, scry2, scrx2, scry2);
1327   XDrawLine (dpy, drw, gc, scrx2, scry1, scrx2, scry2);
1328   set_colour (WINBG_DARK);
1329   XDrawLine (dpy, drw, gc, scrx1, scry1, scrx2, scry1);
1330   XDrawLine (dpy, drw, gc, scrx1, scry1, scrx1, scry2);
1331   drw_mods++;
1332   pop_colour ();
1333 #endif
1334 }
1335 
1336 
1337 /*
1338  *	DrawScreenMeter - draw a meter bar on the screen
1339  *
1340  *	In a hollow box; max. value = 1.0
1341  */
DrawScreenMeter(int scrx1,int scry1,int scrx2,int scry2,float value)1342 void DrawScreenMeter (int scrx1, int scry1, int scrx2, int scry2, float value)
1343 {
1344 #if defined Y_BGI
1345   if (value < 0.0)
1346     value = 0.0;
1347   if (value > 1.0)
1348     value = 1.0;
1349   setfillstyle (1, TranslateToDoomColor (BLACK));
1350   bar (scrx1 + 1 + (int) ((scrx2 - scrx1 - 2) * value), scry1 + 1, scrx2 - 1, scry2 - 1);
1351   setfillstyle (1, TranslateToDoomColor (LIGHTGREEN));
1352   bar (scrx1 + 1, scry1 + 1, scrx1 + 1 + (int) ((scrx2 - scrx1 - 2) * value), scry2 - 1);
1353 #elif defined Y_X11
1354   printf ("DrawScreenMeter()\n");  // FIXME
1355 #endif
1356 }
1357 
1358 
1359 // Shared by DrawScreenText() and DrawScreenString()
1360 
1361 /* Coordinates of first character of last string drawn with
1362    DrawScreenText() or DrawScreenString(). */
1363 static int lastx0;
1364 static int lasty0;
1365 
1366 // Where the last DrawScreen{Text,String}() left the "cursor".
1367 static int lastxcur;
1368 static int lastycur;
1369 
1370 
1371 /*
1372  *	DrawScreenText - format and display a string
1373  *
1374  *	Write text to the screen in printf() fashion.
1375  *	The top left corner of the first character is at (<scrx>, <scry>)
1376  *	If <scrx> == -1, the text is printed at the same abscissa
1377  *	as the last text printed with this function.
1378  *	If <scry> == -1, the text is printed one line (FONTH pixels)
1379  *	below the last text printed with this function.
1380  *	If <msg> == NULL, no text is printed. Useful to set the
1381  *	coordinates for the next time.
1382  */
DrawScreenText(int scrx,int scry,const char * msg,...)1383 void DrawScreenText (int scrx, int scry, const char *msg, ...)
1384 {
1385   char temp[120];
1386   va_list args;
1387 
1388   // <msg> == NULL: print nothing, just set the coordinates.
1389   if (msg == NULL)
1390   {
1391     if (scrx != -1 && scrx != -2)
1392     {
1393       lastx0   = scrx;
1394       lastxcur = scrx;
1395     }
1396     if (scry != -1 && scry != -2)
1397     {
1398       lasty0   = scry;  // Note: no "+ FONTH"
1399       lastycur = scry;
1400     }
1401     return;
1402   }
1403 
1404   va_start (args, msg);
1405   y_vsnprintf (temp, sizeof temp, msg, args);
1406   DrawScreenString (scrx, scry, temp);
1407 }
1408 
1409 
1410 /*
1411  *	DrawScreenString - display a string
1412  *
1413  *	Same thing as DrawScreenText() except that the string is
1414  *	printed verbatim (no formatting or conversion).
1415  *
1416  *	A "\1" in the string is not displayed but causes
1417  *	subsequent characters to be displayed in WINLABEL (or
1418  *	WINLABEL_DIM if the current colour before the function
1419  *	was called was WINFG_DIM).
1420  *
1421  *	A "\2" in the string is not displayed but causes
1422  *	subsequent characters to be displayed in the same colour
1423  *	that was active before the function was called.
1424  *
1425  *	The string can contain any number of "\1" and "\2".
1426  *	Regardless, upon return from the function, the current
1427  *	colour is restored to what it was before the function
1428  *	was called.
1429  *
1430  *	This colour switching business was hacked in a hurry.
1431  *	Feel free to improve it.
1432  */
DrawScreenString(int scrx,int scry,const char * str)1433 void DrawScreenString (int scrx, int scry, const char *str)
1434 {
1435   int x; int y;
1436 
1437   /* FIXME originally, the test was "< 0". Because it broke
1438      when the screen was too small, I changed it to a more
1439      specific "== -1". A quick and very dirty hack ! */
1440   if (scrx == -1)
1441     x = lastx0;
1442   else if (scrx == -2)
1443     x = lastxcur;
1444   else
1445     x = scrx;
1446   if (scry == -1)
1447     y = lasty0;
1448   else if (scry == -2)
1449     y = lastycur;
1450   else
1451     y = scry;
1452   size_t len = strlen (str);
1453 #if defined Y_BGI
1454   outtextxy (x, y, str);
1455   // FIXME implement colour changes (\1, \2)
1456 #elif defined Y_X11
1457   if (strchr (str, '\1') == 0)
1458   {
1459     XDrawString (dpy, drw, gc, x - font_xofs, y + font_yofs, str, len);
1460   }
1461   else
1462   {
1463     acolour_t save = get_colour ();
1464     int xx = x;
1465     len = 0;
1466     for (const char *p = str; *p != '\0';)
1467     {
1468       int i;
1469       for (i = 0; p[i] != '\0' && p[i] != '\1' && p[i] != '\2'; i++)
1470 	;
1471       len += i;
1472       if (i > 0)
1473       {
1474 	XDrawString (dpy, drw, gc, xx - font_xofs, y + font_yofs, p, i);
1475 	xx += i * FONTW;
1476       }
1477       if (p[i] == '\0')
1478 	break;
1479       if (p[i] == '\1')
1480 	set_colour (save == WINFG_DIM ? WINLABEL_DIM : WINLABEL);
1481       else if (p[i] == '\2')
1482 	set_colour (save);
1483       i++;
1484       p += i;
1485     }
1486     set_colour (save);
1487   }
1488   if (text_dot)
1489     XDrawPoint (dpy, drw, gc, x, y);
1490   drw_mods++;
1491 #endif
1492 
1493   lastxcur = x + FONTW * len;
1494   lastycur = y;
1495   if (scrx != -2)
1496     lastx0 = x;
1497   if (scry != -2)
1498     lasty0 = y + FONTH;
1499 }
1500 
1501 
1502 /*
1503  *	DrawScreenChar - display a character
1504  *
1505  *	Same thing as DrawScreenText() except that the string is
1506  *	printed verbatim (no formatting or conversion).
1507  */
DrawScreenChar(int x,int y,char c)1508 void DrawScreenChar (int x, int y, char c)
1509 {
1510 #if defined Y_BGI
1511   char buf[2];
1512   buf[0] = c;
1513   buf[1] = '\0';
1514   outtextxy (x, y, buf);
1515 #elif defined Y_X11
1516   XDrawString (dpy, drw, gc, x - font_xofs, y + font_yofs, &c, 1);
1517   if (text_dot)
1518     XDrawPoint (dpy, drw, gc, x, y);
1519   drw_mods++;
1520 #endif
1521 }
1522 
1523 
1524 /*
1525  *	DrawPointer  - draw (or erase) the pointer if we aren't using the mouse
1526  */
DrawPointer(bool rulers)1527 void DrawPointer (bool rulers)
1528 {
1529 #ifdef Y_BGI
1530   int r;
1531 
1532   // Use XOR mode : drawing the pointer twice erases it
1533   SetDrawingMode (1);
1534   // Draw the pointer
1535   if (rulers)
1536   {
1537     set_colour (MAGENTA);
1538     r = (int) (512 * Scale);
1539     circle (is.x, is.y, r);
1540     r >>= 1;
1541     circle (is.x, is.y, r);
1542     r >>= 1;
1543     circle (is.x, is.y, r);
1544     r >>= 1;
1545     circle (is.x, is.y, r);
1546     r = (int) (1024 * Scale);
1547     line (is.x - r, is.y, is.x + r, is.y);
1548     line (is.x, is.y - r, is.x, is.y + r);
1549   }
1550   else
1551   {
1552     set_colour (YELLOW);
1553     line (is.x - 15, is.y - 13, is.x + 15, is.y + 13);
1554     line (is.x - 15, is.y + 13, is.x + 15, is.y - 13);
1555   }
1556   // Restore normal write mode
1557   SetDrawingMode (0);
1558 #else
1559   ;
1560 #endif
1561 }
1562 
1563 
1564 #ifdef Y_BGI
1565 /*
1566  *	TranslateToDoomColor - translate a standard color to Doom palette 0 (approx.)
1567  */
TranslateToDoomColor(int colour)1568 int TranslateToDoomColor (int colour)
1569 {
1570   if (GfxMode < 0)
1571     switch (colour)
1572     {
1573       case BLACK:
1574 	return 0;
1575       case BLUE:
1576 	return 202;
1577       case GREEN:
1578 	return 118;
1579       case CYAN:
1580 	return 194;
1581       case RED:
1582 	return 183;
1583       case MAGENTA:
1584 	return 253;
1585       case BROWN:
1586 	return 144;
1587       case LIGHTGREY:
1588 	return 88;
1589       case DARKGREY:
1590 	return 96;
1591       case LIGHTBLUE:
1592 	return 197;
1593       case LIGHTGREEN:
1594 	return 112;
1595       case LIGHTCYAN:
1596 	return 193;
1597       case LIGHTRED:
1598 	return 176;
1599       case LIGHTMAGENTA:
1600 	return 250;
1601       case YELLOW:
1602 	return 231;
1603       case WHITE:
1604 	return 4;
1605     }
1606   return colour;
1607 }
1608 #endif
1609 
1610 
1611 #if defined Y_BGI && defined CIRRUS_PATCH
1612 /*
1613  *	Cirrus Logic Hardware Mouse Cursor Stuff
1614  */
1615 
1616 #define CRTC 0x3D4
1617 #define ATTR 0x3C0
1618 #define SEQ  0x3C4
1619 #define GRC  0x3CE
1620 #define LOBYTE(w)  ((unsigned char)(w))
1621 #define HIBYTE(w)  ((unsigned char)((unsigned int)(w) >> 8))
1622 
1623 
rdinx(unsigned pt,unsigned inx)1624 unsigned rdinx (unsigned pt, unsigned inx)
1625 {
1626   if (pt == ATTR)
1627     inportb (CRTC + 6);
1628   outportb (pt, inx);
1629   return inportb (pt + 1);
1630 }
1631 
1632 
wrinx(int pt,unsigned inx,unsigned val)1633 void wrinx (int pt, unsigned inx, unsigned val)
1634 {
1635   if (pt == ATTR)
1636   {
1637     inportb (CRTC + 6);
1638     outportb (pt, inx);
1639     outportb (pt, val);
1640   }
1641   else
1642   {
1643     outportb (pt, inx);
1644     outportb (pt + 1, val);
1645   }
1646 }
1647 
1648 
modinx(unsigned pt,unsigned inx,unsigned mask,unsigned nwv)1649 void modinx (unsigned pt, unsigned inx, unsigned mask, unsigned nwv)
1650 {
1651   unsigned temp;
1652 
1653   temp = (rdinx (pt, inx) & ~mask) + (nwv & mask);
1654   wrinx (pt, inx, temp);
1655 }
1656 
1657 
clrinx(unsigned pt,unsigned inx,unsigned val)1658 void clrinx (unsigned pt, unsigned inx, unsigned val)
1659 {
1660   unsigned x;
1661 
1662   x = rdinx (pt, inx);
1663   wrinx (pt, inx, x & ~val);
1664 }
1665 
1666 
SetHWCursorPos(unsigned x,unsigned y)1667 void SetHWCursorPos (unsigned x, unsigned y)
1668 {
1669   outport (SEQ, (x << 5) | 0x10);
1670   outport (SEQ, (y << 5) | 0x11);
1671 }
1672 
1673 
SetHWCursorCol(long fgcol,long bgcol)1674 void SetHWCursorCol (long fgcol, long bgcol)
1675 {
1676   modinx (SEQ, 0x12, 3, 2);
1677   outportb (0x3C8, 0xFF);
1678   outportb (0x3C9, LOBYTE (fgcol) >> 2);
1679   outportb (0x3C9, HIBYTE (bgcol) >> 2);
1680   outportb (0x3C8, 0);
1681   outportb (0x3C9, LOBYTE (bgcol) >> 2);
1682   outportb (0x3C9, HIBYTE (bgcol) >> 2);
1683   outportb (0x3C9, bgcol >> 18);
1684   modinx (SEQ, 0x12, 3, 1);
1685 }
1686 
1687 
CopyHWCursorMap(unsigned bytes)1688 void CopyHWCursorMap (unsigned bytes)
1689 {
1690   char    *curmapptr = 0xA000FF00L;
1691   unsigned lbank = (1024 / 64) - 1;
1692 
1693   if ((rdinx (GRC, 0x0B) & 32)==0)
1694     lbank = lbank << 2;
1695   wrinx (GRC, 9, lbank << 2);
1696   memmove (curmapptr, &mp, bytes);
1697 }
1698 
1699 
SetHWCursorMap(char * map)1700 void SetHWCursorMap (char *map)
1701 {
1702   memmove (&mp, map, 128);
1703   memmove (&mp + 128, &mp, 128);
1704   CopyHWCursorMap (256);
1705   SetHWCursorCol (0xFF00000L, 0xFF);
1706   wrinx (SEQ, 0x13, 0x3F);
1707 }
1708 
1709 #endif  /* Y_BGI && CIRRUS_PATCH */
1710 
1711 
1712 #ifdef Y_DOS
cooked_installuserdriver(const char far * __name,int huge (* detect)(void))1713 static int cooked_installuserdriver (const char far *__name,
1714                                     int huge (*detect)(void))
1715 {
1716   char savecwd[PATH_MAX+1];
1717   int gdriver;
1718 
1719   getcwd (savecwd, PATH_MAX);
1720   if (al_fchdir (install_dir))
1721     fatal_error ("installuserdriver: chdir1 error (%s)", strerror (errno));
1722   gdriver = installuserdriver (__name, detect);
1723   if (al_fchdir (savecwd))
1724     fatal_error ("installuserdriver: chdir2 error (%s)", strerror (errno));
1725   return gdriver;
1726 }
1727 #endif
1728 
1729