Poly.c revision 1f0ac6a5
1/* 2 * 3 * Copyright © 2002 Keith Packard 4 * 5 * Permission to use, copy, modify, distribute, and sell this software and its 6 * documentation for any purpose is hereby granted without fee, provided that 7 * the above copyright notice appear in all copies and that both that 8 * copyright notice and this permission notice appear in supporting 9 * documentation, and that the name of Keith Packard not be used in 10 * advertising or publicity pertaining to distribution of the software without 11 * specific, written prior permission. Keith Packard makes no 12 * representations about the suitability of this software for any purpose. It 13 * is provided "as is" without express or implied warranty. 14 * 15 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 17 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 21 * PERFORMANCE OF THIS SOFTWARE. 22 */ 23 24#ifdef HAVE_CONFIG_H 25#include <config.h> 26#endif 27#include "Xrenderint.h" 28 29typedef struct _Edge Edge; 30 31struct _Edge { 32 XLineFixed edge; 33 XFixed current_x; 34 Bool clockWise; 35 Edge *next, *prev; 36}; 37 38static int 39CompareEdge (const void *o1, const void *o2) 40{ 41 const Edge *e1 = o1, *e2 = o2; 42 43 return e1->edge.p1.y - e2->edge.p1.y; 44} 45 46static XFixed 47XRenderComputeX (XLineFixed *line, XFixed y) 48{ 49 XFixed dx = line->p2.x - line->p1.x; 50 double ex = (double) (y - line->p1.y) * (double) dx; 51 XFixed dy = line->p2.y - line->p1.y; 52 53 return (XFixed) line->p1.x + (XFixed) (ex / dy); 54} 55 56static double 57XRenderComputeInverseSlope (XLineFixed *l) 58{ 59 return (XFixedToDouble (l->p2.x - l->p1.x) / 60 XFixedToDouble (l->p2.y - l->p1.y)); 61} 62 63static double 64XRenderComputeXIntercept (XLineFixed *l, double inverse_slope) 65{ 66 return XFixedToDouble (l->p1.x) - inverse_slope * XFixedToDouble (l->p1.y); 67} 68 69static XFixed 70XRenderComputeIntersect (XLineFixed *l1, XLineFixed *l2) 71{ 72 /* 73 * x = m1y + b1 74 * x = m2y + b2 75 * m1y + b1 = m2y + b2 76 * y * (m1 - m2) = b2 - b1 77 * y = (b2 - b1) / (m1 - m2) 78 */ 79 double m1 = XRenderComputeInverseSlope (l1); 80 double b1 = XRenderComputeXIntercept (l1, m1); 81 double m2 = XRenderComputeInverseSlope (l2); 82 double b2 = XRenderComputeXIntercept (l2, m2); 83 84 return XDoubleToFixed ((b2 - b1) / (m1 - m2)); 85} 86 87static int 88XRenderComputeTrapezoids (Edge *edges, 89 int nedges, 90 int winding, 91 XTrapezoid *traps) 92{ 93 int ntraps = 0; 94 int inactive; 95 Edge *active; 96 Edge *e, *en, *next; 97 XFixed y, next_y, intersect; 98 99 qsort (edges, nedges, sizeof (Edge), CompareEdge); 100 101 y = edges[0].edge.p1.y; 102 active = 0; 103 inactive = 0; 104 while (active || inactive < nedges) 105 { 106 /* insert new active edges into list */ 107 while (inactive < nedges) 108 { 109 e = &edges[inactive]; 110 if (e->edge.p1.y > y) 111 break; 112 /* move this edge into the active list */ 113 inactive++; 114 e->next = active; 115 e->prev = 0; 116 if (active) 117 active->prev = e; 118 active = e; 119 } 120 /* compute x coordinates along this group */ 121 for (e = active; e; e = e->next) 122 e->current_x = XRenderComputeX (&e->edge, y); 123 124 /* sort active list */ 125 for (e = active; e; e = next) 126 { 127 next = e->next; 128 /* 129 * Find one later in the list that belongs before the 130 * current one 131 */ 132 for (en = next; en; en = en->next) 133 { 134 if (en->current_x < e->current_x || 135 (en->current_x == e->current_x && 136 en->edge.p2.x < e->edge.p2.x)) 137 { 138 /* 139 * insert en before e 140 * 141 * extract en 142 */ 143 en->prev->next = en->next; 144 if (en->next) 145 en->next->prev = en->prev; 146 /* 147 * insert en 148 */ 149 if (e->prev) 150 e->prev->next = en; 151 else 152 active = en; 153 en->prev = e->prev; 154 e->prev = en; 155 en->next = e; 156 /* 157 * start over at en 158 */ 159 next = en; 160 break; 161 } 162 } 163 } 164#if 0 165 printf ("y: %6.3g:", y / 65536.0); 166 for (e = active; e; e = e->next) 167 { 168 printf (" %6.3g", e->current_x / 65536.0); 169 } 170 printf ("\n"); 171#endif 172 /* find next inflection point */ 173 next_y = active->edge.p2.y; 174 for (e = active; e; e = en) 175 { 176 if (e->edge.p2.y < next_y) 177 next_y = e->edge.p2.y; 178 en = e->next; 179 /* check intersect */ 180 if (en && e->edge.p2.x > en->edge.p2.x) 181 { 182 intersect = XRenderComputeIntersect (&e->edge, &e->next->edge); 183 /* make sure this point is below the actual intersection */ 184 intersect = intersect + 1; 185 if (intersect < next_y) 186 next_y = intersect; 187 } 188 } 189 /* check next inactive point */ 190 if (inactive < nedges && edges[inactive].edge.p1.y < next_y) 191 next_y = edges[inactive].edge.p1.y; 192 193 /* walk the list generating trapezoids */ 194 for (e = active; e && (en = e->next); e = en->next) 195 { 196 traps->top = y; 197 traps->bottom = next_y; 198 traps->left = e->edge; 199 traps->right = en->edge; 200 traps++; 201 ntraps++; 202 } 203 204 y = next_y; 205 206 /* delete inactive edges from list */ 207 for (e = active; e; e = next) 208 { 209 next = e->next; 210 if (e->edge.p2.y <= y) 211 { 212 if (e->prev) 213 e->prev->next = e->next; 214 else 215 active = e->next; 216 if (e->next) 217 e->next->prev = e->prev; 218 } 219 } 220 } 221 return ntraps; 222} 223 224void 225XRenderCompositeDoublePoly (Display *dpy, 226 int op, 227 Picture src, 228 Picture dst, 229 _Xconst XRenderPictFormat *maskFormat, 230 int xSrc, 231 int ySrc, 232 int xDst, 233 int yDst, 234 _Xconst XPointDouble *fpoints, 235 int npoints, 236 int winding) 237{ 238 Edge *edges; 239 XTrapezoid *traps; 240 int i, nedges, ntraps; 241 XFixed x, y, prevx = 0, prevy = 0, firstx = 0, firsty = 0; 242 XFixed top = 0, bottom = 0; /* GCCism */ 243 244 edges = (Edge *) Xmalloc (npoints * sizeof (Edge) + 245 (npoints * npoints * sizeof (XTrapezoid))); 246 if (!edges) 247 return; 248 traps = (XTrapezoid *) (edges + npoints); 249 nedges = 0; 250 for (i = 0; i <= npoints; i++) 251 { 252 if (i == npoints) 253 { 254 x = firstx; 255 y = firsty; 256 } 257 else 258 { 259 x = XDoubleToFixed (fpoints[i].x); 260 y = XDoubleToFixed (fpoints[i].y); 261 } 262 if (i) 263 { 264 if (y < top) 265 top = y; 266 else if (y > bottom) 267 bottom = y; 268 if (prevy < y) 269 { 270 edges[nedges].edge.p1.x = prevx; 271 edges[nedges].edge.p1.y = prevy; 272 edges[nedges].edge.p2.x = x; 273 edges[nedges].edge.p2.y = y; 274 edges[nedges].clockWise = True; 275 nedges++; 276 } 277 else if (prevy > y) 278 { 279 edges[nedges].edge.p1.x = x; 280 edges[nedges].edge.p1.y = y; 281 edges[nedges].edge.p2.x = prevx; 282 edges[nedges].edge.p2.y = prevy; 283 edges[nedges].clockWise = False; 284 nedges++; 285 } 286 /* drop horizontal edges */ 287 } 288 else 289 { 290 top = y; 291 bottom = y; 292 firstx = x; 293 firsty = y; 294 } 295 prevx = x; 296 prevy = y; 297 } 298 ntraps = XRenderComputeTrapezoids (edges, nedges, winding, traps); 299 /* XXX adjust xSrc/xDst */ 300 XRenderCompositeTrapezoids (dpy, op, src, dst, maskFormat, xSrc, ySrc, traps, ntraps); 301 Xfree (edges); 302} 303