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