1 /*
2 * FIG : Facility for Interactive Generation of figures
3 * Copyright (c) 1985-1988 by Supoj Sutanthavibul
4 * Parts Copyright (c) 1989-2015 by Brian V. Smith
5 * Parts Copyright (c) 1991 by Paul King
6 * Parts Copyright (c) 2016-2020 by Thomas Loimer
7 *
8 * Any party obtaining a copy of these files is granted, free of charge, a
9 * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
10 * nonexclusive right and license to deal in this software and documentation
11 * files (the "Software"), including without limitation the rights to use,
12 * copy, modify, merge, publish, distribute, sublicense and/or sell copies of
13 * the Software, and to permit persons who receive copies from any such
14 * party to do so, with the only requirement being that the above copyright
15 * and this permission notice remain intact.
16 *
17 */
18
19 /*
20 * This file provides some drawing primitives which make use of the
21 * underlying low-level windowing system operations.
22 *
23 * The file is divided into routines for:
24 *
25 * GRAPHICS CONTEXTS (which are used by all the following)
26 * FONTS
27 * LINES
28 * SHADING
29 */
30
31 /* IMPORTS */
32
33 #include "fig.h"
34 #include "figx.h"
35 #include "resources.h"
36 #include "paintop.h"
37 #include "mode.h"
38 #include "object.h"
39 #include "u_create.h"
40 #include "u_fonts.h"
41 #include "w_canvas.h"
42 #include "w_drawprim.h"
43 #include "w_indpanel.h"
44 #include "w_layers.h"
45 #include "w_msgpanel.h"
46 #include "w_setup.h"
47 #include "w_util.h"
48
49 #include "u_create.h"
50 #include "w_cursor.h"
51 #include "w_file.h"
52 #include "w_rottext.h"
53
54 /* EXPORTS */
55
56 XFontStruct *bold_font;
57 XFontStruct *roman_font;
58 XFontStruct *button_font;
59 XFontStruct *canvas_font;
60
61 /* LOCAL */
62
63 static void clip_line(int x1, int y1, int x2, int y2, short *x3, short *y3, short *x4, short *y4);
64 static int clip_poly(XPoint *inVertices, int npoints, XPoint *outVertices);
65 static void intersect(XPoint first, XPoint second, int x1, int y1, int x2, int y2, XPoint *intersectPt);
66 static Boolean inside (XPoint testVertex, int x1, int y1, int x2, int y2);
67 static void setup_next(int npoints, XPoint *in, XPoint *out);
68 static Pixel gc_color[NUMOPS], gc_background[NUMOPS];
69 static XRectangle clip[1];
70 static int parsesize(char *name);
71 static Boolean openwinfonts;
72 static Boolean font_scalable[NUM_FONTS];
73
74 #define MAXNAMES 300
75
76 static struct {
77 char *fn;
78 int s;
79 } flist[MAXNAMES];
80
81
82 void rescale_pattern (int patnum);
83 void zXFillPolygon (Display *d, Window w, GC gc, zXPoint *points, int n, int complex, int coordmode);
84 void zXDrawLines (Display *d, Window w, GC gc, zXPoint *points, int n, int coordmode);
85 void scale_pattern (int indx);
86 int SutherlandHodgmanPolygoClip (XPoint *inVertices, XPoint *outVertices, int inLength, int x1, int y1, int x2, int y2);
87
init_font(void)88 void init_font(void)
89 {
90 struct xfont *newfont, *nf;
91 int f, count, i, p, ss;
92 char template[300];
93 char backup_template[300];
94 char **fontlist, **fname;
95
96 if (appres.boldFont == NULL || *appres.boldFont == '\0')
97 appres.boldFont = BOLD_FONT;
98 if (appres.normalFont == NULL || *appres.normalFont == '\0')
99 appres.normalFont = NORMAL_FONT;
100 if (appres.buttonFont == NULL || *appres.buttonFont == '\0')
101 appres.buttonFont = BUTTON_FONT;
102
103 while ((roman_font = XLoadQueryFont(tool_d, appres.normalFont)) == 0) {
104 if (strcmp(appres.normalFont,"fixed") == 0) {
105 fprintf(stderr, "Can't load 'fixed' font, something is wrong");
106 fprintf(stderr," with your server - quitting.\n");
107 exit(1);
108 }
109 file_msg("Can't load font: %s, using 'fixed'\n", appres.normalFont);
110 appres.normalFont = "fixed";
111 } /* now loop to load "fixed" */
112 hidden_text_length = 4 * roman_font->max_bounds.width;
113 if ((bold_font = XLoadQueryFont(tool_d, appres.boldFont)) == 0) {
114 file_msg("Can't load font: %s, using %s\n",
115 appres.boldFont, appres.normalFont);
116 bold_font = XLoadQueryFont(tool_d, appres.normalFont);
117 }
118 if ((button_font = XLoadQueryFont(tool_d, appres.buttonFont)) == 0) {
119 file_msg("Can't load font: %s, using %s\n",
120 appres.buttonFont, appres.normalFont);
121 button_font = XLoadQueryFont(tool_d, appres.normalFont);
122 }
123 /*
124 * Now initialize the font structure for the X fonts corresponding to the
125 * Postscript fonts for the canvas. OpenWindows can use any LaserWriter
126 * fonts at any size, so we don't need to load anything if we are using
127 * it.
128 */
129
130 /* if the user hasn't disallowed scalable fonts, check that the
131 server really has them by checking for font of 0-0 size */
132 openwinfonts = False;
133 if (appres.scalablefonts) {
134 /* first look for OpenWindow style font names (e.g. times-roman) */
135 if ((fontlist = XListFonts(tool_d, ps_fontinfo[1].name, 1, &count))!=0) {
136 openwinfonts = True; /* yes, use them */
137 for (f=0; f<NUM_FONTS; f++) { /* copy the OpenWindow font names */
138 x_fontinfo[f].template = ps_fontinfo[f+1].name;
139 font_scalable[f] = True;
140 }
141 XFreeFontNames(fontlist);
142 } else {
143 for (f = 0; f < NUM_FONTS; f++) {
144 strcpy(template,x_fontinfo[f].template); /* nope, check for font size 0 */
145 strcat(template,"0-0-*-*-*-*-");
146 /* add ISO8859 (if not Symbol font or ZapfDingbats) to font name in non-international mode*/
147 if (
148 #ifdef I18N
149 !appres.international &&
150 #endif
151 strstr(template,"ymbol") == NULL &&
152 strstr(template,"ingbats") == NULL)
153 strcat(template,"ISO8859-*");
154 else
155 strcat(template,"*-*");
156
157 if ((fontlist = XListFonts(tool_d, template, 1, &count)))
158 font_scalable[f] = True;
159 else
160 font_scalable[f] = False;
161
162 XFreeFontNames(fontlist);
163 }
164 }
165 }
166
167 /* no scalable fonts - query the server for all the font
168 names and sizes and build a list of them */
169
170 for (f = 0; f < NUM_FONTS; f++) {
171 if (!font_scalable[f]) {
172 nf = NULL;
173 strcpy(template,x_fontinfo[f].template);
174 strcat(template,"*-*-*-*-*-*-");
175 strcpy(backup_template,x_backup_fontinfo[f].template);
176 strcat(backup_template,"*-*-*-*-*-*-");
177 /* add ISO8859 (if not Symbol font or ZapfDingbats) to font name in non-international mode*/
178 if (
179 #ifdef I18N
180 !appres.international &&
181 #endif
182 strstr(template,"ymbol") == NULL &&
183 strstr(template,"ingbats") == NULL) {
184 strcat(template,"ISO8859-*");
185 strcat(backup_template,"ISO8859-*");
186 } else {
187 strcat(template,"*-*");
188 strcat(backup_template,"*-*");
189 }
190 /* don't free the Fontlist because we keep pointers into it */
191 p = 0;
192
193 if ((fontlist = XListFonts(tool_d, template, MAXNAMES, &count))==0)
194 fontlist = XListFonts(tool_d, backup_template, MAXNAMES, &count);
195
196 if (fontlist == 0) {
197 /* no fonts by that name found, substitute the -normal font name */
198 flist[p].fn = appres.normalFont;
199 flist[p++].s = 12; /* just set the size to 12 */
200 } else {
201 fname = fontlist; /* go through the list finding point
202 * sizes */
203 while (count--) {
204 ss = parsesize(*fname); /* get the point size from
205 * the name */
206 flist[p].fn = *fname++; /* save name of this size
207 * font */
208 flist[p++].s = ss; /* and save size */
209 }
210 }
211 /* start at size 4 and go to 50 */
212 for (ss = 4; ss <= 50; ss++) {
213 for (i = 0; i < p; i++)
214 if (flist[i].s == ss) /* found size */
215 break;
216 /* if found size, allocate the font */
217 if (i < p && flist[i].s == ss) {
218 newfont = (struct xfont *) malloc(sizeof(struct xfont));
219 if (nf == NULL)
220 x_fontinfo[f].xfontlist = newfont;
221 else
222 nf->next = newfont;
223 nf = newfont; /* keep current ptr */
224 nf->size = ss; /* store the size here */
225 if (appres.DEBUG)
226 fprintf(stderr,"Font: %s\n",flist[i].fn);
227 nf->fname = flist[i].fn; /* keep actual name */
228 nf->fstruct = NULL;
229 nf->fset = NULL;
230 nf->next = NULL;
231 }
232 } /* next size */
233 } /* !font_scalable[f] */
234 } /* next font, f */
235 }
236
237 /* parse the point size of font 'name' */
238 /* e.g. -adobe-courier-bold-o-normal--10-100-75-75-m-60-ISO8859-1 */
239
240 static int
parsesize(char * name)241 parsesize(char *name)
242 {
243 int s;
244 char *np;
245
246 for (np = name; *(np + 1); np++) {
247 /* look for "--" */
248 if (strncmp(np, "--", 2) == 0)
249 return atoi(np + 2);
250 /* For "-b&h-lucida-*-normal-sans-<point-size>-*" */
251 if (strncmp(np, "-normal-sans-", 13) == 0)
252 return atoi(np + 13);
253 }
254
255 fprintf(stderr, "Can't parse '%s'\n", name);
256 return 0;
257 }
258
259 /*
260 * Lookup an X font, "fnum" corresponding to a Postscript font style that is
261 * close in size to "size"
262 */
263
264 XFontStruct *
lookfont(int fnum,int size)265 lookfont(int fnum, int size)
266 {
267 XFontStruct *fontst;
268 XFontSet fontset = NULL;
269 char fn[300],back_fn[300];
270 char template[300], *sub;
271 Boolean found;
272 struct xfont *newfont, *nf, *oldnf;
273
274 #ifdef I18N
275 char **mcharset;
276 int ncharset;
277 char *defstr;
278 #endif
279
280 if (fnum == DEFAULT)
281 fnum = 0; /* pass back the -normal font font */
282 if (size < 0)
283 size = DEF_FONTSIZE; /* default font size */
284 if (size < MIN_X_FONT_SIZE)
285 size = MIN_X_FONT_SIZE; /* minimum allowable */
286 else if (size > MAX_X_FONT_SIZE)
287 size = MAX_X_FONT_SIZE; /* maximum allowable */
288
289 /* if user asks, adjust for correct font size */
290 if (appres.correct_font_size)
291 size = round(size*80.0/72.0);
292
293 /* see if we've already loaded that font size 'size'
294 from the font family 'fnum' */
295
296 found = False;
297
298 /* start with the basic font name (e.g. -*-times-medium-r-normal-... */
299
300 nf = x_fontinfo[fnum].xfontlist;
301 oldnf = nf;
302 if (nf != NULL) {
303 if (nf->size > size && !font_scalable[fnum])
304 found = True;
305 else {
306 while (nf != NULL) {
307 if (nf->size == size || (!font_scalable[fnum] &&
308 (nf->size >= size && oldnf->size <= size))) {
309 found = True;
310 break;
311 }
312 oldnf = nf;
313 nf = nf->next;
314 }
315 }
316 }
317 if (found) { /* found exact size (or only larger available) */
318 strcpy(fn,nf->fname); /* put the name in fn */
319 if (size < nf->size)
320 put_msg("Font size %d not found, using larger %d point",size,nf->size);
321 } else if (!font_scalable[fnum]) { /* not found, use largest available */
322 nf = oldnf;
323 strcpy(fn,nf->fname); /* put the name in fn */
324 if (size > nf->size)
325 put_msg("Font size %d not found, using smaller %d point",size,nf->size);
326 } else { /* scalablefonts; none yet of that size, alloc one and put it in the list */
327 newfont = (struct xfont *) malloc(sizeof(struct xfont));
328 /* add it on to the end of the list */
329 if (x_fontinfo[fnum].xfontlist == NULL)
330 x_fontinfo[fnum].xfontlist = newfont;
331 else
332 oldnf->next = newfont;
333 nf = newfont; /* keep current ptr */
334 nf->size = size; /* store the size here */
335 nf->fstruct = NULL;
336 nf->fset = NULL;
337 nf->next = NULL;
338
339 if (openwinfonts) {
340 /* OpenWindows fonts, create font name like times-roman-13 */
341 sprintf(fn, "%s-%d", x_fontinfo[fnum].template, size);
342 } else {
343 /* X11 fonts, create a full XLFD font name */
344 strcpy(template,x_fontinfo[fnum].template);
345 /* attach pointsize to font name */
346 strcat(template,"%d-*-*-*-*-*-");
347 /* add ISO8859 (if not Symbol font or ZapfDingbats) to font name in non-international mode */
348 if (
349 #ifdef I18N
350 !appres.international &&
351 #endif
352 strstr(template,"ymbol") == NULL &&
353 strstr(template,"ingbats") == NULL)
354 strcat(template,"ISO8859-*");
355 else
356 strcat(template,"*-*");
357 /* use the pixel field instead of points in the fontname so that the
358 font scales with screen size */
359 sprintf(fn, template, size);
360 /* do same process with backup font name in case first doesn't exist */
361 strcpy(template,x_backup_fontinfo[fnum].template);
362 strcat(template,"%d-*-*-*-*-*-");
363 /* add ISO8859 (if not Symbol font or ZapfDingbats) to font name in non-international mode */
364 if (
365 #ifdef I18N
366 !appres.international &&
367 #endif
368 strstr(template,"ymbol") == NULL &&
369 strstr(template,"ingbats") == NULL)
370 strcat(template,"ISO8859-*");
371 else
372 strcat(template,"*-*");
373 sprintf(back_fn, template, size);
374 }
375 /* allocate space for the name and put it in the structure */
376 nf->fname = (char *) new_string(max2(strlen(fn),strlen(back_fn)));
377 strcpy(nf->fname, fn);
378 /* save the backup name too */
379 nf->bname = (char *) new_string(strlen(back_fn));
380 strcpy(nf->bname, back_fn);
381 } /* scalable */
382
383 if (nf->fstruct == NULL) {
384 if (appres.DEBUG)
385 fprintf(stderr,"Loading font %s\n",fn);
386 /* if we are previewing a figure and the user pressed Cancel,
387 return now with the simple roman font */
388 if (check_cancel())
389 return roman_font;
390 set_temp_cursor(wait_cursor);
391 fontst = XLoadQueryFont(tool_d, fn);
392 #ifdef I18N
393 /* create fontsets for all fonts but Symbol and Dingbats */
394 if (appres.international &&
395 strstr(fn,"ymbol") == NULL &&
396 strstr(fn,"ingbats") == NULL)
397 fontset = XCreateFontSet(tool_d, fn, &mcharset, &ncharset, &defstr);
398 #endif
399 reset_cursor();
400 if (fontst == NULL) {
401 /* doesn't exist, see if substituting "condensed" for "narrow" will match */
402 if ((sub=strstr(fn,"-narrow-")) != NULL) {
403 strcpy(template, fn);
404 strcpy(&template[sub-fn],"-condensed-");
405 strcat(template, (sub+8));
406 /* try it */
407 fontst = XLoadQueryFont(tool_d, template);
408 } else {
409 /* doesn't exist, try backup font name */
410 fontst = XLoadQueryFont(tool_d, nf->bname);
411 if (fontst) {
412 /* use this name instead */
413 strcpy(nf->fname, nf->bname);
414 } else {
415 /* backup name doesn't exist, see if we can substitute "condensed" for "narrow" */
416 if ((sub=strstr(nf->bname,"-narrow-")) != NULL) {
417 /* see if substituting "condensed" for "narrow" will match */
418 strcpy(template, nf->bname);
419 strcpy(&template[sub-nf->bname],"-condensed-");
420 strcat(template, (sub+8));
421 /* try it */
422 fontst = XLoadQueryFont(tool_d, template);
423 }
424 }
425 }
426 }
427 if (fontst == NULL) {
428 /* even that font doesn't exist, use a plain one */
429 file_msg("Can't find %s, using %s", fn, appres.normalFont);
430 fontst = XLoadQueryFont(tool_d, appres.normalFont);
431 if (nf->fname)
432 free(nf->fname);
433 /* allocate space for the name and put it in the structure */
434 nf->fname = (char *) new_string(strlen(appres.normalFont));
435 strcpy(nf->fname, appres.normalFont); /* keep actual name */
436 }
437
438 /* put the structure in the list */
439 nf->fstruct = fontst;
440 nf->fset = fontset;
441 } /* if (nf->fstruct == NULL) */
442
443 return (nf->fstruct);
444 }
445
446 /* print "string" in window "w" using font specified in fstruct at angle
447 "angle" (radians) at (x,y)
448 If background is != COLOR_NONE, draw background color ala DrawImageString
449 */
450
451 void
pw_text(Window w,int x,int y,int op,int depth,XFontStruct * fstruct,float angle,char * string,Color color,Color background)452 pw_text(Window w, int x, int y, int op, int depth, XFontStruct *fstruct,
453 float angle, char *string, Color color, Color background)
454 {
455 int xfg, xbg;
456
457 if (fstruct == NULL) {
458 fprintf(stderr,"Error, in pw_text, fstruct==NULL\n");
459 return;
460 }
461
462 /* if this depth is inactive, draw the text in gray */
463 /* if depth == MAX_DEPTH+1 then the caller wants the original color no matter what */
464 if (draw_parent_gray || (depth < MAX_DEPTH+1 && !active_layer(depth)))
465 color = MED_GRAY;
466
467 /* get the X colors */
468 xfg = x_color(color);
469 xbg = x_color(background);
470 if ((xfg != gc_color[op]) ||
471 (background != COLOR_NONE && (xbg != gc_background[op]))) {
472 /* don't change the colors for ERASE */
473 if (op == PAINT || op == INV_PAINT) {
474 if (op == PAINT)
475 set_x_fg_color(gccache[op], color);
476 else
477 XSetForeground(tool_d,gccache[op], xfg ^ x_bg_color.pixel);
478 gc_color[op] = xfg;
479 if (background != COLOR_NONE) {
480 set_x_bg_color(gccache[op], background);
481 gc_background[op] = xbg;
482 }
483 }
484 }
485
486 /* check for preview cancel here. The text call may take some time if
487 a large font has to be rotated. */
488 if (check_cancel())
489 return ;
490
491 if (background != COLOR_NONE) {
492 zXRotDrawImageString(tool_d, fstruct, angle, w, gccache[op], x, y, string);
493 } else {
494 zXRotDrawString(tool_d, fstruct, angle, w, gccache[op], x, y, string);
495 }
496 }
497
498 PR_SIZE
textsize(XFontStruct * fstruct,int n,char * s)499 textsize(XFontStruct *fstruct, int n, char *s)
500 {
501 PR_SIZE ret;
502 int dir, asc, desc;
503 XCharStruct overall;
504
505 #ifdef I18N
506 if (appres.international) {
507 extern void i18n_text_extents(); /* w_i18n.h */
508 i18n_text_extents(fstruct, s, n, &dir, &asc, &desc, &overall);
509 ret.length = ZOOM_FACTOR * overall.width;
510 ret.ascent = ZOOM_FACTOR * overall.ascent;
511 ret.descent = ZOOM_FACTOR * overall.descent;
512 return (ret);
513 }
514 #endif /* I18N */
515 XTextExtents(fstruct, s, n, &dir, &asc, &desc, &overall);
516 ret.length = ZOOM_FACTOR * overall.width;
517 ret.ascent = ZOOM_FACTOR * overall.ascent;
518 ret.descent = ZOOM_FACTOR * overall.descent;
519 return (ret);
520 }
521
522 /* LINES */
523
524 static int gc_thickness[NUMOPS],
525 gc_line_style[NUMOPS],
526 gc_join_style[NUMOPS],
527 gc_cap_style[NUMOPS];
528
529 GC
makegc(int op,Pixel fg,Pixel bg)530 makegc(int op, Pixel fg, Pixel bg)
531 {
532 register GC ngc;
533 XGCValues gcv;
534 unsigned long gcmask;
535
536 gcv.font = roman_font->fid;
537 gcv.join_style = JoinMiter;
538 gcv.cap_style = CapButt;
539 gcmask = GCJoinStyle | GCCapStyle | GCFunction | GCForeground |
540 GCBackground | GCFont;
541 switch (op) {
542 case PAINT:
543 gcv.foreground = fg;
544 gcv.background = bg;
545 gcv.function = GXcopy;
546 break;
547 case ERASE:
548 gcv.foreground = bg;
549 gcv.background = bg;
550 gcv.function = GXcopy;
551 break;
552 case INV_PAINT:
553 gcv.foreground = fg ^ bg;
554 gcv.background = bg;
555 gcv.function = GXxor;
556 break;
557 }
558
559 ngc = XCreateGC(tool_d, tool_w, gcmask, &gcv);
560 return (ngc);
561 }
562
init_gc(void)563 void init_gc(void)
564 {
565 int i;
566 XColor tmp_color;
567 XGCValues gcv;
568
569 gccache[PAINT] = makegc(PAINT, x_fg_color.pixel, x_bg_color.pixel);
570 gccache[ERASE] = makegc(ERASE, x_fg_color.pixel, x_bg_color.pixel);
571 gccache[INV_PAINT] = makegc(INV_PAINT, x_fg_color.pixel, x_bg_color.pixel);
572 /* parse any grid color spec */
573 XParseColor(tool_d, tool_cm, appres.grid_color, &tmp_color);
574 if (XAllocColor(tool_d, tool_cm, &tmp_color)==0) {
575 fprintf(stderr,"Can't allocate color for grid \n");
576 grid_color = x_fg_color.pixel;
577 grid_gc = makegc(PAINT, grid_color, x_bg_color.pixel);
578 } else {
579 grid_color = tmp_color.pixel;
580 grid_gc = makegc(PAINT, grid_color, x_bg_color.pixel);
581 }
582
583 for (i = 0; i < NUMOPS; i++) {
584 gc_color[i] = -1;
585 gc_background[i] = -1;
586 gc_thickness[i] = -1;
587 gc_line_style[i] = -1;
588 gc_join_style[i] = -1;
589 }
590 /* gc for page border and axis lines */
591 border_gc = DefaultGC(tool_d, tool_sn);
592 /* set the roman font for the message window */
593 XSetFont(tool_d, border_gc, roman_font->fid);
594
595 /* gc for picture pixmap rendering */
596 pic_gc = XCreateGC(tool_d, DefaultRootWindow(tool_d), 0, NULL);
597
598 /* make a gc for the command buttons */
599 gcv.font = button_font->fid;
600 button_gc = XCreateGC(tool_d, DefaultRootWindow(tool_d), GCFont, &gcv);
601 /* copy the other components from the page border gc to the button_gc */
602 XCopyGC(tool_d, border_gc, ~GCFont, button_gc);
603
604 }
605
606 /* create the gc's for fill style (PAINT and ERASE) */
607 /* the fill_pm[] must already be created */
608
init_fill_gc(void)609 void init_fill_gc(void)
610 {
611 XGCValues gcv;
612 int i;
613 unsigned long mask;
614
615 gcv.fill_style = FillOpaqueStippled;
616 gcv.arc_mode = ArcPieSlice; /* fill mode for arcs */
617 gcv.fill_rule = EvenOddRule /* WindingRule */ ;
618 for (i = 0; i < NUMFILLPATS; i++) {
619 /* all the bits are recolored in set_fill_gc() */
620 fill_gc[i] = makegc(PAINT, x_fg_color.pixel, x_color(BLACK));
621 mask = GCFillStyle | GCFillRule | GCArcMode;
622 if (fill_pm[i]) {
623 gcv.stipple = fill_pm[i];
624 mask |= GCStipple;
625 }
626 XChangeGC(tool_d, fill_gc[i], mask, &gcv);
627 }
628 }
629
630 /* SHADING */
631
632 /* grey images for fill patterns (32x32) */
633 unsigned char shade_images[NUMSHADEPATS][128] = {
634 {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
635 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
636 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
637 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
638 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
639 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
640 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
641 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
642 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
643 {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x88,0x88,
644 0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08,
645 0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x88,
646 0x88,0x88,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
647 0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
648 0x00,0x88,0x88,0x88,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
649 0x00,0x00,0x08,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
650 0x00,0x00,0x00,0x88,0x88,0x88,0x88,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
651 0x00,0x00,0x00,0x00,0x08,0x08,0x08,0x08},
652 {0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x00,0x00,0x00,
653 0x00,0x01,0x11,0x01,0x11,0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x00,0x00,
654 0x00,0x00,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x00,
655 0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44,
656 0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x44,0x44,0x44,
657 0x44,0x00,0x00,0x00,0x00,0x01,0x11,0x01,0x11,0x00,0x00,0x00,0x00,0x44,0x44,
658 0x44,0x44,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x00,0x44,
659 0x44,0x44,0x44,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,
660 0x44,0x44,0x44,0x44,0x00,0x00,0x00,0x00},
661 {0x00,0x00,0x00,0x00,0x11,0x51,0x11,0x51,0x00,0x00,0x00,0x00,0x44,0x44,0x44,
662 0x44,0x00,0x00,0x00,0x00,0x15,0x15,0x15,0x15,0x00,0x00,0x00,0x00,0x44,0x44,
663 0x44,0x44,0x00,0x00,0x00,0x00,0x51,0x11,0x51,0x11,0x00,0x00,0x00,0x00,0x44,
664 0x44,0x44,0x44,0x00,0x00,0x00,0x00,0x15,0x15,0x15,0x15,0x00,0x00,0x00,0x00,
665 0x44,0x44,0x44,0x44,0x00,0x00,0x00,0x00,0x11,0x51,0x11,0x51,0x00,0x00,0x00,
666 0x00,0x44,0x44,0x44,0x44,0x00,0x00,0x00,0x00,0x15,0x15,0x15,0x15,0x00,0x00,
667 0x00,0x00,0x44,0x44,0x44,0x44,0x00,0x00,0x00,0x00,0x51,0x11,0x51,0x11,0x00,
668 0x00,0x00,0x00,0x44,0x44,0x44,0x44,0x00,0x00,0x00,0x00,0x15,0x15,0x15,0x15,
669 0x00,0x00,0x00,0x00,0x44,0x44,0x44,0x44},
670 {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,0x00,0x00,0x00,0x00,0x8a,0x88,0x8a,
671 0x88,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,0x00,0x00,0x00,0x00,0x88,0x88,
672 0x88,0x88,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,0x00,0x00,0x00,0x00,0x8a,
673 0x8a,0x8a,0x8a,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,0x00,0x00,0x00,0x00,
674 0x88,0x88,0x88,0x88,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,0x00,0x00,0x00,
675 0x00,0x8a,0x88,0x8a,0x88,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,0x00,0x00,
676 0x00,0x00,0x88,0x88,0x88,0x88,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,0x00,
677 0x00,0x00,0x00,0x8a,0x8a,0x8a,0x8a,0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
678 0x00,0x00,0x00,0x00,0x88,0x88,0x88,0x88},
679 {0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,
680 0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,
681 0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,
682 0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,
683 0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,
684 0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,
685 0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,
686 0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,
687 0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00},
688 {0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x88,0x88,0x88,
689 0x88,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x80,0x80,
690 0x80,0x80,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,0x88,
691 0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,0x55,
692 0x88,0x80,0x88,0x80,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,0x55,
693 0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,0x55,
694 0x55,0x55,0x80,0x80,0x80,0x80,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x55,
695 0x55,0x55,0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x00,0x00,0x00,0x00,
696 0x55,0x55,0x55,0x55,0x88,0x80,0x88,0x80},
697 {0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,0x80,0x80,0x80,0x80,0x55,0x55,0x55,
698 0x55,0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,0x88,0x08,0x88,0x08,0x55,0x55,
699 0x55,0x55,0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,0x80,0x80,0x80,0x80,0x55,
700 0x55,0x55,0x55,0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,0x08,0x08,0x08,0x08,
701 0x55,0x55,0x55,0x55,0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,0x80,0x80,0x80,
702 0x80,0x55,0x55,0x55,0x55,0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,0x88,0x08,
703 0x88,0x08,0x55,0x55,0x55,0x55,0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,0x80,
704 0x80,0x80,0x80,0x55,0x55,0x55,0x55,0x22,0x22,0x22,0x22,0x55,0x55,0x55,0x55,
705 0x08,0x08,0x08,0x08,0x55,0x55,0x55,0x55},
706 {0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x22,0xa2,0x22,0xa2,0x55,0x55,0x55,
707 0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x2a,0x2a,0x2a,0x2a,0x55,0x55,
708 0x55,0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0xa2,0x22,0xa2,0x22,0x55,
709 0x55,0x55,0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x2a,0x2a,0x2a,0x2a,
710 0x55,0x55,0x55,0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x22,0xa2,0x22,
711 0xa2,0x55,0x55,0x55,0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0x2a,0x2a,
712 0x2a,0x2a,0x55,0x55,0x55,0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,0xa2,
713 0x22,0xa2,0x22,0x55,0x55,0x55,0x55,0x88,0x88,0x88,0x88,0x55,0x55,0x55,0x55,
714 0x2a,0x2a,0x2a,0x2a,0x55,0x55,0x55,0x55},
715 {0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x54,0x54,0x54,
716 0x54,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x44,0x44,
717 0x44,0x44,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x44,
718 0x54,0x44,0x54,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,
719 0x44,0x44,0x44,0x44,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,
720 0xaa,0x54,0x54,0x54,0x54,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,
721 0xaa,0xaa,0x44,0x44,0x44,0x44,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,
722 0xaa,0xaa,0xaa,0x44,0x54,0x44,0x54,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,
723 0xaa,0xaa,0xaa,0xaa,0x44,0x44,0x44,0x44},
724 {0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,
725 0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,
726 0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,
727 0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,
728 0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,
729 0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,
730 0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,
731 0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,
732 0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa},
733 {0xdd,0xdd,0xdd,0xdd,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,
734 0xaa,0xd5,0xd5,0xd5,0xd5,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,0xaa,
735 0xaa,0xaa,0xdd,0xdd,0xdd,0xdd,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,0xaa,
736 0xaa,0xaa,0xaa,0xdd,0xd5,0xdd,0xd5,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,0x55,
737 0xaa,0xaa,0xaa,0xaa,0xdd,0xdd,0xdd,0xdd,0xaa,0xaa,0xaa,0xaa,0x55,0x55,0x55,
738 0x55,0xaa,0xaa,0xaa,0xaa,0xd5,0xd5,0xd5,0xd5,0xaa,0xaa,0xaa,0xaa,0x55,0x55,
739 0x55,0x55,0xaa,0xaa,0xaa,0xaa,0xdd,0xdd,0xdd,0xdd,0xaa,0xaa,0xaa,0xaa,0x55,
740 0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa,0xdd,0xd5,0xdd,0xd5,0xaa,0xaa,0xaa,0xaa,
741 0x55,0x55,0x55,0x55,0xaa,0xaa,0xaa,0xaa},
742 {0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0xd5,0xd5,0xd5,0xd5,0xaa,0xaa,0xaa,
743 0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0xdd,0x5d,0xdd,0x5d,0xaa,0xaa,
744 0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0xd5,0xd5,0xd5,0xd5,0xaa,
745 0xaa,0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0x5d,0xdd,0x5d,0xdd,
746 0xaa,0xaa,0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0xd5,0xd5,0xd5,
747 0xd5,0xaa,0xaa,0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0xdd,0x5d,
748 0xdd,0x5d,0xaa,0xaa,0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0xd5,
749 0xd5,0xd5,0xd5,0xaa,0xaa,0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,
750 0x5d,0xdd,0x5d,0xdd,0xaa,0xaa,0xaa,0xaa},
751 {0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,0x55,0x55,0x55,0x55,0xfe,0xfe,0xfe,
752 0xfe,0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,0x55,0x55,0x55,0x55,0xee,0xef,
753 0xee,0xef,0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,0x55,0x55,0x55,0x55,0xfe,
754 0xfe,0xfe,0xfe,0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,0x55,0x55,0x55,0x55,
755 0xef,0xef,0xef,0xef,0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,0x55,0x55,0x55,
756 0x55,0xfe,0xfe,0xfe,0xfe,0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,0x55,0x55,
757 0x55,0x55,0xee,0xef,0xee,0xef,0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,0x55,
758 0x55,0x55,0x55,0xfe,0xfe,0xfe,0xfe,0x55,0x55,0x55,0x55,0xbb,0xbb,0xbb,0xbb,
759 0x55,0x55,0x55,0x55,0xef,0xef,0xef,0xef},
760 {0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,0xaa,0xaa,
761 0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0x77,0x7f,0x77,0x7f,0xaa,0xaa,
762 0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0x77,0x77,0x77,0x77,0xaa,
763 0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0x7f,0x7f,0x7f,0x7f,
764 0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0x77,0x77,0x77,
765 0x77,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0x77,0x7f,
766 0x77,0x7f,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0x77,
767 0x77,0x77,0x77,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,
768 0x7f,0x7f,0x7f,0x7f,0xaa,0xaa,0xaa,0xaa},
769 {0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,
770 0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,
771 0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,
772 0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,
773 0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,
774 0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,
775 0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,
776 0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa,
777 0xff,0xff,0xff,0xff,0xaa,0xaa,0xaa,0xaa},
778 {0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,0xdd,0xdd,0xdd,0xdd,0xff,0xff,0xff,
779 0xff,0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,0x5d,0xdd,0x5d,0xdd,0xff,0xff,
780 0xff,0xff,0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,0xdd,0xdd,0xdd,0xdd,0xff,
781 0xff,0xff,0xff,0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,0x5d,0x5d,0x5d,0x5d,
782 0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,0xdd,0xdd,0xdd,
783 0xdd,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,0x5d,0xdd,
784 0x5d,0xdd,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,0xdd,
785 0xdd,0xdd,0xdd,0xff,0xff,0xff,0xff,0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff,
786 0x5d,0x5d,0x5d,0x5d,0xff,0xff,0xff,0xff},
787 {0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xbb,0xba,0xba,0xba,0xff,0xff,0xff,
788 0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xab,0xbb,0xab,0xbb,0xff,0xff,
789 0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xbb,0xba,0xba,0xba,0xff,
790 0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xbb,0xab,0xbb,0xab,
791 0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xbb,0xba,0xba,
792 0xba,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xab,0xbb,
793 0xab,0xbb,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xbb,
794 0xba,0xba,0xba,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,
795 0xbb,0xab,0xbb,0xab,0xff,0xff,0xff,0xff},
796 {0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xfb,0xfb,0xfb,
797 0xfb,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xbf,0xbb,
798 0xbf,0xbb,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,0xfb,
799 0xfb,0xfb,0xfb,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,0xff,
800 0xbf,0xbf,0xbf,0xbf,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,0xff,
801 0xff,0xfb,0xfb,0xfb,0xfb,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,0xff,
802 0xff,0xff,0xbf,0xbb,0xbf,0xbb,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,0xff,
803 0xff,0xff,0xff,0xfb,0xfb,0xfb,0xfb,0xff,0xff,0xff,0xff,0xee,0xee,0xee,0xee,
804 0xff,0xff,0xff,0xff,0xbf,0xbf,0xbf,0xbf},
805 {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbb,0xbb,0xbb,
806 0xbb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xfb,
807 0xfb,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xbb,
808 0xbb,0xbb,0xbb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
809 0xfb,0xfb,0xfb,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
810 0xff,0xbb,0xbb,0xbb,0xbb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
811 0xff,0xff,0xfb,0xfb,0xfb,0xfb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
812 0xff,0xff,0xff,0xbb,0xbb,0xbb,0xbb,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
813 0xff,0xff,0xff,0xff,0xfb,0xfb,0xfb,0xfb},
814 {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
815 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
816 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
817 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
818 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
819 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
820 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
821 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
822 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff},
823 };
824
825 /* initial data for patterns */
826
827 /* 30 degrees left diagonal */
828 #define left30_width 8
829 #define left30_height 4
830 static unsigned char left30_bits[] = {
831 0x03, 0x0c, 0x30, 0xc0};
832 /* 30 degrees right diagonal */
833 #define right30_width 8
834 #define right30_height 4
835 static unsigned char right30_bits[] = {
836 0xc0, 0x30, 0x0c, 0x03};
837 /* 30 degrees crosshatch */
838 #define crosshatch30_width 8
839 #define crosshatch30_height 4
840 static unsigned char crosshatch30_bits[] = {
841 0x81, 0x66, 0x18, 0x66};
842 /* 45 degrees left diagonal */
843 #define left45_width 8
844 #define left45_height 8
845 static unsigned char left45_bits[] = {
846 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
847 /* 45 degrees right diagonal */
848 #define right45_width 8
849 #define right45_height 8
850 static unsigned char right45_bits[] = {
851 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
852 /* 45 degrees crosshatch */
853 #define crosshatch45_width 8
854 #define crosshatch45_height 8
855 static unsigned char crosshatch45_bits[] = {
856 0x11, 0x0a, 0x04, 0x0a, 0x11, 0xa0, 0x40, 0xa0};
857 /* horizontal bricks */
858 #define bricks_width 16
859 #define bricks_height 16
860 static unsigned char bricks_bits[] = {
861 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80,
862 0x00, 0x80, 0xff, 0xff, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
863 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xff, 0xff};
864 /* vertical bricks */
865 #define vert_bricks_width 16
866 #define vert_bricks_height 16
867 static unsigned char vert_bricks_bits[] = {
868 0xff, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
869 0x80, 0x80, 0x80, 0x80, 0x80, 0xff, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
870 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80};
871 /* horizontal lines */
872 #define horizontal_width 8
873 #define horizontal_height 4
874 static unsigned char horizontal_bits[] = {
875 0xff, 0x00, 0x00, 0x00};
876 /* vertical lines */
877 #define vertical_width 8
878 #define vertical_height 8
879 static unsigned char vertical_bits[] = {
880 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88};
881 /* crosshatch */
882 #define crosshatch_width 8
883 #define crosshatch_height 4
884 static unsigned char crosshatch_bits[] = {
885 0xff, 0x88, 0x88, 0x88};
886 /* left-pointing shingles */
887 #define leftshingle_width 24
888 #define leftshingle_height 24
889 static unsigned char leftshingle_bits[] = {
890 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40,
891 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff,
892 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00,
893 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0xff, 0xff, 0xff,
894 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00,
895 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0xff, 0xff, 0xff};
896 /* right-pointing shingles */
897 #define rightshingle_width 24
898 #define rightshingle_height 24
899 static unsigned char rightshingle_bits[] = {
900 0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20,
901 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff,
902 0x00, 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00,
903 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x00, 0xff, 0xff, 0xff,
904 0x10, 0x00, 0x00, 0x10, 0x00, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00,
905 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x00, 0x00, 0xff, 0xff, 0xff};
906 /* vertical left-pointing shingles */
907 #define vert_leftshingle_width 24
908 #define vert_leftshingle_height 24
909 static unsigned char vert_leftshingle_bits[] = {
910 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
911 0x80, 0x80, 0x81, 0x80, 0x80, 0x86, 0x80, 0x80, 0x98, 0x80, 0x80, 0xe0,
912 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
913 0x80, 0x81, 0x80, 0x80, 0x86, 0x80, 0x80, 0x98, 0x80, 0x80, 0xe0, 0x80,
914 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
915 0x81, 0x80, 0x80, 0x86, 0x80, 0x80, 0x98, 0x80, 0x80, 0xe0, 0x80, 0x80};
916 /* vertical right-pointing shingles */
917 #define vert_rightshingle_width 24
918 #define vert_rightshingle_height 24
919 static unsigned char vert_rightshingle_bits[] = {
920 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
921 0x80, 0xc0, 0x80, 0x80, 0xb0, 0x80, 0x80, 0x8c, 0x80, 0x80, 0x83, 0x80,
922 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
923 0x80, 0x80, 0xc0, 0x80, 0x80, 0xb0, 0x80, 0x80, 0x8c, 0x80, 0x80, 0x83,
924 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
925 0xc0, 0x80, 0x80, 0xb0, 0x80, 0x80, 0x8c, 0x80, 0x80, 0x83, 0x80, 0x80};
926 /* fish scales */
927 #define fishscales_width 16
928 #define fishscales_height 8
929 static unsigned char fishscales_bits[] = {
930 0x40, 0x02, 0x30, 0x0c, 0x0e, 0x70, 0x01, 0x80, 0x02, 0x40, 0x0c, 0x30,
931 0x70, 0x0e, 0x80, 0x01};
932 /* small fish scales */
933 #define small_fishscales_width 8
934 #define small_fishscales_height 8
935 static unsigned char small_fishscales_bits[] = {
936 0x01, 0x01, 0x82, 0x6c, 0x10, 0x10, 0x28, 0xc6};
937 /* circles */
938 #define circles_width 16
939 #define circles_height 16
940 static unsigned char circles_bits[] = {
941 0xe0, 0x0f, 0x18, 0x30, 0x04, 0x40, 0x02, 0x80, 0x02, 0x80, 0x01, 0x00,
942 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
943 0x02, 0x80, 0x02, 0x80, 0x04, 0x40, 0x18, 0x30};
944 /* hexagons */
945 #define hexagons_width 30
946 #define hexagons_height 18
947 static unsigned char hexagons_bits[] = {
948 0x08, 0x80, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00,
949 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00,
950 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf8, 0x3f,
951 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x02, 0x00, 0x02, 0x00,
952 0x02, 0x00, 0x02, 0x00, 0x04, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00,
953 0x08, 0x80, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00};
954 /* octagons */
955 #define octagons_width 16
956 #define octagons_height 16
957 static unsigned char octagons_bits[] = {
958 0xe0, 0x0f, 0x10, 0x10, 0x08, 0x20, 0x04, 0x40, 0x02, 0x80, 0x01, 0x00,
959 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
960 0x02, 0x80, 0x04, 0x40, 0x08, 0x20, 0x10, 0x10};
961 /* horizontal sawtooth */
962 #define horiz_saw_width 16
963 #define horiz_saw_height 8
964 static unsigned char horiz_saw_bits[] = {
965 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x14, 0x14, 0x22, 0x22,
966 0x41, 0x41, 0x80, 0x80};
967 /* vertical sawtooth */
968 #define vert_saw_width 8
969 #define vert_saw_height 16
970 static unsigned char vert_saw_bits[] = {
971 0x02, 0x04, 0x08, 0x10, 0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08, 0x10,
972 0x08, 0x04, 0x02, 0x01};
973
974 /* patterns like bricks, etc */
975 patrn_strct pattern_images[NUMPATTERNS] = {
976 {left30_width, left30_height, (char*)left30_bits},
977 {right30_width, right30_height, (char*)right30_bits},
978 {crosshatch30_width, crosshatch30_height, (char*)crosshatch30_bits},
979 {left45_width, left45_height, (char*)left45_bits},
980 {right45_width, right45_height, (char*)right45_bits},
981 {crosshatch45_width, crosshatch45_height, (char*)crosshatch45_bits},
982 {bricks_width, bricks_height, (char*)bricks_bits},
983 {vert_bricks_width, vert_bricks_height, (char*)vert_bricks_bits},
984 {horizontal_width, horizontal_height, (char*)horizontal_bits},
985 {vertical_width, vertical_height, (char*)vertical_bits},
986 {crosshatch_width, crosshatch_height, (char*)crosshatch_bits},
987 {leftshingle_width, leftshingle_height, (char*)leftshingle_bits},
988 {rightshingle_width, rightshingle_height, (char*)rightshingle_bits},
989 {vert_leftshingle_width, vert_leftshingle_height, (char*)vert_leftshingle_bits},
990 {vert_rightshingle_width, vert_rightshingle_height, (char*)vert_rightshingle_bits},
991 {fishscales_width, fishscales_height, (char*)fishscales_bits},
992 {small_fishscales_width, small_fishscales_height, (char*)small_fishscales_bits},
993 {circles_width, circles_height, (char*)circles_bits},
994 {hexagons_width, hexagons_height, (char*)hexagons_bits},
995 {octagons_width, octagons_height, (char*)octagons_bits},
996 {horiz_saw_width, horiz_saw_height, (char*)horiz_saw_bits},
997 {vert_saw_width, vert_saw_height, (char*)vert_saw_bits}
998 };
999
1000 /* generate the fill pixmaps */
1001
init_fill_pm(void)1002 void init_fill_pm(void)
1003 {
1004 int i,j;
1005
1006 for (i = 0; i <= NUMFILLPATS; i++) {
1007 fillstyle_choices[i].value = i;
1008 fillstyle_choices[i].icon = &none_ic;
1009 }
1010
1011 /**********************************************************************************/
1012 /* NOTE: All fillstyle_choices pixmaps will be recolored in recolor_fillstyles() */
1013 /**********************************************************************************/
1014
1015 /* use same colors for "NONE" indicator for black and color */
1016 fillstyle_choices[0].pixmap = XCreatePixmapFromBitmapData(tool_d,
1017 tool_w, none_ic.bits, none_ic.width,
1018 none_ic.height, x_fg_color.pixel, x_bg_color.pixel,
1019 tool_dpth);
1020
1021 /* Shade patterns go from full black to full saturation of the color */
1022 for (i = 0; i < NUMSHADEPATS; i++) {
1023 fill_pm[i] = XCreateBitmapFromData(tool_d, tool_w,
1024 (char*)shade_images[i], SHADE_IM_SIZE, SHADE_IM_SIZE);
1025 /* create fill style pixmaps for indicator button */
1026 /* The actual colors of fg/bg will be reset in recolor_fillstyles */
1027 fillstyle_choices[i + 1].pixmap = XCreatePixmapFromBitmapData(tool_d,
1028 tool_w, (char*)shade_images[i], SHADE_IM_SIZE, SHADE_IM_SIZE,
1029 x_fg_color.pixel,x_bg_color.pixel,tool_dpth);
1030 }
1031 /* Tint patterns go from full saturation of the color to full white */
1032 /* Note that there are no fillstyle_choices for tints for black */
1033 for (i = NUMSHADEPATS; i < NUMSHADEPATS+NUMTINTPATS; i++) {
1034 j = NUMSHADEPATS+NUMTINTPATS-i-1; /* reverse the patterns */
1035 fill_pm[i] = XCreateBitmapFromData(tool_d, tool_w,
1036 (char*)shade_images[j], SHADE_IM_SIZE, SHADE_IM_SIZE);
1037 /* create fill style pixmaps for indicator button */
1038 /* The actual colors of fg/bg will be reset in recolor_fillstyles */
1039 fillstyle_choices[i + 1].pixmap = XCreatePixmapFromBitmapData(tool_d,
1040 tool_w, (char*)shade_images[j], SHADE_IM_SIZE, SHADE_IM_SIZE,
1041 x_fg_color.pixel,x_bg_color.pixel,tool_dpth);
1042 }
1043 /* Now do the remaining patterns (bricks, shingles, etc) */
1044 for (i = NUMSHADEPATS+NUMTINTPATS; i < NUMFILLPATS; i++) {
1045 /* create pattern at this zoom */
1046 rescale_pattern(i);
1047 j = i-(NUMSHADEPATS+NUMTINTPATS);
1048 /* save these patterns at zoom = 1 for the fill button panel */
1049 fill_but_pm[j] = fill_pm[i];
1050 fill_but_pm_zoom[j] = fill_pm_zoom[i];
1051 /* to force new pixmaps for canvas */
1052 fill_pm[i] = (Pixmap) 0;
1053 /* and create another one */
1054 rescale_pattern(i);
1055 /* create fill style pixmaps for indicator button */
1056 /* The actual colors of fg/bg will be reset in recolor_fillstyles */
1057 fillstyle_choices[i + 1].pixmap = XCreatePixmapFromBitmapData(tool_d,
1058 tool_w, pattern_images[j].odata,
1059 pattern_images[j].owidth, pattern_images[j].oheight,
1060 x_fg_color.pixel,x_bg_color.pixel,tool_dpth);
1061 }
1062 }
1063
1064 void
pw_vector(Window w,int x1,int y1,int x2,int y2,int op,int line_width,int line_style,float style_val,Color color)1065 pw_vector(Window w, int x1, int y1, int x2, int y2, int op,
1066 int line_width, int line_style, float style_val, Color color)
1067 {
1068 if (line_width == 0)
1069 return;
1070 set_line_stuff(line_width, line_style, style_val, JOIN_MITER, CAP_BUTT, op, color);
1071 if (line_style == PANEL_LINE)
1072 XDrawLine(tool_d, w, gccache[op], x1, y1, x2, y2);
1073 else
1074 zXDrawLine(tool_d, w, gccache[op], x1, y1, x2, y2);
1075 }
1076
1077 void
pw_curve(Window w,int xstart,int ystart,int xend,int yend,int op,int depth,int linewidth,int style,float style_val,int fill_style,Color pen_color,Color fill_color,int cap_style)1078 pw_curve(Window w, int xstart, int ystart, int xend, int yend,
1079 int op, int depth, int linewidth, int style, float style_val, int fill_style,
1080 Color pen_color, Color fill_color, int cap_style)
1081 {
1082 int xmin, ymin;
1083 unsigned int wd, ht;
1084
1085 /* if this depth is inactive, draw the curve and any fill in gray */
1086 /* if depth == MAX_DEPTH+1 then the caller wants the original color no matter what */
1087 if (draw_parent_gray || (depth < MAX_DEPTH+1 && !active_layer(depth))) {
1088 pen_color = MED_GRAY;
1089 fill_color = LT_GRAY;
1090 }
1091
1092 xmin = min2(xstart, xend);
1093 ymin = min2(ystart, yend);
1094 wd = (unsigned int) abs(xstart - xend);
1095 ht = (unsigned int) abs(ystart - yend);
1096
1097 /* if it's a fill pat we know about */
1098 if (fill_style >= 0 && fill_style < NUMFILLPATS) {
1099 set_fill_gc(fill_style, op, pen_color, fill_color, xstart, ystart);
1100 zXFillArc(tool_d, w, fillgc, xmin, ymin, wd, ht, 0, 360 * 64);
1101 }
1102 if (linewidth == 0)
1103 return;
1104 if (op == ERASE) {
1105 /* kludge - to speed things up we erase with thick solid lines */
1106 set_line_stuff(linewidth + 3, SOLID_LINE, 0.0, JOIN_MITER,
1107 cap_style, op, pen_color);
1108 zXDrawArc(tool_d, w, gccache[op], xmin, ymin, wd, ht, 0, 360 * 64);
1109 } else {
1110 set_line_stuff(linewidth, style, style_val, JOIN_MITER,
1111 cap_style, op, pen_color);
1112 zXDrawArc(tool_d, w, gccache[op], xmin, ymin, wd, ht, 0, 360 * 64);
1113 }
1114 }
1115
1116 /* a point object - actually draw a line from (x-line_width/2,y) to (x+linewidth/2,y)
1117 so that we get some thickness */
1118
1119 void
pw_point(Window w,int x,int y,int op,int depth,int line_width,Color color,int cap_style)1120 pw_point(Window w, int x, int y, int op, int depth, int line_width,
1121 Color color, int cap_style)
1122 {
1123 int hf_wid;
1124
1125 /* if this depth is inactive, draw the point in gray */
1126 if (draw_parent_gray || !active_layer(depth))
1127 color = MED_GRAY;
1128
1129 /* pw_point doesn't use line_style or fill_style but needs color */
1130 set_line_stuff(line_width, SOLID_LINE, 0.0, JOIN_MITER, cap_style,
1131 op, color);
1132 if (cap_style > 0)
1133 hf_wid = 0;
1134 else
1135 hf_wid = (int)(ZOOM_FACTOR*line_width/2);
1136 /* add one to the right if the line_width is odd */
1137 zXDrawLine(tool_d, w, gccache[op], x-hf_wid, y, x+hf_wid+(line_width%2), y);
1138 }
1139
1140 void
pw_arcbox(Window w,int xmin,int ymin,int xmax,int ymax,int radius,int op,int depth,int line_width,int line_style,float style_val,int fill_style,Color pen_color,Color fill_color)1141 pw_arcbox(Window w, int xmin, int ymin, int xmax, int ymax, int radius,
1142 int op, int depth, int line_width, int line_style,
1143 float style_val, int fill_style, Color pen_color, Color fill_color)
1144 {
1145 GC gc;
1146 int diam = 2 * radius;
1147
1148 /* if this depth is inactive, draw the arcbox in gray */
1149 if (draw_parent_gray || (depth < MAX_DEPTH+1 && !active_layer(depth))) {
1150 pen_color = MED_GRAY;
1151 fill_color = LT_GRAY;
1152 }
1153
1154 /* if it's a fill pat we know about */
1155 if (fill_style >= 0 && fill_style < NUMFILLPATS) {
1156 set_fill_gc(fill_style, op, pen_color, fill_color, xmin, ymin);
1157 /* upper left */
1158 zXFillArc(tool_d, w, fillgc, xmin, ymin, diam, diam, 90 * 64, 90 * 64);
1159 /* lower left */
1160 zXFillArc(tool_d, w, fillgc, xmin, ymax - diam, diam, diam, 180 * 64, 90 * 64);
1161 /* lower right */
1162 zXFillArc(tool_d, w, fillgc, xmax - diam, ymax - diam, diam, diam, 270 * 64, 90 * 64);
1163 /* upper right */
1164 zXFillArc(tool_d, w, fillgc, xmax - diam, ymin, diam, diam, 0 * 64, 90 * 64);
1165 /* fill strip on left side between upper and lower arcs */
1166 if (ymax - ymin - diam > 0)
1167 zXFillRectangle(tool_d, w, fillgc, xmin, ymin + radius, radius,
1168 ymax - ymin - diam + 1);
1169 /* fill middle section */
1170 if (xmax - xmin - diam > 0)
1171 zXFillRectangle(tool_d, w, fillgc, xmin + radius, ymin,
1172 xmax - xmin - diam + 1, ymax - ymin + 1);
1173 /* fill strip on right side between upper and lower arcs */
1174 if (ymax - ymin - diam > 0)
1175 zXFillRectangle(tool_d, w, fillgc, xmax - radius, ymin + radius,
1176 radius, ymax - ymin - diam + 1);
1177 }
1178 if (line_width == 0)
1179 return;
1180
1181 set_line_stuff(line_width, line_style, style_val, JOIN_MITER, CAP_BUTT,
1182 op, pen_color);
1183 gc = gccache[op];
1184 /* now draw the edges and arc corners */
1185 zXDrawArc(tool_d, w, gc, xmin, ymin, diam, diam, 90 * 64, 90 * 64);
1186 zXDrawLine(tool_d, w, gc, xmin, ymin + radius, xmin, ymax - radius + 1);
1187 zXDrawArc(tool_d, w, gc, xmin, ymax - diam, diam, diam, 180 * 64, 90 * 64);
1188 zXDrawLine(tool_d, w, gc, xmin + radius, ymax, xmax - radius + 1, ymax);
1189 zXDrawArc(tool_d, w, gc, xmax - diam, ymax - diam, diam, diam, 270 * 64, 90 * 64);
1190 zXDrawLine(tool_d, w, gc, xmax, ymax - radius, xmax, ymin + radius - 1);
1191 zXDrawArc(tool_d, w, gc, xmax - diam, ymin, diam, diam, 0 * 64, 90 * 64);
1192 zXDrawLine(tool_d, w, gc, xmax - radius, ymin, xmin + radius - 1, ymin);
1193 }
1194
1195 void
pw_lines(Window w,zXPoint * points,int npoints,int op,int depth,int line_width,int line_style,float style_val,int join_style,int cap_style,int fill_style,Color pen_color,Color fill_color)1196 pw_lines(Window w, zXPoint *points, int npoints, int op, int depth,
1197 int line_width, int line_style, float style_val,
1198 int join_style, int cap_style, int fill_style,
1199 Color pen_color, Color fill_color)
1200 {
1201 register int i;
1202 register XPoint *p;
1203
1204 /* if this depth is inactive, draw the line in gray */
1205 if (draw_parent_gray || (depth < MAX_DEPTH+1 && !active_layer(depth))) {
1206 pen_color = MED_GRAY;
1207 fill_color = LT_GRAY;
1208 }
1209
1210 /* if the line has only one point or it has two points and those points are
1211 coincident AND we are drawing a DOTTED line, this kills Xsun and hangs
1212 other servers.
1213 We will just call pw_point since it is only a point anyway */
1214
1215 if ((npoints == 1) ||
1216 (npoints == 2 && points[0].x == points[1].x && points[0].y == points[1].y)) {
1217 pw_point(w, points[0].x, points[0].y, op, depth, line_width, pen_color, cap_style);
1218 return;
1219 }
1220
1221 if (line_style == PANEL_LINE) {
1222 /* must use XPoint, not our zXPoint */
1223 p = (XPoint *) malloc(npoints * sizeof(XPoint));
1224 for (i=0; i<npoints; i++) {
1225 p[i].x = (short) points[i].x;
1226 p[i].y = (short) points[i].y;
1227 }
1228 }
1229
1230 /* if it's a fill pat we know about, find upper-left corner for pattern origin */
1231 if (fill_style >= 0 && fill_style < NUMFILLPATS) {
1232 int xmin=100000, ymin=100000, i;
1233 if (fill_style >= NUMTINTPATS+NUMSHADEPATS) {
1234 for (i=0; i<npoints; i++) {
1235 xmin = min2(xmin,points[i].x);
1236 ymin = min2(ymin,points[i].y);
1237 }
1238 }
1239 else {
1240 xmin = ymin = 0;
1241 }
1242 set_fill_gc(fill_style, op, pen_color, fill_color, xmin, ymin);
1243 if (line_style == PANEL_LINE) {
1244 XFillPolygon(tool_d, w, fillgc, p, npoints,
1245 Complex, CoordModeOrigin);
1246 } else {
1247 zXFillPolygon(tool_d, w, fillgc, points, npoints,
1248 Complex, CoordModeOrigin);
1249 }
1250 }
1251 if (line_width == 0)
1252 return;
1253 set_line_stuff(line_width, line_style, style_val, join_style, cap_style,
1254 op, pen_color);
1255 if (line_style == PANEL_LINE) {
1256 XDrawLines(tool_d, w, gccache[op], p, npoints, CoordModeOrigin);
1257 free((char *) p);
1258 } else {
1259 zXDrawLines(tool_d, w, gccache[op], points, npoints, CoordModeOrigin);
1260 }
1261 }
1262
set_clip_window(int xmin,int ymin,int xmax,int ymax)1263 void set_clip_window(int xmin, int ymin, int xmax, int ymax)
1264 {
1265 clip_xmin = clip[0].x = xmin;
1266 clip_ymin = clip[0].y = ymin;
1267 clip_xmax = xmax;
1268 clip_ymax = ymax;
1269 clip_width = clip[0].width = xmax - xmin + 1;
1270 clip_height = clip[0].height = ymax - ymin + 1;
1271 XSetClipRectangles(tool_d, border_gc, 0, 0, clip, 1, YXBanded);
1272 XSetClipRectangles(tool_d, gccache[PAINT], 0, 0, clip, 1, YXBanded);
1273 XSetClipRectangles(tool_d, gccache[INV_PAINT], 0, 0, clip, 1, YXBanded);
1274 XSetClipRectangles(tool_d, gccache[ERASE], 0, 0, clip, 1, YXBanded);
1275 }
1276
set_zoomed_clip_window(int xmin,int ymin,int xmax,int ymax)1277 void set_zoomed_clip_window(int xmin, int ymin, int xmax, int ymax)
1278 {
1279 set_clip_window(ZOOMX(xmin), ZOOMY(ymin), ZOOMX(xmax), ZOOMY(ymax));
1280 }
1281
reset_clip_window(void)1282 void reset_clip_window(void)
1283 {
1284 set_clip_window(0, 0, CANVAS_WD, CANVAS_HT);
1285 }
1286
set_fill_gc(int fill_style,int op,int pencolor,int fillcolor,int xorg,int yorg)1287 void set_fill_gc(int fill_style, int op, int pencolor, int fillcolor, int xorg, int yorg)
1288 {
1289 Color fg, bg;
1290
1291 /* see if we need to create this fill style if it is a pattern.
1292 This might have happened if there was a change of zoom. */
1293
1294 if ((fill_style >= NUMSHADEPATS+NUMTINTPATS) &&
1295 ((fill_pm[fill_style] == 0) || (fill_pm_zoom[fill_style] != display_zoomscale)))
1296 rescale_pattern(fill_style);
1297 fillgc = fill_gc[fill_style];
1298 if (op != ERASE) {
1299 /* if a pattern, color the lines in the pen color and the field in fill color */
1300 if (fill_style >= NUMSHADEPATS+NUMTINTPATS) {
1301 fg = x_color(pencolor);
1302 bg = x_color(fillcolor);
1303 } else {
1304 if (fillcolor == BLACK) {
1305 fg = x_color(BLACK);
1306 bg = x_color(WHITE);
1307 } else if (fillcolor == DEFAULT) {
1308 fg = x_fg_color.pixel;
1309 bg = x_bg_color.pixel;
1310 } else {
1311 fg = x_color(fillcolor);
1312 bg = (fill_style < NUMSHADEPATS? x_color(BLACK): x_color(WHITE));
1313 }
1314 }
1315 } else {
1316 fg = x_bg_color.pixel; /* un-fill */
1317 bg = x_bg_color.pixel;
1318 }
1319 XSetForeground(tool_d,fillgc,fg);
1320 XSetBackground(tool_d,fillgc,bg);
1321 /* set stipple from the fill_pm array */
1322 XSetStipple(tool_d, fillgc, fill_pm[fill_style]);
1323 /* set origin of pattern relative to object itself */
1324 XSetTSOrigin(tool_d, fillgc, ZOOMX(xorg), ZOOMY(yorg));
1325 XSetClipRectangles(tool_d, fillgc, 0, 0, clip, 1, YXBanded);
1326 }
1327
1328
1329 static unsigned char dash_list[16][8] = {
1330 {255, 255, 255, 255, 255, 255, 255, 255},
1331 {255, 255, 255, 255, 255, 255, 255, 255},
1332 {255, 255, 255, 255, 255, 255, 255, 255},
1333 {255, 255, 255, 255, 255, 255, 255, 255},
1334 {255, 255, 255, 255, 255, 255, 255, 255},
1335 {255, 255, 255, 255, 255, 255, 255, 255},
1336 {255, 255, 255, 255, 255, 255, 255, 255},
1337 {255, 255, 255, 255, 255, 255, 255, 255},
1338 {255, 255, 255, 255, 255, 255, 255, 255},
1339 {255, 255, 255, 255, 255, 255, 255, 255},
1340 {255, 255, 255, 255, 255, 255, 255, 255},
1341 {255, 255, 255, 255, 255, 255, 255, 255},
1342 {255, 255, 255, 255, 255, 255, 255, 255},
1343 {255, 255, 255, 255, 255, 255, 255, 255},
1344 {255, 255, 255, 255, 255, 255, 255, 255},
1345 {255, 255, 255, 255, 255, 255, 255, 255}};
1346
1347 static int join_styles[3] = { JoinMiter, JoinRound, JoinBevel };
1348 static int cap_styles[3] = { CapButt, CapRound, CapProjecting };
1349
1350 static int ndash_dot = 4;
1351 static float dash_dot[4] = { 1., 0.5, 0., 0.5 };
1352 static int ndash_2dots = 6;
1353 static float dash_2dots[6] = { 1., 0.45, 0., 0.333, 0., 0.45 };
1354 static int ndash_3dots = 8;
1355 static float dash_3dots[8] = { 1., 0.4, 0., 0.3, 0., 0.3, 0., 0.4 };
1356
1357
set_line_stuff(int width,int style,float style_val,int join_style,int cap_style,int op,int color)1358 void set_line_stuff(int width, int style, float style_val, int join_style, int cap_style, int op, int color)
1359 {
1360 XGCValues gcv;
1361 unsigned long mask;
1362
1363 switch (style) {
1364 case RUBBER_LINE:
1365 width = 0;
1366 break;
1367 case PANEL_LINE:
1368 break;
1369 default:
1370 width = round(display_zoomscale * (width > 1 ? width - 1 : 0.5));
1371 break;
1372 }
1373
1374 /* user zero-width lines for speed with SOLID lines */
1375 /* can't do this for dashed lines because server isn't */
1376 /* required to draw dashes for zero-width lines */
1377 if (width == 1 && style == SOLID_LINE)
1378 width = 0;
1379 /* conversely, if the width is calculated to 0 and this is a dashed line, make width 1 */
1380 if (width == 0 && style != SOLID_LINE)
1381 width = 1;
1382
1383 /* see if all gc stuff is already correct */
1384
1385 if (width == gc_thickness[op] && style == gc_line_style[op] &&
1386 join_style == gc_join_style[op] &&
1387 cap_style == gc_cap_style[op] &&
1388 (x_color(color) == gc_color[op]) &&
1389 ((style != DASH_LINE && style != DOTTED_LINE &&
1390 style != DASH_DOT_LINE && style != DASH_2_DOTS_LINE &&
1391 style != DASH_3_DOTS_LINE) ||
1392 dash_list[op][1] == (unsigned char) round(style_val * display_zoomscale)))
1393 return; /* no need to change anything */
1394
1395 gcv.line_width = width;
1396 mask = GCLineWidth | GCLineStyle | GCCapStyle | GCJoinStyle;
1397 if (op == PAINT) {
1398 gcv.foreground = x_color(color);
1399 mask |= GCForeground;
1400 } else if (op == INV_PAINT) {
1401 gcv.foreground = x_color(color) ^ x_bg_color.pixel;
1402 mask |= GCForeground;
1403 }
1404 gcv.join_style = join_styles[join_style];
1405 gcv.cap_style = cap_styles[cap_style];
1406 gcv.line_style = (style == DASH_LINE || style == DOTTED_LINE ||
1407 style == DASH_DOT_LINE || style == DASH_2_DOTS_LINE ||
1408 style == DASH_3_DOTS_LINE) ?
1409 LineOnOffDash : LineSolid;
1410
1411 XChangeGC(tool_d, gccache[op], mask, &gcv);
1412 if (style_val > 0.0) { /* style_val of 0.0 causes problems */
1413 if (style == DASH_LINE || style == DOTTED_LINE) {
1414 /* length of ON/OFF pixels */
1415 if (style_val * display_zoomscale > 255.0)
1416 dash_list[op][0] = dash_list[op][1] = (char) 255; /* too large for X! */
1417 else
1418 dash_list[op][0] = dash_list[op][1] =
1419 (char) round(style_val * display_zoomscale);
1420 /* length of ON pixels for dotted */
1421 if (style == DOTTED_LINE)
1422 dash_list[op][0] = (char)display_zoomscale;
1423
1424 if (dash_list[op][0]==0) /* take care for rounding to zero ! */
1425 dash_list[op][0]=1;
1426 if (dash_list[op][1]==0) /* take care for rounding to zero ! */
1427 dash_list[op][1]=1;
1428 XSetDashes(tool_d, gccache[op], 0, (char *) dash_list[op], 2);
1429 } else if (style == DASH_DOT_LINE || style == DASH_2_DOTS_LINE ||
1430 style == DASH_3_DOTS_LINE) {
1431 int il, nd;
1432 float *fl;
1433 if (style == DASH_2_DOTS_LINE) {
1434 fl=dash_2dots;
1435 nd=ndash_2dots;
1436 } else if (style == DASH_3_DOTS_LINE) {
1437 fl=dash_3dots;
1438 nd=ndash_3dots;
1439 } else {
1440 fl=dash_dot;
1441 nd=ndash_dot;
1442 }
1443 for (il =0; il<nd; il ++) {
1444 if (fl[il] != 0.) {
1445 if (fl[il] * style_val * display_zoomscale > 255.0)
1446 dash_list[op][il] = (char) 255; /* too large for X! */
1447 else
1448 dash_list[op][il] = (char) round(fl[il] * style_val *
1449 display_zoomscale);
1450 } else {
1451 dash_list[op][il] = (char)display_zoomscale;
1452 }
1453 if (dash_list[op][il]==0) /* take care for rounding to zero ! */
1454 dash_list[op][il]=1;
1455 }
1456 XSetDashes(tool_d, gccache[op], 0, (char *) dash_list[op], nd);
1457 }
1458 }
1459 gc_thickness[op] = width;
1460 gc_line_style[op] = style;
1461 gc_join_style[op] = join_style;
1462 gc_cap_style[op] = cap_style;
1463 gc_color[op] = x_color(color);
1464 }
1465
1466 int
x_color(int col)1467 x_color(int col)
1468 {
1469 int pix;
1470 if (!all_colors_available) {
1471 pix = colors[BLACK];
1472 } else if (col == LT_GRAY) {
1473 pix = lt_gray_color;
1474 } else if (col == DARK_GRAY) {
1475 pix = dark_gray_color;
1476 } else if (col == MED_GRAY) {
1477 pix = med_gray_color;
1478 } else if (col == TRANSP_BACKGROUND) {
1479 pix = med_gray_color;
1480 } else if (col == COLOR_NONE) {
1481 pix = colors[WHITE];
1482 } else if (col==WHITE) {
1483 pix = colors[WHITE];
1484 } else if (col==BLACK) {
1485 pix = colors[BLACK];
1486 } else if (col==DEFAULT) {
1487 pix = x_fg_color.pixel;
1488 } else if (col==CANVAS_BG) {
1489 pix = x_bg_color.pixel;
1490 } else {
1491 if (col < 0)
1492 col = BLACK;
1493 if (col >= NUM_STD_COLS+num_usr_cols)
1494 pix = x_fg_color.pixel;
1495 else
1496 pix = colors[col];
1497 }
1498 return pix;
1499 }
1500
1501 /* resize the fill patterns for the current display_zoomscale */
1502 /* also generate new Pixmaps in fill_pm[] */
1503
rescale_pattern(int patnum)1504 void rescale_pattern(int patnum)
1505 {
1506 int j;
1507 XGCValues gcv;
1508
1509 /* this make a few seconds (depending on the machine) */
1510 set_temp_cursor(wait_cursor);
1511 j = patnum-(NUMSHADEPATS+NUMTINTPATS);
1512 /* first rescale the data */
1513 scale_pattern(j);
1514 /* free any old pixmaps before creating new ones */
1515 if (fill_pm[patnum]) {
1516 XFreePixmap(tool_d,fill_pm[patnum]);
1517 }
1518 fill_pm[patnum] = XCreateBitmapFromData(tool_d, tool_w,
1519 pattern_images[j].cdata,
1520 pattern_images[j].cwidth,
1521 pattern_images[j].cheight);
1522 /* set the zoom value so we know what zoom it was generated for */
1523 fill_pm_zoom[patnum] = display_zoomscale;
1524 /* now update the gc to use the new pixmaps */
1525 if (fill_gc[patnum]) {
1526 gcv.stipple = fill_pm[patnum];
1527 XChangeGC(tool_d, fill_gc[patnum], GCStipple, &gcv);
1528 }
1529 reset_cursor();
1530 }
1531
scale_pattern(int indx)1532 void scale_pattern(int indx)
1533 {
1534 int i;
1535 int j;
1536 char *odata;
1537 char *ndata;
1538 int nbytes;
1539 int obytes;
1540 int ibit;
1541 int jbit;
1542 int wbit;
1543 int width, height;
1544 int nwidth, nheight;
1545
1546 width = pattern_images[indx].owidth;
1547 height = pattern_images[indx].oheight;
1548
1549 nwidth = display_zoomscale * width;
1550 nheight = display_zoomscale * height;
1551
1552 /* if already correct size just return */
1553 if (nwidth ==pattern_images[indx].cwidth &&
1554 nheight==pattern_images[indx].cheight)
1555 return;
1556
1557 /* prevent 0-size bitmaps */
1558 if (nwidth == 0)
1559 nwidth = 1;
1560 if (nheight == 0)
1561 nheight = 1;
1562
1563 obytes = (width + 7) / 8;
1564 nbytes = (nwidth + 7) / 8;
1565
1566 odata = pattern_images[indx].odata;
1567 ndata = pattern_images[indx].cdata;
1568 /* if was already scaled before free that data */
1569 if (ndata)
1570 free(ndata);
1571 /* allocate new space for zoomed bytes */
1572 pattern_images[indx].cdata = ndata = (char *) malloc(nbytes * nheight);
1573 memset(ndata, 0, (size_t)(nbytes * nheight));
1574
1575 /* create a new bitmap at the specified size (requires interpolation) */
1576 if (nwidth >= width) { /* new is larger, loop over its matrix */
1577 for (j = 0; j < nheight; j++) {
1578 jbit = height * j / nheight * obytes;
1579 for (i = 0; i < nwidth; i++) {
1580 ibit = width * i / nwidth; /* xy bit position from original bitmap */
1581 wbit = *(odata + jbit + ibit / 8);
1582 if (wbit & (1 << (ibit & 7)))
1583 *(ndata + j * nbytes + i / 8) |= (1 << (i & 7));
1584 }
1585 }
1586 } else { /* new is smaller, loop over orig matrix so we don't lose bits */
1587 for (j = 0; j < height; j++) {
1588 jbit = nheight * j / height * nbytes;
1589 for (i = 0; i < width; i++) {
1590 ibit = nwidth * i / width; /* xy bit position from new bitmap */
1591 wbit = *(odata + j * obytes + i / 8);
1592 if (wbit & (1 << (i & 7)))
1593 *(ndata + jbit + ibit / 8) |= (1 << (ibit & 7));
1594 }
1595 }
1596 }
1597 pattern_images[indx].cwidth = nwidth;
1598 pattern_images[indx].cheight = nheight;
1599 }
1600
1601 /* storage for conversion of data points to screen coords (zXDrawLines and zXFillPolygon) */
1602
1603 static XPoint *_pp_ = (XPoint *) NULL; /* data pointer itself */
1604 static int _npp_ = 0; /* number of points currently allocated */
1605 static Boolean _noalloc_ = False; /* signals previous failed alloc */
1606 static Boolean chkalloc(int n);
1607 static void convert_sh(zXPoint *p, int n);
1608
zXDrawLines(Display * d,Window w,GC gc,zXPoint * points,int n,int coordmode)1609 void zXDrawLines(Display *d, Window w, GC gc, zXPoint *points, int n, int coordmode)
1610 {
1611 #ifdef CLIP_LINE
1612 XPoint *outp;
1613 #endif /* CLIP_LINE */
1614
1615 /* make sure we have allocated data */
1616 if (!chkalloc(n)) {
1617 return;
1618 }
1619 /* now convert each point to short into _pp_ */
1620 convert_sh(points, n);
1621 #ifdef CLIP_LINE
1622 outp = (XPoint *) malloc(2*n*sizeof(XPoint));
1623 n = clip_poly(_pp_, n, outp);
1624 XDrawLines(d, w, gc, outp, n, coordmode);
1625 #else
1626 XDrawLines(d, w, gc, _pp_, n, coordmode);
1627 #endif /* CLIP_LINE */
1628 }
1629
zXFillPolygon(Display * d,Window w,GC gc,zXPoint * points,int n,int complex,int coordmode)1630 void zXFillPolygon(Display *d, Window w, GC gc, zXPoint *points, int n, int complex, int coordmode)
1631 {
1632 XPoint *outp;
1633
1634 /* make sure we have allocated data for _pp_ */
1635 if (!chkalloc(n)) {
1636 return;
1637 }
1638 /* now convert each point to short into _pp_ */
1639 convert_sh(points, n);
1640 outp = (XPoint *) malloc(2*n*sizeof(XPoint));
1641 n = clip_poly(_pp_, n, outp);
1642 XFillPolygon(d, w, gc, outp, n, complex, coordmode);
1643 free(outp);
1644 }
1645
1646 /* convert each point to short */
1647
1648 static void
convert_sh(zXPoint * p,int n)1649 convert_sh(zXPoint *p, int n)
1650 {
1651 int i;
1652
1653 for (i=0; i<n; i++) {
1654 _pp_[i].x = ZOOMX(p[i].x);
1655 _pp_[i].y = ZOOMY(p[i].y);
1656 }
1657 }
1658
1659 static Boolean
chkalloc(int n)1660 chkalloc(int n)
1661 {
1662 int i;
1663 XPoint *tpp;
1664
1665 /* see if we need to allocate some (more) memory */
1666 if (n > _npp_) {
1667 /* if previous allocation failed, return now */
1668 if (_noalloc_)
1669 return False;
1670 /* get either what we need +50 points or 500, whichever is larger */
1671 i = max2(n+50, 500);
1672 if (_npp_ == 0) {
1673 if ((tpp = (XPoint *) malloc(i * sizeof(XPoint))) == 0) {
1674 fprintf(stderr,"\007Can't alloc memory for %d point array, exiting\n",i);
1675 exit(1);
1676 }
1677 } else {
1678 if ((tpp = (XPoint *) realloc(_pp_, i * sizeof(XPoint))) == 0) {
1679 file_msg("Can't alloc memory for %d point array",i);
1680 _noalloc_ = True;
1681 return False;
1682 }
1683 }
1684 /* everything ok, set global pointer and count */
1685 _pp_ = tpp;
1686 _npp_ = i;
1687 }
1688 return True;
1689 }
1690
1691 /*
1692 * clip_poly - This procedure performs the Sutherland-Hodgman polygon clipping
1693 * on the inVertices array, putting the resultant points into the outVertices array,
1694 * and returning the number of points as the return value.
1695 * We are clipping to the canvas area.
1696 */
1697
1698 static int
clip_poly(XPoint * inVertices,int npoints,XPoint * outVertices)1699 clip_poly(XPoint *inVertices, int npoints, XPoint *outVertices)
1700 {
1701 /* clip to left edge */
1702 npoints = SutherlandHodgmanPolygoClip (inVertices, outVertices, npoints,
1703 -100, CANVAS_HT*2, -100, -100);
1704 setup_next(npoints, inVertices, outVertices);
1705 /* now to bottom edge */
1706 npoints = SutherlandHodgmanPolygoClip (inVertices,outVertices, npoints,
1707 -100, CANVAS_HT*2, CANVAS_WD*2, CANVAS_HT*2);
1708 setup_next(npoints, inVertices, outVertices);
1709 /* right edge */
1710 npoints = SutherlandHodgmanPolygoClip (inVertices,outVertices, npoints,
1711 CANVAS_WD*2, -100, CANVAS_WD*2, CANVAS_HT*2);
1712 setup_next(npoints, inVertices, outVertices);
1713 /* top edge */
1714 npoints = SutherlandHodgmanPolygoClip (inVertices,outVertices, npoints,
1715 CANVAS_WD*2, -100, -100, -100);
1716 setup_next(npoints, inVertices, outVertices);
1717 return npoints;
1718 }
1719
1720 /*
1721 * The "SutherlandHodgmanPolygoClip" function is a critical function of the
1722 * polygon clipping. It uses the Sutherland_Hodgman algorithm to implement
1723 * a step in clipping a polygon to a clipping window.
1724 */
1725
1726 int
SutherlandHodgmanPolygoClip(XPoint * inVertices,XPoint * outVertices,int inLength,int x1,int y1,int x2,int y2)1727 SutherlandHodgmanPolygoClip (
1728 XPoint *inVertices, /* Input vertex array */
1729 XPoint *outVertices, /* Output vertex array */
1730 int inLength, /* Number of entries in inVertices */
1731 int x1, int y1, int x2, int y2) /* Edge of clip polygon */
1732 {
1733 XPoint s,p; /*Start, end point of current polygon edge*/
1734 XPoint i; /*Intersection point with a clip boundary*/
1735 int j; /*Vertex loop counter*/
1736 int outpts; /* number of points in output array */
1737
1738 outpts = 0;
1739 s.x = inVertices[inLength-1].x; /*Start with the last vertex in inVertices*/
1740 s.y = inVertices[inLength-1].y;
1741 for (j=0; j < inLength; j++) {
1742 p.x = inVertices[j].x; /*Now s and p correspond to the vertices*/
1743 p.y = inVertices[j].y;
1744 if (inside(p,x1, y1, x2, y2)) { /*Cases 1 and 4*/
1745 if (inside(s, x1, y1, x2, y2)) {
1746 outVertices[outpts].x = p.x;
1747 outVertices[outpts].y = p.y;
1748 outpts++;
1749 } else { /*Case 4*/
1750 intersect(s, p, x1, y1, x2, y2, &i);
1751 outVertices[outpts].x = i.x;
1752 outVertices[outpts].y = i.y;
1753 outpts++;
1754 outVertices[outpts].x = p.x;
1755 outVertices[outpts].y = p.y;
1756 outpts++;
1757 }
1758 } else { /*Cases 2 and 3*/
1759 if (inside(s, x1, y1, x2, y2)) /*Cases 2*/ {
1760 intersect(s, p, x1, y1, x2, y2, &i);
1761 outVertices[outpts].x = i.x;
1762 outVertices[outpts].y = i.y;
1763 outpts++;
1764 }
1765 } /*No action for case 3*/
1766 s.x = p.x; /*Advance to next pair of vertices*/
1767 s.y = p.y;
1768 }
1769 return outpts;
1770 } /*SutherlandHodgmanPolygonClip*/
1771
1772 /*
1773 * The "Inside" function returns TRUE if the vertex tested is on the inside
1774 * of the clipping boundary. "Inside" is defined as "to the left of
1775 * clipping boundary when one looks from the first vertex to the second
1776 * vertex of the clipping boundary". The code for this function is:
1777 */
1778
1779 static Boolean
inside(XPoint testVertex,int x1,int y1,int x2,int y2)1780 inside (XPoint testVertex, int x1, int y1, int x2, int y2)
1781 {
1782 if (x2 > x1) /*bottom edge*/
1783 if (testVertex.y <= y1)
1784 return True;
1785 if (x2 < x1) /*top edge*/
1786 if (testVertex.y >= y1)
1787 return True;
1788 if (y2 > y1) /*right edge*/
1789 if (testVertex.x <= x2)
1790 return True;
1791 if (y2 < y1) /*left edge*/
1792 if (testVertex.x >= x2)
1793 return True;
1794 /* outside */
1795 return False;
1796 }
1797
1798 /*
1799 * The "intersect" function calculates the intersection of the polygon edge
1800 * (vertex s to p) with the clipping boundary.
1801 */
1802
1803 static void
intersect(XPoint first,XPoint second,int x1,int y1,int x2,int y2,XPoint * intersectPt)1804 intersect(XPoint first, XPoint second, int x1, int y1, int x2, int y2,
1805 XPoint *intersectPt)
1806 {
1807 if (y1 == y2) { /*horizontal*/
1808 intersectPt->y=y1;
1809 intersectPt->x=first.x +(y1-first.y)*
1810 (second.x-first.x)/(second.y-first.y); /*Vertical*/
1811 } else {
1812 intersectPt->x=x1;
1813 intersectPt->y=first.y +(x1-first.x)*
1814 (second.y-first.y)/(second.x-first.x);
1815 }
1816 }
1817
1818 /*
1819 * setup_next copies the input to the output
1820 */
1821
1822 static void
setup_next(int npoints,XPoint * in,XPoint * out)1823 setup_next(int npoints, XPoint *in, XPoint *out)
1824 {
1825 int i;
1826 for (i=0; i<npoints; i++) {
1827 in[i].x = out[i].x;
1828 in[i].y = out[i].y;
1829 }
1830 }
1831
1832
1833 /*
1834 * clip_line - This procedure clips a line to the current clip boundaries and
1835 * returns the new coordinates in x3, y3 and x4, y4.
1836 * If the line lies completely outside of the clip boundary, the result is False,
1837 * otherwise True.
1838 * This procedure uses the well known Cohen-Sutherland line clipping
1839 * algorithm to clip each coordinate.
1840 */
1841
1842 int compoutcode(int x, int y);
1843
1844 /* bitfields for output codes */
1845 #define codetop 1
1846 #define codebottom 2
1847 #define coderight 4
1848 #define codeleft 8
1849
1850 void
clip_line(int x1,int y1,int x2,int y2,short * x3,short * y3,short * x4,short * y4)1851 clip_line(int x1, int y1, int x2, int y2, short *x3, short *y3, short *x4, short *y4)
1852 {
1853 int outcode0; /* the code of the first endpoint */
1854 int outcode1; /* the code of the second endpoint */
1855 int outcodeout;
1856 int x, y;
1857
1858 outcode0 = compoutcode(x1, y1); /* compute the original codes */
1859 outcode1 = compoutcode(x2, y2);
1860
1861 /* while not trivially accepted */
1862 while (outcode0 != 0 || outcode1 != 0) {
1863 if ((outcode0 & outcode1) != 0) { /* trivial reject */
1864 /* set line to a single point at the limits of the screen */
1865 if ((outcode0|outcode1) & codebottom) *y3 = *y4 = CANVAS_HT;
1866 if ((outcode0|outcode1) & codetop) *y3 = *y4 = 0;
1867 if ((outcode0|outcode1) & codeleft) *x3 = *x4 = 0;
1868 if ((outcode0|outcode1) & coderight) *x3 = *x4 = CANVAS_WD;
1869 return;
1870 } else {
1871 /* failed both tests, so calculate the line segment to clip */
1872 if (outcode0 > 0 )
1873 outcodeout = outcode0; /* clip the first point */
1874 else
1875 outcodeout = outcode1; /* clip the last point */
1876
1877 if ((outcodeout & codebottom) == codebottom) {
1878 /* clip the line to the bottom of the viewport */
1879 y = CANVAS_HT;
1880 x = x1+(double)(x2-x1)*(double)(y-y1) / (y2 - y1);
1881 }
1882 else if ((outcodeout & codetop) == codetop ) {
1883 /* clip the line to the top of the viewport */
1884 y = 0;
1885 x = x1+(double)(x2-x1)*(double)(y-y1) / (y2 - y1);
1886 }
1887 else if ((outcodeout & coderight) == coderight ) {
1888 /* clip the line to the right edge of the viewport */
1889 x = CANVAS_WD;
1890 y = y1+(double)(y2-y1)*(double)(x-x1) / (x2-x1);
1891 }
1892 else if ((outcodeout & codeleft) == codeleft ) {
1893 /* clip the line to the left edge of the viewport */
1894 x = 0;
1895 y = y1+(double)(y2-y1)*(double)(x-x1) / (x2-x1);
1896 };
1897
1898 if (outcodeout == outcode0) { /* modify the first coordinate */
1899 x1 = x; y1 = y; /* update temporary variables */
1900 outcode0 = compoutcode(x1, y1); /* recalculate the outcode */
1901 }
1902 else {
1903 /* modify the second coordinate */
1904 x2 = x; y2 = y; /* update temporary variables */
1905 outcode1 = compoutcode(x2, y2); /* recalculate the outcode */
1906 }
1907 }
1908 }
1909
1910 /* coordinates for the new line! */
1911 *x3 = (short) x1;
1912 *y3 = (short) y1;
1913 *x4 = (short) x2;
1914 *y4 = (short) y2;
1915
1916 return;
1917 }
1918
1919 /* return codes for different cases */
1920
1921 int
compoutcode(int x,int y)1922 compoutcode(int x, int y)
1923 {
1924 int code = 0;
1925
1926 if (y > CANVAS_HT) code = codebottom;
1927 else if (y < 0) code = codetop;
1928
1929 if (x > CANVAS_WD) code = code+coderight;
1930 else if (x < 0) code = code+codeleft;
1931 return code;
1932 }
1933
1934