comparison packages/services/gfx/mw/current/src/engine/devpoly.c @ 208:e0c0827131d1 ecos

Merge from eCos master repository on 2002-05-20-20:11:54-BST
author jlarmour
date Mon, 20 May 2002 22:19:26 +0000
parents
children
comparison
equal deleted inserted replaced
207:74c807ddde34 208:e0c0827131d1
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include "device.h"
4 /*
5 * Microwindows polygon outline and fill routines.
6 * Copyright (c) 1999, 2000, 2001 Greg Haerr <greg@censoft.com>
7 * Portions Copyright (c) 1991 David I. Bell
8 *
9 * There are currently three implementations of the polygon
10 * fill routine. The version from X11 most properly
11 * fills polygons that must also be outlined as well. All are
12 * controlled with #if directive in this file.
13 */
14
15 /* extern definitions*/
16 void drawpoint(PSD psd,MWCOORD x, MWCOORD y);
17 void drawrow(PSD psd,MWCOORD x1,MWCOORD x2,MWCOORD y);
18 extern int gr_mode; /* drawing mode */
19
20 /* Draw a polygon in the foreground color, applying clipping if necessary.
21 * The polygon is only closed if the first point is repeated at the end.
22 * Some care is taken to plot the endpoints correctly if the current
23 * drawing mode is XOR. However, internal crossings are not handled
24 * correctly.
25 */
26 void
27 GdPoly(PSD psd, int count, MWPOINT *points)
28 {
29 MWCOORD firstx;
30 MWCOORD firsty;
31 MWBOOL didline;
32
33 if (count < 2)
34 return;
35 firstx = points->x;
36 firsty = points->y;
37 didline = FALSE;
38
39 while (count-- > 1) {
40 if (didline && (gr_mode == MWMODE_XOR))
41 drawpoint(psd, points->x, points->y);
42 /* note: change to drawline*/
43 GdLine(psd, points[0].x, points[0].y, points[1].x, points[1].y, TRUE);
44 points++;
45 didline = TRUE;
46 }
47 if (gr_mode == MWMODE_XOR) {
48 points--;
49 if (points->x == firstx && points->y == firsty)
50 drawpoint(psd, points->x, points->y);
51 }
52 GdFixCursor(psd);
53 }
54
55 #if 1 /* improved convex polygon fill routine*/
56 /***********************************************************
57 Copyright (c) 1987 X Consortium
58
59 Permission is hereby granted, free of charge, to any person obtaining a copy
60 of this software and associated documentation files (the "Software"), to deal
61 in the Software without restriction, including without limitation the rights
62 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
63 copies of the Software, and to permit persons to whom the Software is
64 furnished to do so, subject to the following conditions:
65
66 The above copyright notice and this permission notice shall be included in
67 all copies or substantial portions of the Software.
68
69 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
70 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
71 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
72 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
73 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
74 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
75
76 Except as contained in this notice, the name of the X Consortium shall not be
77 used in advertising or otherwise to promote the sale, use or other dealings
78 in this Software without prior written authorization from the X Consortium.
79
80
81 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
82
83 All Rights Reserved
84
85 Permission to use, copy, modify, and distribute this software and its
86 documentation for any purpose and without fee is hereby granted,
87 provided that the above copyright notice appear in all copies and that
88 both that copyright notice and this permission notice appear in
89 supporting documentation, and that the name of Digital not be
90 used in advertising or publicity pertaining to distribution of the
91 software without specific, written prior permission.
92
93 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
94 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
95 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
96 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
97 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
98 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
99 SOFTWARE.
100 ******************************************************************/
101
102 /*
103 * Written by Brian Kelleher; Dec. 1985.
104 * Adapted for Microwindows Sep 2001 by Greg Haerr <greg@censoft.com>
105 *
106 * Fill a convex polygon in the fg color, with clipping.
107 * If the given polygon
108 * is not convex, then the result is undefined.
109 * The algorithm is to order the edges from smallest
110 * y to largest by partitioning the array into a left
111 * edge list and a right edge list. The algorithm used
112 * to traverse each edge is an extension of Bresenham's
113 * line algorithm with y as the major axis.
114 *
115 * This file contains a few macros to help track
116 * the edge of a filled object. The object is assumed
117 * to be filled in scanline order, and thus the
118 * algorithm used is an extension of Bresenham's line
119 * drawing algorithm which assumes that y is always the
120 * major axis.
121 *
122 * In scan converting polygons, we want to choose those pixels
123 * which are inside the polygon. Thus, we add .5 to the starting
124 * x coordinate for both left and right edges. Now we choose the
125 * first pixel which is inside the pgon for the left edge and the
126 * first pixel which is outside the pgon for the right edge.
127 * Draw the left pixel, but not the right.
128 *
129 * How to add .5 to the starting x coordinate:
130 * If the edge is moving to the right, then subtract dy from the
131 * error term from the general form of the algorithm.
132 * If the edge is moving to the left, then add dy to the error term.
133 *
134 * The reason for the difference between edges moving to the left
135 * and edges moving to the right is simple: If an edge is moving
136 * to the right, then we want the algorithm to flip immediately.
137 * If it is moving to the left, then we don't want it to flip until
138 * we traverse an entire pixel.
139 */
140 #define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
141 int dx; /* local storage */ \
142 \
143 /* \
144 * if the edge is horizontal, then it is ignored \
145 * and assumed not to be processed. Otherwise, do this stuff. \
146 */ \
147 if ((dy) != 0) { \
148 xStart = (x1); \
149 dx = (x2) - xStart; \
150 if (dx < 0) { \
151 m = dx / (dy); \
152 m1 = m - 1; \
153 incr1 = -2 * dx + 2 * (dy) * m1; \
154 incr2 = -2 * dx + 2 * (dy) * m; \
155 d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
156 } else { \
157 m = dx / (dy); \
158 m1 = m + 1; \
159 incr1 = 2 * dx - 2 * (dy) * m1; \
160 incr2 = 2 * dx - 2 * (dy) * m; \
161 d = -2 * m * (dy) + 2 * dx; \
162 } \
163 } \
164 }
165
166 #define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
167 if (m1 > 0) { \
168 if (d > 0) { \
169 minval += m1; \
170 d += incr1; \
171 } \
172 else { \
173 minval += m; \
174 d += incr2; \
175 } \
176 } else {\
177 if (d >= 0) { \
178 minval += m1; \
179 d += incr1; \
180 } \
181 else { \
182 minval += m; \
183 d += incr2; \
184 } \
185 } \
186 }
187
188 /*
189 * Find the index of the point with the smallest y.
190 */
191 static int
192 getPolyYBounds(MWPOINT *pts, int n, int *by, int *ty)
193 {
194 MWPOINT *ptMin;
195 int ymin, ymax;
196 MWPOINT *ptsStart = pts;
197
198 ptMin = pts;
199 ymin = ymax = (pts++)->y;
200
201 while (--n > 0) {
202 if (pts->y < ymin)
203 {
204 ptMin = pts;
205 ymin = pts->y;
206 }
207 if(pts->y > ymax)
208 ymax = pts->y;
209
210 pts++;
211 }
212
213 *by = ymin;
214 *ty = ymax;
215 return(ptMin-ptsStart);
216 }
217
218 void
219 GdFillPoly(PSD psd, int count, MWPOINT *pointtable)
220 {
221 MWCOORD xl = 0, xr = 0; /* x vals of left and right edges */
222 int dl = 0, dr = 0; /* decision variables */
223 int ml = 0, m1l = 0; /* left edge slope and slope+1 */
224 int mr = 0, m1r = 0; /* right edge slope and slope+1 */
225 int incr1l = 0, incr2l = 0; /* left edge error increments */
226 int incr1r = 0, incr2r = 0; /* right edge error increments */
227 int dy; /* delta y */
228 MWCOORD y; /* current scanline */
229 int left, right; /* indices to first endpoints */
230 int i; /* loop counter */
231 int nextleft, nextright; /* indices to second endpoints */
232 MWPOINT *ptsOut, *FirstPoint;/* output buffer */
233 MWCOORD *width, *FirstWidth;/* output buffer */
234 int imin; /* index of smallest vertex (in y)*/
235 int ymin; /* y-extents of polygon */
236 int ymax;
237
238 /*
239 * find leftx, bottomy, rightx, topy, and the index
240 * of bottomy.
241 */
242 imin = getPolyYBounds(pointtable, count, &ymin, &ymax);
243
244 dy = ymax - ymin + 1;
245 if ((count < 3) || (dy < 0))
246 return;
247 ptsOut = FirstPoint = (MWPOINT *)ALLOCA(sizeof(MWPOINT) * dy);
248 width = FirstWidth = (MWCOORD *)ALLOCA(sizeof(MWCOORD) * dy);
249 if(!FirstPoint || !FirstWidth)
250 {
251 if (FirstWidth) FREEA(FirstWidth);
252 if (FirstPoint) FREEA(FirstPoint);
253 return;
254 }
255
256 nextleft = nextright = imin;
257 y = pointtable[nextleft].y;
258
259 /*
260 * loop through all edges of the polygon
261 */
262 do {
263 /*
264 * add a left edge if we need to
265 */
266 if (pointtable[nextleft].y == y) {
267 left = nextleft;
268
269 /*
270 * find the next edge, considering the end
271 * conditions of the array.
272 */
273 nextleft++;
274 if (nextleft >= count)
275 nextleft = 0;
276
277 /*
278 * now compute all of the random information
279 * needed to run the iterative algorithm.
280 */
281 BRESINITPGON(pointtable[nextleft].y-pointtable[left].y,
282 pointtable[left].x,pointtable[nextleft].x,
283 xl, dl, ml, m1l, incr1l, incr2l);
284 }
285
286 /*
287 * add a right edge if we need to
288 */
289 if (pointtable[nextright].y == y) {
290 right = nextright;
291
292 /*
293 * find the next edge, considering the end
294 * conditions of the array.
295 */
296 nextright--;
297 if (nextright < 0)
298 nextright = count-1;
299
300 /*
301 * now compute all of the random information
302 * needed to run the iterative algorithm.
303 */
304 BRESINITPGON(pointtable[nextright].y-pointtable[right].y,
305 pointtable[right].x,pointtable[nextright].x,
306 xr, dr, mr, m1r, incr1r, incr2r);
307 }
308
309 /*
310 * generate scans to fill while we still have
311 * a right edge as well as a left edge.
312 */
313 i = MWMIN(pointtable[nextleft].y, pointtable[nextright].y) - y;
314 /* in case we're called with non-convex polygon */
315 if(i < 0)
316 {
317 FREEA(FirstWidth);
318 FREEA(FirstPoint);
319 return;
320 }
321 while (i-- > 0)
322 {
323 ptsOut->y = y;
324
325 /*
326 * reverse the edges if necessary
327 */
328 if (xl < xr)
329 {
330 *(width++) = xr - xl;
331 (ptsOut++)->x = xl;
332 }
333 else
334 {
335 *(width++) = xl - xr;
336 (ptsOut++)->x = xr;
337 }
338 y++;
339
340 /* increment down the edges */
341 BRESINCRPGON(dl, xl, ml, m1l, incr1l, incr2l);
342 BRESINCRPGON(dr, xr, mr, m1r, incr1r, incr2r);
343 }
344 } while (y != ymax);
345
346 /*
347 * Finally, fill the spans
348 */
349 i = ptsOut-FirstPoint;
350 ptsOut = FirstPoint;
351 width = FirstWidth;
352 while (--i >= 0) {
353 /* calc x extent from width*/
354 int e = *width++ - 1;
355 if (e >= 0) {
356 drawrow(psd, ptsOut->x, ptsOut->x + e, ptsOut->y);
357 }
358 ++ptsOut;
359 }
360
361 FREEA(FirstWidth);
362 FREEA(FirstPoint);
363 GdFixCursor(psd);
364 }
365 #endif
366
367 #if 0 /* original convex only polygon fill routine*/
368 /*
369 * Fill a polygon in the foreground color, applying clipping if necessary.
370 * The last point may be a duplicate of the first point, but this is
371 * not required.
372 * Note: this routine currently only correctly fills convex polygons.
373 */
374
375 /* Utility routine for filling polygons. Find the intersection point (if
376 * any) of a horizontal line with an arbitrary line, and extend the current
377 * minimum and maximum x values as needed to include the intersection point.
378 * Input parms:
379 * y row to check for intersection
380 * x1, y1 first endpoint
381 * x2, y2 second enpoint
382 * minxptr address of current minimum x
383 * maxxptr address of current maximum x
384 */
385 static void
386 extendrow(MWCOORD y,MWCOORD x1,MWCOORD y1,MWCOORD x2,MWCOORD y2,
387 MWCOORD *minxptr,MWCOORD *maxxptr)
388 {
389 MWCOORD x; /* x coordinate of intersection */
390 typedef long NUM;
391 NUM num; /* numerator of fraction */
392
393 /* First make sure the specified line segment includes the specified
394 * row number. If not, then there is no intersection.
395 */
396 if (((y < y1) || (y > y2)) && ((y < y2) || (y > y1)))
397 return;
398
399 /* If a horizontal line, then check the two endpoints. */
400 if (y1 == y2) {
401 if (*minxptr > x1) *minxptr = x1;
402 if (*minxptr > x2) *minxptr = x2;
403 if (*maxxptr < x1) *maxxptr = x1;
404 if (*maxxptr < x2) *maxxptr = x2;
405 return;
406 }
407
408 /* If a vertical line, then check the x coordinate. */
409 if (x1 == x2) {
410 if (*minxptr > x1) *minxptr = x1;
411 if (*maxxptr < x1) *maxxptr = x1;
412 return;
413 }
414
415 /* An arbitrary line. Calculate the intersection point using the
416 * formula x = x1 + (y - y1) * (x2 - x1) / (y2 - y1).
417 */
418 num = ((NUM) (y - y1)) * (x2 - x1);
419 x = x1 + num / (y2 - y1);
420 if (*minxptr > x) *minxptr = x;
421 if (*maxxptr < x) *maxxptr = x;
422 }
423
424 void
425 GdFillPoly(PSD psd, int count, MWPOINT *points)
426 {
427 MWPOINT *pp; /* current point */
428 MWCOORD miny; /* minimum row */
429 MWCOORD maxy; /* maximum row */
430 MWCOORD minx; /* minimum column */
431 MWCOORD maxx; /* maximum column */
432 int i; /* counter */
433
434 if (count <= 0)
435 return;
436
437 /* First determine the minimum and maximum rows for the polygon. */
438 pp = points;
439 miny = pp->y;
440 maxy = pp->y;
441 for (i = count; i-- > 0; pp++) {
442 if (miny > pp->y) miny = pp->y;
443 if (maxy < pp->y) maxy = pp->y;
444 }
445 if (miny < 0)
446 miny = 0;
447 if (maxy >= psd->yvirtres)
448 maxy = psd->yvirtres - 1;
449 if (miny > maxy)
450 return;
451
452 /* Now for each row, scan the list of points and determine the
453 * minimum and maximum x coordinate for each line, and plot the row.
454 * The last point connects with the first point automatically.
455 */
456 for (; miny <= maxy; miny++) {
457 minx = MAX_MWCOORD;
458 maxx = MIN_MWCOORD;
459 pp = points;
460 for (i = count; --i > 0; pp++)
461 extendrow(miny, pp[0].x, pp[0].y, pp[1].x, pp[1].y,
462 &minx, &maxx);
463 extendrow(miny, pp[0].x, pp[0].y, points[0].x, points[0].y,
464 &minx, &maxx);
465
466 if (minx <= maxx)
467 drawrow(psd, minx, maxx, miny);
468 }
469 GdFixCursor(psd);
470 }
471 #endif
472
473 #if 0 /* irregular polygon fill, uses edge table, malloc, qsort*/
474 /*
475 * Fill a polygon in the foreground color, applying clipping if necessary.
476 * The last point may be a duplicate of the first point, but this is
477 * not required.
478 * Note: this routine correctly draws convex, concave, regular,
479 * and irregular polygons.
480 */
481 #define USE_FLOAT HAVEFLOAT /* set to use floating point*/
482
483 #define swap(a,b) do { a ^= b; b ^= a; a ^= b; } while (0)
484
485 typedef struct {
486 int x1, y1, x2, y2;
487 #if USE_FLOAT
488 double x, m;
489 #else
490 int cx, fn, mn, d;
491 #endif
492 } edge_t;
493
494 static int
495 edge_cmp(const void *lvp, const void *rvp)
496 {
497 /* convert from void pointers to structure pointers */
498 const edge_t *lp = (const edge_t *)lvp;
499 const edge_t *rp = (const edge_t *)rvp;
500
501 /* if the minimum y values are different, sort on minimum y */
502 if (lp->y1 != rp->y1)
503 return lp->y1 - rp->y1;
504
505 /* if the current x values are different, sort on current x */
506 #if USE_FLOAT
507 if (lp->x < rp->x)
508 return -1;
509 else if (lp->x > rp->x)
510 return +1;
511 #else
512 if (lp->cx != rp->cx)
513 return lp->cx - rp->cx;
514 #endif
515
516 /* otherwise they are equal */
517 return 0;
518 }
519
520 void
521 GdFillPoly(PSD psd, int count, MWPOINT * pointtable)
522 {
523 edge_t *get; /* global edge table */
524 int nge = 0; /* num global edges */
525 int cge = 0; /* cur global edge */
526
527 edge_t *aet; /* active edge table */
528 int nae = 0; /* num active edges */
529
530 int i, y;
531
532 if (count < 3) {
533 /* error, polygons require at least three edges (a triangle) */
534 return;
535 }
536 get = (edge_t *) calloc(count, sizeof(edge_t));
537 aet = (edge_t *) calloc(count, sizeof(edge_t));
538
539 if ((get == 0) || (aet == 0)) {
540 /* error, couldn't allocate one or both of the needed tables */
541 if (get)
542 free(get);
543 if (aet)
544 free(aet);
545 return;
546 }
547 /* setup the global edge table */
548 for (i = 0; i < count; ++i) {
549 get[nge].x1 = pointtable[i].x;
550 get[nge].y1 = pointtable[i].y;
551 get[nge].x2 = pointtable[(i + 1) % count].x;
552 get[nge].y2 = pointtable[(i + 1) % count].y;
553 if (get[nge].y1 != get[nge].y2) {
554 if (get[nge].y1 > get[nge].y2) {
555 swap(get[nge].x1, get[nge].x2);
556 swap(get[nge].y1, get[nge].y2);
557 }
558 #if USE_FLOAT
559 get[nge].x = get[nge].x1;
560 get[nge].m = get[nge].x2 - get[nge].x1;
561 get[nge].m /= get[nge].y2 - get[nge].y1;
562 #else
563 get[nge].cx = get[nge].x1;
564 get[nge].mn = get[nge].x2 - get[nge].x1;
565 get[nge].d = get[nge].y2 - get[nge].y1;
566 get[nge].fn = get[nge].mn / 2;
567 #endif
568 ++nge;
569 }
570 }
571
572 qsort(get, nge, sizeof(get[0]), edge_cmp);
573
574 /* start with the lowest y in the table */
575 y = get[0].y1;
576
577 do {
578
579 /* add edges to the active table from the global table */
580 while ((nge > 0) && (get[cge].y1 == y)) {
581 aet[nae] = get[cge++];
582 --nge;
583 aet[nae++].y1 = 0;
584 }
585
586 qsort(aet, nae, sizeof(aet[0]), edge_cmp);
587
588 /* using odd parity, render alternating line segments */
589 for (i = 1; i < nae; i += 2) {
590 #if USE_FLOAT
591 int l = (int)aet[i - 1].x;
592 int r = (int)aet[i].x;
593 #else
594 int l = (int)aet[i - 1].cx;
595 int r = (int)aet[i].cx;
596 #endif
597 if (r > l)
598 drawrow(psd, l, r - 1, y);
599 }
600
601 /* prepare for the next scan line */
602 ++y;
603
604 /* remove inactive edges from the active edge table */
605 /* or update the current x position of active edges */
606 for (i = 0; i < nae; ++i) {
607 if (aet[i].y2 == y)
608 aet[i--] = aet[--nae];
609 else {
610 #if USE_FLOAT
611 aet[i].x += aet[i].m;
612 #else
613 aet[i].fn += aet[i].mn;
614 if (aet[i].fn < 0) {
615 aet[i].cx += aet[i].fn / aet[i].d - 1;
616 aet[i].fn %= aet[i].d;
617 aet[i].fn += aet[i].d;
618 }
619 if (aet[i].fn >= aet[i].d) {
620 aet[i].cx += aet[i].fn / aet[i].d;
621 aet[i].fn %= aet[i].d;
622 }
623 #endif
624 }
625 }
626
627 /* keep doing this while there are any edges left */
628 } while ((nae > 0) || (nge > 0));
629
630 /* all done, free the edge tables */
631 free(get);
632 free(aet);
633
634 GdFixCursor(psd);
635 }
636 #endif