1 /*
2    Copyright (c) 1991 - 1994 Heinz W. Werntges.  All rights reserved.
3    Distributed by Free Software Foundation, Inc.
4 
5 This file is part of HP2xx.
6 
7 HP2xx is distributed in the hope that it will be useful, but
8 WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
9 to anyone for the consequences of using it or for whether it serves any
10 particular purpose or works at all, unless he says so in writing.  Refer
11 to the GNU General Public License, Version 2 or later, for full details.
12 
13 Everyone is granted permission to copy, modify and redistribute
14 HP2xx, but only under the conditions described in the GNU General Public
15 License.  A copy of this license is supposed to have been
16 given to you along with HP2xx so you can know your rights and
17 responsibilities.  It should be in a file named COPYING.  Among other
18 things, the copyright notice and this notice must be preserved on all
19 copies.
20 
21 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
22 */
23 
24 /** picbuf.c: Part of hp2xx project dealing with the picture buffer
25  **
26  ** 91/01/19  V 1.00  HWW  Derived from hptopcl.c
27  ** 91/01/29  V 1.01  HWW  Tested on SUN
28  ** 91/02/15  V 1.02  HWW  stdlib.h supported
29  ** 91/02/20  V 1.03a HWW  minor mod. in fread(); adaptation to
30  **			   new HPGL_Pt structures in tmpfile_to_PicBuf()
31  ** 91/06/09  V 1.04  HWW  new options acknowledged; minimal changes
32  ** 91/10/15  V 1.05  HWW  ANSI_C
33  ** 91/11/20  V 1.06  HWW  "SPn;" consequences
34  ** 92/02/17  V 1.07b HWW  Preparations for font support
35  ** 92/05/24  V 2.00c HWW  Color supported! Fonts ok now; "init" bug fixed
36  ** 92/06/08  V 2.00d HWW  GIVE_BACK: 5 --> 8; free_PicBuf() debugged
37  ** 92/12/24  V 2.00e HWW  plot_RowBuf() augmented to bit REsetting
38  ** 93/04/02  V 2.01a HWW  Always use four bit planes in color mode!
39  **			   Out-dated "DotBlock" concept replaced by "char".
40  ** 94/02/14  V 2.10  HWW  New parameter structs; restructured
41  **			   Improved cleanup & error handling
42  ** 00/07/16          MK   Modify pensize correction in size_Pixbuf
43  **                        for new .1 pixel pensize unit scheme (G.B.)
44  **/
45 
46 
47 #include <stdio.h>
48 #include <stdlib.h>
49 #ifndef _NO_VCL
50 #include <unistd.h>
51 #endif
52 #include <string.h>
53 #include <math.h>
54 #include "bresnham.h"
55 #include "murphy.h"
56 #include "pendef.h"
57 #include "lindef.h"
58 #include "picbuf.h"
59 #include "hp2xx.h"
60 #include "hpgl.h"
61 
62 
63 static RowBuf *first_buf = NULL, *last_buf = NULL;
64 
65 static int X_Offset = 0;
66 static int Y_Offset = 0;
67 
68 #ifndef SEEK_SET
69 #define SEEK_SET 0
70 #endif
71 
72 
73 
swapout_RowBuf(RowBuf * row,const PicBuf * picbuf)74 static void swapout_RowBuf(RowBuf * row, const PicBuf * picbuf)
75 {
76 	if (fseek
77 	    (picbuf->sd, (long) row->index * picbuf->nb * picbuf->depth,
78 	     SEEK_SET)) {
79 		PError("swapout_RowBuf (on seek)");
80 		exit(ERROR);
81 	}
82 
83 	if ((int)
84 	    fwrite((char *) row->buf, (size_t) picbuf->nb,
85 		   (size_t) picbuf->depth, picbuf->sd)
86 	    != picbuf->depth) {
87 		PError("swapout_RowBuf (on write)");
88 		exit(ERROR);
89 	}
90 }
91 
92 
93 
swapin_RowBuf(RowBuf * row,const PicBuf * picbuf)94 static void swapin_RowBuf(RowBuf * row, const PicBuf * picbuf)
95 {
96 	if (fseek
97 	    (picbuf->sd, (long) row->index * picbuf->nb * picbuf->depth,
98 	     SEEK_SET)) {
99 		PError("swapin_RowBuf (on seek)");
100 		exit(ERROR);
101 	}
102 
103 	if ((int)
104 	    fread((char *) row->buf, (size_t) picbuf->nb,
105 		  (size_t) picbuf->depth, picbuf->sd)
106 	    != picbuf->depth) {
107 		PError("swapin_RowBuf (on read)");
108 		exit(ERROR);
109 	}
110 }
111 
112 
113 
114 
115 
link_RowBuf(RowBuf * act,RowBuf * prev)116 static void link_RowBuf(RowBuf * act, RowBuf * prev)
117 {
118 	if (prev == NULL) {	/* Make act the new "first_buf"   */
119 		if (first_buf == NULL) {
120 			first_buf = act;
121 			act->next = act->prev = NULL;
122 			return;
123 		}
124 		act->next = first_buf;
125 		act->prev = NULL;
126 		first_buf->prev = act;
127 		first_buf = act;
128 	} else {		/* Squeeze act between prev & prev->next */
129 
130 		if ((act->next = prev->next) != NULL)
131 			act->next->prev = act;
132 		act->prev = prev;
133 		prev->next = act;
134 	}
135 }
136 
137 
138 
139 
140 
unlink_RowBuf(RowBuf * act)141 static void unlink_RowBuf(RowBuf * act)
142 {
143 	if ((act->prev == NULL) && (act->next == NULL))
144 		return;
145 
146 	if (act->prev)
147 		act->prev->next = act->next;
148 	else
149 		first_buf = act->next;
150 
151 	if (act->next)
152 		act->next->prev = act->prev;
153 	else
154 		last_buf = act->prev;
155 
156 	act->next = act->prev = NULL;
157 }
158 
159 
160 
161 
get_RowBuf(const PicBuf * pb,int index)162 RowBuf *get_RowBuf(const PicBuf * pb, int index)
163 {
164 	RowBuf *row;
165 
166 	if (pb == NULL)
167 		return NULL;
168 	if (index < 0 || index >= pb->nr) {
169 		Eprintf("get_RowBuf: Illegal y (%d not in [0, %d])\n",
170 			index, pb->nr - 1);
171 		return NULL;
172 	}
173 
174 	row = pb->row + index;
175 
176 /**
177  ** If swapped, load first. Put into first position, if not already there:
178  **/
179 	if ((row->prev == NULL) && (row->next == NULL)) {
180 		swapout_RowBuf(last_buf, pb);
181 		row->buf = last_buf->buf;
182 		unlink_RowBuf(last_buf);	/* Mark as swapped       */
183 		swapin_RowBuf(row, pb);
184 		link_RowBuf(row, NULL);	/* Put in first position */
185 	} else if (row->prev != NULL) {
186 		unlink_RowBuf(row);
187 		link_RowBuf(row, NULL);	/* Put in first position */
188 	}
189 	/* else: Leave it in first position */
190 
191 	return row;
192 }
193 
194 
195 
196 
197 
plot_RowBuf(RowBuf * rowbuf,int x,int depth,PEN_C color_index)198 static void plot_RowBuf(RowBuf * rowbuf, int x, int depth,
199 			PEN_C color_index)
200 /**
201  ** Write color index into pixel x of given row buffer
202  **/
203 {
204 	int i, Mask;
205 	Byte *addr;
206 
207 	if (rowbuf == NULL)
208 		return;
209 /**
210  ** Color_index is either the low bit (b/w) or the low nybble (color)
211  ** rowbuf->buf is either a sequence of such bits or nybbles.
212  ** High bits show left, low bits show right.
213  **
214  ** This is a time-critical step, so code here is compact,
215  ** but not easily readable...
216  **/
217 
218 	if (depth == 1) {
219 		if (color_index > 1)
220 			color_index = 1;
221 		Mask = 0x80;
222 		if ((i = x & 0x07) != 0) {
223 			Mask >>= i;
224 			if (i != 7)
225 				color_index <<= (7 - i);
226 		} else
227 			color_index <<= 7;
228 		addr = rowbuf->buf + (x >> 3);
229 	} else if (depth == 4) {
230 		Mask = 0xF0;
231 		if ((x & 0x01) != 0)
232 			Mask >>= 4;
233 		else
234 			color_index <<= 4;
235 		addr = rowbuf->buf + (x >> 1);
236 	} else {
237 		addr = rowbuf->buf + x;
238 		Mask = 0x00;
239 	}
240 	if (depth < 8) {
241 		*addr &= ~Mask;
242 		*addr |= color_index;
243 	} else
244 		*addr = (Byte) color_index;
245 }
246 
247 
248 
249 
250 
index_from_RowBuf(const RowBuf * rowbuf,int x,const PicBuf * pb)251 int index_from_RowBuf(const RowBuf * rowbuf, int x, const PicBuf * pb)
252 /**
253  ** Return color index of pixel x in given row
254  **/
255 {
256 	int i, Mask, color_index;
257 	Byte *addr;
258 
259 	if (pb->depth == 1) {
260 		Mask = 0x80;
261 		if ((i = x & 0x07) != 0)
262 			Mask >>= i;
263 		addr = rowbuf->buf + (x >> 3);
264 		return (*addr & Mask) ? xxForeground : xxBackground;
265 	} else if (pb->depth == 4) {
266 		Mask = 0xF0;
267 		if ((x & 0x01) != 0)
268 			Mask >>= 4;
269 		addr = rowbuf->buf + (x >> 1);
270 		color_index = *addr & Mask;
271 		if ((x & 0x01) == 0)
272 			color_index >>= 4;
273 		return color_index;
274 	} else {
275 		addr = rowbuf->buf + x;
276 		color_index = *addr;
277 		return color_index;
278 	}
279 }
280 
281 
282 
283 
284 
285 static void
HPcoord_to_dotcoord(const HPGL_Pt * HP_P,DevPt * DevP,const OUT_PAR * po)286 HPcoord_to_dotcoord(const HPGL_Pt * HP_P, DevPt * DevP, const OUT_PAR * po)
287 {
288 	DevP->x = (int) ((HP_P->x - po->xmin) * po->HP_to_xdots);
289 	DevP->y = (int) ((HP_P->y - po->ymin) * po->HP_to_ydots);
290 }
291 
292 
293 
size_PicBuf(const GEN_PAR * pg,const OUT_PAR * po,int * p_rows,int * p_cols)294 void size_PicBuf(const GEN_PAR * pg, const OUT_PAR * po, int *p_rows,
295 		 int *p_cols)
296 {
297 	HPGL_Pt HP_Pt;
298 	DevPt D_Pt;
299 	int maxps;
300 
301 	HP_Pt.x = po->xmax;
302 	HP_Pt.y = po->ymax;
303 	HPcoord_to_dotcoord(&HP_Pt, &D_Pt, po);
304 	/* Pensize correction */
305 /*  maxps= (int)(1. + pg->maxpensize *po->HP_to_xdots/0.025); */
306 	maxps = 1 + ceil(pg->maxpensize * po->HP_to_xdots / 0.025);
307 	X_Offset = maxps / 2;
308 	Y_Offset = maxps / 2;
309 
310 /*   printf("maxps = %d\n",maxps);*/
311 	*p_cols = D_Pt.x + maxps + 1;
312 	*p_rows = D_Pt.y + maxps + 1;
313 }
314 
315 
allocate_PicBuf(const GEN_PAR * pg,int n_rows,int n_cols)316 PicBuf *allocate_PicBuf(const GEN_PAR * pg, int n_rows, int n_cols)
317 /**
318  ** Here we allocate the picture buffer. This memory is used by all raster
319  ** modes. It is organized in rows (scan lines). Rows which do not
320  ** end on a byte boundary will be right-padded with "background" bits.
321  **
322  ** If colors are active, there will always be "four bit" layers per row,
323  ** even if you need only three colors.
324  ** These layers are implemented by allocating longer rows
325  ** (regular length times number of bit planes per pel (depth)).
326  **
327  ** We try to allocate all row buffers from main memory first.
328  ** If allocation fails, we first free a few lines (see constant GIVE_BACK)
329  ** to avoid operation close to the dyn. memory limit,
330  ** and then initiate swapping to a file.
331  **/
332 {
333 	PicBuf *pb;
334 	RowBuf *prev, *act;
335 	int nr, not_allocated;
336 #define	GIVE_BACK 8
337 
338 	if ((pb = (PicBuf *) malloc(sizeof(*pb))) == NULL) {
339 		Eprintf("Cannot malloc() PicBuf structure\n");
340 		return NULL;
341 	}
342 
343 	pb->nr = n_rows;
344 	pb->nc = n_cols;
345 	pb->sd = NULL;
346 	pb->sf_name = NULL;
347 	pb->row = NULL;
348 	first_buf = NULL;	/* Re-init for multiple-file    */
349 	last_buf = NULL;	/* applications                 */
350 
351 /**
352  ** Number of buffer bytes per row:
353  **
354  ** Example:
355  **
356  ** dot range (horiz.): 0...2595 ==> 2596 dots per row, pb->nc=2096 ==>
357  ** 	[2596 bits / 8 bits per byte]
358  ** ==> 324 DotBlocks + 4 bits which require another whole byte (!)
359  **/
360 
361 	pb->nb = (pb->nc >> 3);
362 	if (pb->nc & 7)
363 		pb->nb++;
364 
365 /**
366  ** Auto-detection of depth (# bits per pel):
367  **
368  ** B/W mode      (1 bit per pel, Foreground & Background),
369  ** or color mode (4 bits per pel)
370  **/
371 
372 	pb->depth = (pg->is_color) ? 4 : 1;
373 	if (pg->is_color && pg->maxcolor > 15) {
374 		pb->depth = 8;
375 		if (!pg->quiet)
376 			fprintf(stderr, "using 8bpp picbuf for NP>15\n");
377 	}
378 /**
379  ** Allocate a (large) array of RowBuf structures: One for each scan line.
380  ** !!! The NULL initialization done implicitly by calloc() is crucial !!!
381  **/
382 
383 	if ((pb->row =
384 	     (RowBuf *) calloc((unsigned) pb->nr, sizeof(RowBuf)))
385 	    == NULL) {
386 		Eprintf("Cannot calloc() %d RowBuf structures\n", pb->nr);
387 		free_PicBuf(pb);
388 		return NULL;
389 	}
390 
391 /**
392  ** Now try to allocate as many buffers as possible. Double-link all RowBuf's
393  ** which succeed in buffer allocation, leave the rest isolated (swapping
394  ** candidates!)
395  **/
396 
397 	not_allocated = 0;
398 	prev = (RowBuf *) NULL;
399 	for (nr = 0, act = pb->row; nr < pb->nr; nr++, act++) {
400 		act->prev = act->next = NULL;
401 		act->index = nr;
402 		if ((act->buf =
403 		     (Byte *) calloc((unsigned) (pb->nb * pb->depth),
404 				     1)) == NULL)
405 			not_allocated++;
406 		else {
407 			link_RowBuf(act, prev);
408 			prev = act;
409 			last_buf = act;
410 		}
411 	}
412 
413 /**
414  ** Prepare swapping
415  **/
416 
417 	if (not_allocated) {
418 		if (last_buf->index > GIVE_BACK)
419 			for (nr = 0; nr < GIVE_BACK; nr++) {
420 				/* Return some memory for internal use */
421 				free((char *) last_buf->buf);
422 				unlink_RowBuf(last_buf);
423 				not_allocated++;
424 		} else {
425 			Eprintf
426 			    ("\nNot enough memory for swapping -- sorry!\n");
427 			free_PicBuf(pb);
428 			return NULL;
429 		}
430 
431 		Eprintf("\nCouldn't allocate %d out of %d row buffers.\n",
432 			not_allocated, pb->nr);
433 		Eprintf("Swapping to disk...\n");
434 		pb->sf_name = pg->swapfile;
435 		if ((pb->sd = fopen(pb->sf_name, WRITE_BIN)) == NULL) {
436 			Eprintf("Couldn't open swap file '%s'\n",
437 				pb->sf_name);
438 			PError("hp2xx");
439 			free_PicBuf(pb);
440 			return NULL;
441 		}
442 
443 /**
444  ** Init. swap file data to background color (0), using a shortcut by
445  ** assuming that all data are stored without gaps. Thus, instead of
446  ** row-by-row operation, we simply write a sufficient number of 0 rows
447  ** into the swap file sequentially.
448  **/
449 
450 		for (nr = 0; nr < pb->nr; nr++)
451 			if ((int)
452 			    fwrite((char *) pb->row[0].buf,
453 				   (size_t) pb->nb, (size_t) pb->depth,
454 				   pb->sd)
455 			    != pb->depth) {
456 				Eprintf("Couldn't clear swap file!\n");
457 				PError("hp2xx");
458 				free_PicBuf(pb);
459 				return NULL;
460 			}
461 	}
462 	return pb;
463 }
464 
465 
466 
467 
free_PicBuf(PicBuf * pb)468 void free_PicBuf(PicBuf * pb)
469 /**
470  ** De-allocate all row buffers and the picture puffer struct,
471  ** remove the swap file (if any).
472  **/
473 {
474 	RowBuf *row;
475 	int i;
476 
477 	if (pb == NULL)
478 		return;
479 
480 	if (pb->sd) {
481 		fclose(pb->sd);
482 		pb->sd = NULL;
483 #ifdef VAX
484 		delete(pb->sf_name);
485 #else
486 		unlink(pb->sf_name);
487 #endif
488 	}
489 	for (i = 0; i < pb->nr; i++) {
490 		row = &(pb->row[i]);
491 		if (row != NULL
492 		    && (row->prev != NULL || row->next != NULL))
493 			free((char *) row->buf);
494 	}
495 	free((char *) pb->row);
496 	free((char *) pb);
497 }
498 
499 
500 
501 
502 
plot_PicBuf(PicBuf * pb,DevPt * pt,PEN_C color_index)503 void plot_PicBuf(PicBuf * pb, DevPt * pt, PEN_C color_index)
504 {
505 	if ((pt->x + X_Offset) < 0 || pt->x > (pb->nc - X_Offset)) {
506 		Eprintf("plot_PicBuf: Illegal x (%d not in [0, %d])\n",
507 			pt->x + X_Offset, pb->nc);
508 		return;
509 	}
510 	plot_RowBuf(get_RowBuf(pb, pt->y + Y_Offset), pt->x + X_Offset,
511 		    pb->depth, color_index);
512 }
513 
514 
515 
516 
index_from_PicBuf(const PicBuf * pb,const DevPt * pt)517 int index_from_PicBuf(const PicBuf * pb, const DevPt * pt)
518 {
519 	if (pt->x < 0 || pt->x > pb->nc) {
520 		Eprintf
521 		    ("index_from_PicBuf: Illegal x (%d not in [0, %d])\n",
522 		     pt->x, pb->nc);
523 		return 0;
524 	}
525 	return index_from_RowBuf(get_RowBuf(pb, pt->y), pt->x, pb);
526 }
527 
528 
dot_PicBuf(DevPt * p0,int pensize,PEN_C pencolor,PicBuf * pb)529 static void dot_PicBuf(DevPt * p0, int pensize, PEN_C pencolor,
530 		       PicBuf * pb)
531 {
532 
533 	DevPt pt;
534 
535 	int dd = 3 - (pensize);
536 	int dx = 0;
537 	int dy = pensize / 2;
538 
539 	for (; dx <= dy; dx++) {
540 		for (pt.x = p0->x - dx, pt.y = p0->y + dy;
541 		     pt.x <= p0->x + dx; pt.x++)
542 			plot_PicBuf(pb, &pt, pencolor);
543 
544 		for (pt.x = p0->x - dx, pt.y = p0->y - dy;
545 		     pt.x <= p0->x + dx; pt.x++)
546 			plot_PicBuf(pb, &pt, pencolor);
547 
548 		for (pt.x = p0->x - dy, pt.y = p0->y + dx;
549 		     pt.x <= p0->x + dy; pt.x++)
550 			plot_PicBuf(pb, &pt, pencolor);
551 
552 		for (pt.x = p0->x - dy, pt.y = p0->y - dx;
553 		     pt.x <= p0->x + dy; pt.x++)
554 			plot_PicBuf(pb, &pt, pencolor);
555 
556 		if (dd < 0) {
557 			dd += (4 * dx) + 6;
558 		} else {
559 			dd += 4 * (dx - dy) + 10;
560 			dy--;
561 		}
562 	}
563 }
564 
565 
566 static void
line_PicBuf(DevPt * p0,DevPt * p1,PEN_W pensize,PEN_C pencolor,int consecutive,const OUT_PAR * po)567 line_PicBuf(DevPt * p0, DevPt * p1, PEN_W pensize, PEN_C pencolor,
568 	    int consecutive, const OUT_PAR * po)
569     /**
570      ** Rasterize a vector (draw a line in the picture buffer), using the
571      ** Bresenham algorithm.
572      **/
573 {
574 	PicBuf *pb = po->picbuf;
575 	DevPt *p_act;
576 	DevPt t0, t1, t2, t3;
577 	double len, xoff, yoff;
578 	int dx, dy;
579 	int linewidth = (int) ceil(pensize * po->HP_to_xdots / 0.025);	/* convert to pixel space */
580 
581 /*   printf("pensize = %0.3f mm, linewidth = %d pixels\n",pensize,linewidth);*/
582 
583 	if (linewidth == 0)	/* No pen selected! */
584 		return;
585 
586 	if (pencolor == xxBackground)	/* No drawable color!       */
587 		return;
588 
589 	if (linewidth < 5)
590 		consecutive = 0;
591 
592 	if (linewidth == 1) {	/* Thin lines of any attitude */
593 		p_act = bresenham_init(p0, p1);
594 		do {
595 			plot_PicBuf(pb, p_act, pencolor);
596 		} while (bresenham_next() != BRESENHAM_ERR);
597 		return;
598 	}
599 
600 	if ((p1->x == p0->x) && (p1->y == p0->y)) {	/* No Movement Dot Only */
601 		dot_PicBuf(p0, linewidth, pencolor, pb);
602 		return;
603 	}
604 
605 	murphy_init(pb, pencolor);	/* Wide Lines */
606 	murphy_wideline(*p0, *p1, linewidth, consecutive);
607 
608 	if (pensize > 0.35) {
609 		switch (CurrentLineAttr.End) {
610 		case LAE_square:
611 			dx = p0->x - p1->x;
612 			dy = p0->y - p1->y;
613 			len = HYPOT(dx, dy);
614 			xoff = 0.5 * fabs(dx / len);
615 			yoff = 0.5 * fabs(dy / len);
616 			t0.x = p0->x - (linewidth - 1) * yoff;
617 			t0.y = p0->y + (linewidth - 1) * xoff;
618 			t1.x = t0.x - (linewidth - 1) * xoff;
619 			t1.y = t0.y + (linewidth - 1) * yoff;
620 			t3.x = p0->x - (linewidth - 1) * yoff;
621 			t3.y = p0->y - (linewidth - 1) * xoff;
622 			t2.x = t3.x - (linewidth - 1) * xoff;
623 			t2.y = t3.y + (linewidth - 1) * yoff;
624 			polygon_PicBuf(t1, t3, t0, t2, pencolor, pb);
625 			t0.x = p1->x + (linewidth - 1) * yoff;
626 			t0.y = p1->y + (linewidth - 1) * xoff;
627 			t1.x = t0.x + (linewidth - 1) * xoff;
628 			t1.y = t0.y + (linewidth - 1) * yoff;
629 			t3.x = p1->x + (linewidth - 1) * yoff;
630 			t3.y = p1->y - (linewidth - 1) * xoff;
631 			t2.x = t3.x + (linewidth - 1) * xoff;
632 			t2.y = t3.y + (linewidth - 1) * yoff;
633 			polygon_PicBuf(t1, t3, t0, t2, pencolor, pb);
634 			break;
635 		case LAE_butt:
636 		default:
637 			break;
638 		case LAE_triangular:
639 			dx = p0->x - p1->x;
640 			dy = p0->y - p1->y;
641 			len = HYPOT(dx, dy);
642 			xoff = 0.5 * fabs(dx / len);
643 			yoff = 0.5 * fabs(dy / len);
644 			t0.x = p0->x - (linewidth - 1) * xoff;
645 			t0.y = p0->y - (linewidth - 1) * yoff;
646 			t1.x = p0->x + (linewidth - 1) * yoff;
647 			t1.y = p0->y - (linewidth - 1) * xoff;
648 			t2.x = p0->x + (linewidth - 1) * xoff;
649 			t2.y = p0->y + (linewidth - 1) * yoff;
650 			t3.x = p0->x - (linewidth - 1) * yoff;
651 			t3.y = p0->y + (linewidth - 1) * xoff;
652 			polygon_PicBuf(t1, t3, t0, t2, pencolor, pb);
653 			t0.x = p1->x - (linewidth - 1) * xoff;
654 			t0.y = p1->y - (linewidth - 1) * yoff;
655 			t1.x = p1->x + (linewidth - 1) * yoff;
656 			t1.y = p1->y - (linewidth - 1) * xoff;
657 			t2.x = p1->x + (linewidth - 1) * xoff;
658 			t2.y = p1->y + (linewidth - 1) * yoff;
659 			t3.x = p1->x - (linewidth - 1) * yoff;
660 			t3.y = p1->y + (linewidth - 1) * xoff;
661 			polygon_PicBuf(t1, t3, t0, t2, pencolor, pb);
662 			break;
663 		case LAE_round:
664 			dot_PicBuf(p0, linewidth, pencolor, pb);
665 			dot_PicBuf(p1, linewidth, pencolor, pb);
666 			break;
667 		}
668 	} else {
669 		dot_PicBuf(p0, linewidth, pencolor, pb);	/* lines upto 0.35 always have round ends */
670 		dot_PicBuf(p1, linewidth, pencolor, pb);
671 	}
672 
673 }
674 
polygon_PicBuf(DevPt p4,DevPt p2,DevPt p1,DevPt p3,PEN_C pencolor,PicBuf * pb)675 void polygon_PicBuf(DevPt p4, DevPt p2, DevPt p1, DevPt p3, PEN_C pencolor,
676 		    PicBuf * pb)
677 {
678 
679 	DevPt polygon[8];
680 	int xmin, ymin, xmax, ymax;
681 	int start, end, tmp;
682 	DevPt p_act;
683 	double denominator;
684 	double A1, B1, C1, A2, B2, C2;
685 	int scany;
686 	int segx, numlines;
687 	int i, j, k;
688 /*
689 fprintf (stderr,"in polydraw: (%d,%d) (%d,%d) (%d,%d) (%d,%d)\n",p1.x,p1.y,p2.x,p2.y,p3.x,p3.y,
690 p4.x,p4.y);
691 */
692 	polygon[0] = p1;
693 	polygon[1] = p2;
694 	polygon[2] = p2;
695 	polygon[3] = p3;
696 	polygon[4] = p3;
697 	polygon[5] = p4;
698 	polygon[6] = p4;
699 	polygon[7] = p1;
700 /*
701 fprintf(stderr,"pline0 %d %d - %d %d\n",polygon[0].x,polygon[0].y,polygon[1].x,polygon[1].y);
702 fprintf(stderr,"pline1 %d %d - %d %d\n",polygon[2].x,polygon[2].y,polygon[3].x,polygon[3].y);
703 fprintf(stderr,"pline2 %d %d - %d %d\n",polygon[4].x,polygon[4].y,polygon[5].x,polygon[5].y);
704 fprintf(stderr,"pline3 %d %d - %d %d\n",polygon[6].x,polygon[6].y,polygon[7].x,polygon[7].y);
705 */
706 
707 	xmin = MIN(p1.x, p2.x);
708 	xmin = MIN(xmin, p3.x);
709 	xmin = MIN(xmin, p4.x);
710 	xmax = MAX(p1.x, p2.x);
711 	xmax = MAX(xmax, p3.x);
712 	xmax = MAX(xmax, p4.x);
713 	ymin = MIN(p1.y, p2.y);
714 	ymin = MIN(ymin, p3.y);
715 	ymin = MIN(ymin, p4.y);
716 	ymax = MAX(p1.y, p2.y);
717 	ymax = MAX(ymax, p3.y);
718 	ymax = MAX(ymax, p4.y);
719 
720 /*
721 xmin=xmin-2;
722 xmax=xmax+2;
723 */
724 
725 	numlines = 1 + ymax - ymin;
726 
727 /* start at lowest y , run scanlines parallel x across polygon */
728 /* looking for intersections with edges */
729 
730 	for (i = 0; i <= numlines; i++) {	/* for all scanlines ... */
731 		k = -1;
732 		start = end = 0;
733 		scany = ymin + i;
734 /*
735 if(scany >= ymax || scany<=ymin) {
736 continue;
737 }
738 */
739 /* coefficients for current scan line */
740 		A1 = 0.;
741 		B1 = (double) (xmin - xmax);
742 		C1 = (double) (scany * (xmax - xmin));
743 
744 		for (j = 0; j <= 6; j = j + 2) {	/*for all polygon edges */
745 			if ((scany < MIN(polygon[j].y, polygon[j + 1].y))
746 			    || (scany >
747 				MAX(polygon[j].y, polygon[j + 1].y)))
748 				continue;
749 
750 /* coefficients for this edge */
751 			A2 = (double) (polygon[j + 1].y - polygon[j].y);
752 			B2 = (double) (polygon[j].x - polygon[j + 1].x);
753 			C2 = (double) (polygon[j].x *
754 				       (polygon[j].y - polygon[j + 1].y) +
755 				       polygon[j].y * (polygon[j + 1].x -
756 						       polygon[j].x));
757 
758 /*determine coordinates of intersection */
759 			denominator = A1 * B2 - A2 * B1;
760 			if (fabs(denominator) > 1.e-5) {	/* zero means parallel lines */
761 
762 				segx = (int) ((B1 * C2 - B2 * C1) / denominator);	/*x coordinate of intersection */
763 
764 /*fprintf(stderr,"seg x,y= %d %d\n",segx,segy);*/
765 				if ((segx > xmax) || (segx < xmin) ||
766 				    (segx <
767 				     MIN(polygon[j].x, polygon[j + 1].x))
768 				    || (segx >
769 					MAX(polygon[j].x,
770 					    polygon[j + 1].x))) {
771 /*fprintf(stderr,"intersection  at %d %d is not within (%d,%d)-(%d,%d)\n",segx,segy,polygon[j].x,polygon[j].y,polygon[j+1].x,polygon[j+1].y )
772 ; */
773 				} else {
774 
775 					k++;
776 					if (k == 0) {
777 						start = segx;
778 					} else if (segx != start) {
779 						end = segx;
780 					} else if (k > 0)
781 						k--;
782 				}	/* if crossing withing range */
783 			}
784 			/*if not parallel */
785 		}		/*next edge */
786 		if (k >= 1) {
787 			if (start > end) {
788 				tmp = end;
789 				end = start;
790 				start = tmp;
791 			}
792 /*fprintf(stderr,"fillline %d %d - %d %d\n",start.x,start.y,end.x,end.y);*/
793 			for (p_act.x = start, p_act.y = scany;
794 			     p_act.x <= end; p_act.x++)
795 				plot_PicBuf(pb, &p_act, pencolor);
796 		}
797 	}			/* next scanline */
798 
799 }
800 
tmpfile_to_PicBuf(const GEN_PAR * pg,const OUT_PAR * po)801 void tmpfile_to_PicBuf(const GEN_PAR * pg, const OUT_PAR * po)
802 /**
803  ** Interface to higher-level routines:
804  **   Assuming a valid picture buffer, read the drawing commands from
805  **   the temporary file, transform HP_GL coordinates into dot coordinates,
806  **   and draw (rasterize) vectors.
807  **/
808 {
809 	HPGL_Pt pt1;
810 	static DevPt ref = { 0, 0 };
811 	DevPt next;
812 	PlotCmd cmd;
813 	static int consecutive = 0;
814 	int pen_no = 1;
815 
816 	if (!pg->quiet)
817 		Eprintf("\nPlotting in buffer\n");
818 
819 	rewind(pg->td);
820 
821 	while ((cmd = PlotCmd_from_tmpfile()) != CMD_EOF)
822 		switch (cmd) {
823 		case NOP:
824 			break;
825 		case SET_PEN:
826 			if ((pen_no = fgetc(pg->td)) == EOF) {
827 				PError("Unexpected end of temp. file");
828 				exit(ERROR);
829 			}
830 			consecutive = 0;
831 			break;
832 		case DEF_PW:
833 			if (!load_pen_width_table(pg->td)) {
834 				PError("Unexpected end of temp. file");
835 				exit(ERROR);
836 			}
837 			break;
838 		case DEF_PC:
839 			if (load_pen_color_table(pg->td) < 0) {
840 				PError("Unexpected end of temp. file");
841 				exit(ERROR);
842 			}
843 			consecutive = 0;
844 			break;
845 		case DEF_LA:
846 			if (load_line_attr(pg->td) < 0) {
847 				PError("Unexpected end of temp. file");
848 				exit(ERROR);
849 			}
850 			consecutive = 0;
851 			break;
852 		case MOVE_TO:
853 			HPGL_Pt_from_tmpfile(&pt1);
854 			HPcoord_to_dotcoord(&pt1, &ref, po);
855 			consecutive = 0;
856 			break;
857 		case DRAW_TO:
858 			HPGL_Pt_from_tmpfile(&pt1);
859 			HPcoord_to_dotcoord(&pt1, &next, po);
860 			line_PicBuf(&ref, &next, pt.width[pen_no],
861 				    pt.color[pen_no], consecutive, po);
862 			memcpy(&ref, &next, sizeof(ref));
863 			consecutive++;
864 			break;
865 		case PLOT_AT:
866 			HPGL_Pt_from_tmpfile(&pt1);
867 			HPcoord_to_dotcoord(&pt1, &ref, po);
868 			line_PicBuf(&ref, &ref, pt.width[pen_no],
869 				    pt.color[pen_no], consecutive, po);
870 			consecutive = 0;
871 			break;
872 
873 		default:
874 			Eprintf("Illegal cmd in temp. file!\n");
875 			exit(ERROR);
876 		}
877 }
878