| 1 | /* $Id: region.h,v 1.1 1999-05-24 20:19:18 ktk Exp $ */
|
|---|
| 2 |
|
|---|
| 3 | /*
|
|---|
| 4 | * GDI region definitions
|
|---|
| 5 | * Mainly taken from the X11 distribution.
|
|---|
| 6 | * Modifications: Copyright 1998 Huw Davies
|
|---|
| 7 | */
|
|---|
| 8 |
|
|---|
| 9 | /************************************************************************
|
|---|
| 10 |
|
|---|
| 11 | Copyright (c) 1987 X Consortium
|
|---|
| 12 |
|
|---|
| 13 | Permission is hereby granted, free of charge, to any person obtaining a copy
|
|---|
| 14 | of this software and associated documentation files (the "Software"), to deal
|
|---|
| 15 | in the Software without restriction, including without limitation the rights
|
|---|
| 16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|---|
| 17 | copies of the Software, and to permit persons to whom the Software is
|
|---|
| 18 | furnished to do so, subject to the following conditions:
|
|---|
| 19 |
|
|---|
| 20 | The above copyright notice and this permission notice shall be included in
|
|---|
| 21 | all copies or substantial portions of the Software.
|
|---|
| 22 |
|
|---|
| 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|---|
| 24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|---|
| 25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|---|
| 26 | X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|---|
| 27 | AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|---|
| 28 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|---|
| 29 |
|
|---|
| 30 | Except as contained in this notice, the name of the X Consortium shall not be
|
|---|
| 31 | used in advertising or otherwise to promote the sale, use or other dealings
|
|---|
| 32 | in this Software without prior written authorization from the X Consortium.
|
|---|
| 33 |
|
|---|
| 34 |
|
|---|
| 35 | Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
|
|---|
| 36 |
|
|---|
| 37 | All Rights Reserved
|
|---|
| 38 |
|
|---|
| 39 | Permission to use, copy, modify, and distribute this software and its
|
|---|
| 40 | documentation for any purpose and without fee is hereby granted,
|
|---|
| 41 | provided that the above copyright notice appear in all copies and that
|
|---|
| 42 | both that copyright notice and this permission notice appear in
|
|---|
| 43 | supporting documentation, and that the name of Digital not be
|
|---|
| 44 | used in advertising or publicity pertaining to distribution of the
|
|---|
| 45 | software without specific, written prior permission.
|
|---|
| 46 |
|
|---|
| 47 | DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
|
|---|
| 48 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
|
|---|
| 49 | DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
|
|---|
| 50 | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
|---|
| 51 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
|---|
| 52 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
|---|
| 53 | SOFTWARE.
|
|---|
| 54 |
|
|---|
| 55 | ************************************************************************/
|
|---|
| 56 | #ifndef __WINE_REGION_H
|
|---|
| 57 | #define __WINE_REGION_H
|
|---|
| 58 |
|
|---|
| 59 | #include "wingdi.h"
|
|---|
| 60 | #include "gdi.h"
|
|---|
| 61 |
|
|---|
| 62 |
|
|---|
| 63 | typedef struct {
|
|---|
| 64 | INT size;
|
|---|
| 65 | INT numRects;
|
|---|
| 66 | INT type; /* NULL, SIMPLE or COMPLEX */
|
|---|
| 67 | RECT *rects;
|
|---|
| 68 | RECT extents;
|
|---|
| 69 | } WINEREGION;
|
|---|
| 70 |
|
|---|
| 71 | /* GDI logical region object */
|
|---|
| 72 | typedef struct
|
|---|
| 73 | {
|
|---|
| 74 | GDIOBJHDR header;
|
|---|
| 75 | WINEREGION *rgn;
|
|---|
| 76 | } RGNOBJ;
|
|---|
| 77 |
|
|---|
| 78 | /* 1 if two RECTs overlap.
|
|---|
| 79 | * 0 if two RECTs do not overlap.
|
|---|
| 80 | */
|
|---|
| 81 | #define EXTENTCHECK(r1, r2) \
|
|---|
| 82 | ((r1)->right > (r2)->left && \
|
|---|
| 83 | (r1)->left < (r2)->right && \
|
|---|
| 84 | (r1)->bottom > (r2)->top && \
|
|---|
| 85 | (r1)->top < (r2)->bottom)
|
|---|
| 86 |
|
|---|
| 87 | /*
|
|---|
| 88 | * Check to see if there is enough memory in the present region.
|
|---|
| 89 | */
|
|---|
| 90 | #define MEMCHECK(reg, rect, firstrect){\
|
|---|
| 91 | if ((reg)->numRects >= ((reg)->size - 1)){\
|
|---|
| 92 | (firstrect) = HeapReAlloc( SystemHeap, 0, \
|
|---|
| 93 | (firstrect), (2 * (sizeof(RECT)) * ((reg)->size)));\
|
|---|
| 94 | if ((firstrect) == 0)\
|
|---|
| 95 | return;\
|
|---|
| 96 | (reg)->size *= 2;\
|
|---|
| 97 | (rect) = &(firstrect)[(reg)->numRects];\
|
|---|
| 98 | }\
|
|---|
| 99 | }
|
|---|
| 100 |
|
|---|
| 101 | #define EMPTY_REGION(pReg) { \
|
|---|
| 102 | (pReg)->numRects = 0; \
|
|---|
| 103 | (pReg)->extents.left = (pReg)->extents.top = 0; \
|
|---|
| 104 | (pReg)->extents.right = (pReg)->extents.bottom = 0; \
|
|---|
| 105 | (pReg)->type = NULLREGION; \
|
|---|
| 106 | }
|
|---|
| 107 |
|
|---|
| 108 | #define REGION_NOT_EMPTY(pReg) pReg->numRects
|
|---|
| 109 |
|
|---|
| 110 | #define INRECT(r, x, y) \
|
|---|
| 111 | ( ( ((r).right > x)) && \
|
|---|
| 112 | ( ((r).left <= x)) && \
|
|---|
| 113 | ( ((r).bottom > y)) && \
|
|---|
| 114 | ( ((r).top <= y)) )
|
|---|
| 115 |
|
|---|
| 116 |
|
|---|
| 117 | /*
|
|---|
| 118 | * number of points to buffer before sending them off
|
|---|
| 119 | * to scanlines() : Must be an even number
|
|---|
| 120 | */
|
|---|
| 121 | #define NUMPTSTOBUFFER 200
|
|---|
| 122 |
|
|---|
| 123 | /*
|
|---|
| 124 | * used to allocate buffers for points and link
|
|---|
| 125 | * the buffers together
|
|---|
| 126 | */
|
|---|
| 127 |
|
|---|
| 128 | typedef struct _POINTBLOCK {
|
|---|
| 129 | POINT pts[NUMPTSTOBUFFER];
|
|---|
| 130 | struct _POINTBLOCK *next;
|
|---|
| 131 | } POINTBLOCK;
|
|---|
| 132 |
|
|---|
| 133 |
|
|---|
| 134 |
|
|---|
| 135 | /*
|
|---|
| 136 | * This file contains a few macros to help track
|
|---|
| 137 | * the edge of a filled object. The object is assumed
|
|---|
| 138 | * to be filled in scanline order, and thus the
|
|---|
| 139 | * algorithm used is an extension of Bresenham's line
|
|---|
| 140 | * drawing algorithm which assumes that y is always the
|
|---|
| 141 | * major axis.
|
|---|
| 142 | * Since these pieces of code are the same for any filled shape,
|
|---|
| 143 | * it is more convenient to gather the library in one
|
|---|
| 144 | * place, but since these pieces of code are also in
|
|---|
| 145 | * the inner loops of output primitives, procedure call
|
|---|
| 146 | * overhead is out of the question.
|
|---|
| 147 | * See the author for a derivation if needed.
|
|---|
| 148 | */
|
|---|
| 149 |
|
|---|
| 150 |
|
|---|
| 151 | /*
|
|---|
| 152 | * In scan converting polygons, we want to choose those pixels
|
|---|
| 153 | * which are inside the polygon. Thus, we add .5 to the starting
|
|---|
| 154 | * x coordinate for both left and right edges. Now we choose the
|
|---|
| 155 | * first pixel which is inside the pgon for the left edge and the
|
|---|
| 156 | * first pixel which is outside the pgon for the right edge.
|
|---|
| 157 | * Draw the left pixel, but not the right.
|
|---|
| 158 | *
|
|---|
| 159 | * How to add .5 to the starting x coordinate:
|
|---|
| 160 | * If the edge is moving to the right, then subtract dy from the
|
|---|
| 161 | * error term from the general form of the algorithm.
|
|---|
| 162 | * If the edge is moving to the left, then add dy to the error term.
|
|---|
| 163 | *
|
|---|
| 164 | * The reason for the difference between edges moving to the left
|
|---|
| 165 | * and edges moving to the right is simple: If an edge is moving
|
|---|
| 166 | * to the right, then we want the algorithm to flip immediately.
|
|---|
| 167 | * If it is moving to the left, then we don't want it to flip until
|
|---|
| 168 | * we traverse an entire pixel.
|
|---|
| 169 | */
|
|---|
| 170 | #define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
|
|---|
| 171 | int dx; /* local storage */ \
|
|---|
| 172 | \
|
|---|
| 173 | /* \
|
|---|
| 174 | * if the edge is horizontal, then it is ignored \
|
|---|
| 175 | * and assumed not to be processed. Otherwise, do this stuff. \
|
|---|
| 176 | */ \
|
|---|
| 177 | if ((dy) != 0) { \
|
|---|
| 178 | xStart = (x1); \
|
|---|
| 179 | dx = (x2) - xStart; \
|
|---|
| 180 | if (dx < 0) { \
|
|---|
| 181 | m = dx / (dy); \
|
|---|
| 182 | m1 = m - 1; \
|
|---|
| 183 | incr1 = -2 * dx + 2 * (dy) * m1; \
|
|---|
| 184 | incr2 = -2 * dx + 2 * (dy) * m; \
|
|---|
| 185 | d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
|
|---|
| 186 | } else { \
|
|---|
| 187 | m = dx / (dy); \
|
|---|
| 188 | m1 = m + 1; \
|
|---|
| 189 | incr1 = 2 * dx - 2 * (dy) * m1; \
|
|---|
| 190 | incr2 = 2 * dx - 2 * (dy) * m; \
|
|---|
| 191 | d = -2 * m * (dy) + 2 * dx; \
|
|---|
| 192 | } \
|
|---|
| 193 | } \
|
|---|
| 194 | }
|
|---|
| 195 |
|
|---|
| 196 | #define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
|
|---|
| 197 | if (m1 > 0) { \
|
|---|
| 198 | if (d > 0) { \
|
|---|
| 199 | minval += m1; \
|
|---|
| 200 | d += incr1; \
|
|---|
| 201 | } \
|
|---|
| 202 | else { \
|
|---|
| 203 | minval += m; \
|
|---|
| 204 | d += incr2; \
|
|---|
| 205 | } \
|
|---|
| 206 | } else {\
|
|---|
| 207 | if (d >= 0) { \
|
|---|
| 208 | minval += m1; \
|
|---|
| 209 | d += incr1; \
|
|---|
| 210 | } \
|
|---|
| 211 | else { \
|
|---|
| 212 | minval += m; \
|
|---|
| 213 | d += incr2; \
|
|---|
| 214 | } \
|
|---|
| 215 | } \
|
|---|
| 216 | }
|
|---|
| 217 |
|
|---|
| 218 | /*
|
|---|
| 219 | * This structure contains all of the information needed
|
|---|
| 220 | * to run the bresenham algorithm.
|
|---|
| 221 | * The variables may be hardcoded into the declarations
|
|---|
| 222 | * instead of using this structure to make use of
|
|---|
| 223 | * register declarations.
|
|---|
| 224 | */
|
|---|
| 225 | typedef struct {
|
|---|
| 226 | INT minor_axis; /* minor axis */
|
|---|
| 227 | INT d; /* decision variable */
|
|---|
| 228 | INT m, m1; /* slope and slope+1 */
|
|---|
| 229 | INT incr1, incr2; /* error increments */
|
|---|
| 230 | } BRESINFO;
|
|---|
| 231 |
|
|---|
| 232 |
|
|---|
| 233 | #define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
|
|---|
| 234 | BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \
|
|---|
| 235 | bres.m, bres.m1, bres.incr1, bres.incr2)
|
|---|
| 236 |
|
|---|
| 237 | #define BRESINCRPGONSTRUCT(bres) \
|
|---|
| 238 | BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
|
|---|
| 239 |
|
|---|
| 240 |
|
|---|
| 241 |
|
|---|
| 242 | /*
|
|---|
| 243 | * These are the data structures needed to scan
|
|---|
| 244 | * convert regions. Two different scan conversion
|
|---|
| 245 | * methods are available -- the even-odd method, and
|
|---|
| 246 | * the winding number method.
|
|---|
| 247 | * The even-odd rule states that a point is inside
|
|---|
| 248 | * the polygon if a ray drawn from that point in any
|
|---|
| 249 | * direction will pass through an odd number of
|
|---|
| 250 | * path segments.
|
|---|
| 251 | * By the winding number rule, a point is decided
|
|---|
| 252 | * to be inside the polygon if a ray drawn from that
|
|---|
| 253 | * point in any direction passes through a different
|
|---|
| 254 | * number of clockwise and counter-clockwise path
|
|---|
| 255 | * segments.
|
|---|
| 256 | *
|
|---|
| 257 | * These data structures are adapted somewhat from
|
|---|
| 258 | * the algorithm in (Foley/Van Dam) for scan converting
|
|---|
| 259 | * polygons.
|
|---|
| 260 | * The basic algorithm is to start at the top (smallest y)
|
|---|
| 261 | * of the polygon, stepping down to the bottom of
|
|---|
| 262 | * the polygon by incrementing the y coordinate. We
|
|---|
| 263 | * keep a list of edges which the current scanline crosses,
|
|---|
| 264 | * sorted by x. This list is called the Active Edge Table (AET)
|
|---|
| 265 | * As we change the y-coordinate, we update each entry in
|
|---|
| 266 | * in the active edge table to reflect the edges new xcoord.
|
|---|
| 267 | * This list must be sorted at each scanline in case
|
|---|
| 268 | * two edges intersect.
|
|---|
| 269 | * We also keep a data structure known as the Edge Table (ET),
|
|---|
| 270 | * which keeps track of all the edges which the current
|
|---|
| 271 | * scanline has not yet reached. The ET is basically a
|
|---|
| 272 | * list of ScanLineList structures containing a list of
|
|---|
| 273 | * edges which are entered at a given scanline. There is one
|
|---|
| 274 | * ScanLineList per scanline at which an edge is entered.
|
|---|
| 275 | * When we enter a new edge, we move it from the ET to the AET.
|
|---|
| 276 | *
|
|---|
| 277 | * From the AET, we can implement the even-odd rule as in
|
|---|
| 278 | * (Foley/Van Dam).
|
|---|
| 279 | * The winding number rule is a little trickier. We also
|
|---|
| 280 | * keep the EdgeTableEntries in the AET linked by the
|
|---|
| 281 | * nextWETE (winding EdgeTableEntry) link. This allows
|
|---|
| 282 | * the edges to be linked just as before for updating
|
|---|
| 283 | * purposes, but only uses the edges linked by the nextWETE
|
|---|
| 284 | * link as edges representing spans of the polygon to
|
|---|
| 285 | * drawn (as with the even-odd rule).
|
|---|
| 286 | */
|
|---|
| 287 |
|
|---|
| 288 | /*
|
|---|
| 289 | * for the winding number rule
|
|---|
| 290 | */
|
|---|
| 291 | #define CLOCKWISE 1
|
|---|
| 292 | #define COUNTERCLOCKWISE -1
|
|---|
| 293 |
|
|---|
| 294 | typedef struct _EdgeTableEntry {
|
|---|
| 295 | INT ymax; /* ycoord at which we exit this edge. */
|
|---|
| 296 | BRESINFO bres; /* Bresenham info to run the edge */
|
|---|
| 297 | struct _EdgeTableEntry *next; /* next in the list */
|
|---|
| 298 | struct _EdgeTableEntry *back; /* for insertion sort */
|
|---|
| 299 | struct _EdgeTableEntry *nextWETE; /* for winding num rule */
|
|---|
| 300 | int ClockWise; /* flag for winding number rule */
|
|---|
| 301 | } EdgeTableEntry;
|
|---|
| 302 |
|
|---|
| 303 |
|
|---|
| 304 | typedef struct _ScanLineList{
|
|---|
| 305 | INT scanline; /* the scanline represented */
|
|---|
| 306 | EdgeTableEntry *edgelist; /* header node */
|
|---|
| 307 | struct _ScanLineList *next; /* next in the list */
|
|---|
| 308 | } ScanLineList;
|
|---|
| 309 |
|
|---|
| 310 |
|
|---|
| 311 | typedef struct {
|
|---|
| 312 | INT ymax; /* ymax for the polygon */
|
|---|
| 313 | INT ymin; /* ymin for the polygon */
|
|---|
| 314 | ScanLineList scanlines; /* header node */
|
|---|
| 315 | } EdgeTable;
|
|---|
| 316 |
|
|---|
| 317 |
|
|---|
| 318 | /*
|
|---|
| 319 | * Here is a struct to help with storage allocation
|
|---|
| 320 | * so we can allocate a big chunk at a time, and then take
|
|---|
| 321 | * pieces from this heap when we need to.
|
|---|
| 322 | */
|
|---|
| 323 | #define SLLSPERBLOCK 25
|
|---|
| 324 |
|
|---|
| 325 | typedef struct _ScanLineListBlock {
|
|---|
| 326 | ScanLineList SLLs[SLLSPERBLOCK];
|
|---|
| 327 | struct _ScanLineListBlock *next;
|
|---|
| 328 | } ScanLineListBlock;
|
|---|
| 329 |
|
|---|
| 330 |
|
|---|
| 331 | /*
|
|---|
| 332 | *
|
|---|
| 333 | * a few macros for the inner loops of the fill code where
|
|---|
| 334 | * performance considerations don't allow a procedure call.
|
|---|
| 335 | *
|
|---|
| 336 | * Evaluate the given edge at the given scanline.
|
|---|
| 337 | * If the edge has expired, then we leave it and fix up
|
|---|
| 338 | * the active edge table; otherwise, we increment the
|
|---|
| 339 | * x value to be ready for the next scanline.
|
|---|
| 340 | * The winding number rule is in effect, so we must notify
|
|---|
| 341 | * the caller when the edge has been removed so he
|
|---|
| 342 | * can reorder the Winding Active Edge Table.
|
|---|
| 343 | */
|
|---|
| 344 | #define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
|
|---|
| 345 | if (pAET->ymax == y) { /* leaving this edge */ \
|
|---|
| 346 | pPrevAET->next = pAET->next; \
|
|---|
| 347 | pAET = pPrevAET->next; \
|
|---|
| 348 | fixWAET = 1; \
|
|---|
| 349 | if (pAET) \
|
|---|
| 350 | pAET->back = pPrevAET; \
|
|---|
| 351 | } \
|
|---|
| 352 | else { \
|
|---|
| 353 | BRESINCRPGONSTRUCT(pAET->bres); \
|
|---|
| 354 | pPrevAET = pAET; \
|
|---|
| 355 | pAET = pAET->next; \
|
|---|
| 356 | } \
|
|---|
| 357 | }
|
|---|
| 358 |
|
|---|
| 359 |
|
|---|
| 360 | /*
|
|---|
| 361 | * Evaluate the given edge at the given scanline.
|
|---|
| 362 | * If the edge has expired, then we leave it and fix up
|
|---|
| 363 | * the active edge table; otherwise, we increment the
|
|---|
| 364 | * x value to be ready for the next scanline.
|
|---|
| 365 | * The even-odd rule is in effect.
|
|---|
| 366 | */
|
|---|
| 367 | #define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
|
|---|
| 368 | if (pAET->ymax == y) { /* leaving this edge */ \
|
|---|
| 369 | pPrevAET->next = pAET->next; \
|
|---|
| 370 | pAET = pPrevAET->next; \
|
|---|
| 371 | if (pAET) \
|
|---|
| 372 | pAET->back = pPrevAET; \
|
|---|
| 373 | } \
|
|---|
| 374 | else { \
|
|---|
| 375 | BRESINCRPGONSTRUCT(pAET->bres); \
|
|---|
| 376 | pPrevAET = pAET; \
|
|---|
| 377 | pAET = pAET->next; \
|
|---|
| 378 | } \
|
|---|
| 379 | }
|
|---|
| 380 |
|
|---|
| 381 | extern BOOL REGION_DeleteObject( HRGN hrgn, RGNOBJ * obj );
|
|---|
| 382 | extern BOOL REGION_UnionRectWithRgn( HRGN hrgn, const RECT *lpRect );
|
|---|
| 383 | extern HRGN REGION_CropRgn( HRGN hDst, HRGN hSrc, const RECT *lpRect, const POINT *lpPt );
|
|---|
| 384 | extern BOOL REGION_FrameRgn( HRGN dest, HRGN src, INT x, INT y );
|
|---|
| 385 | extern BOOL REGION_LPTODP( HDC hdc, HRGN hDest, HRGN hSrc );
|
|---|
| 386 |
|
|---|
| 387 | #endif /* __WINE_REGION_H */
|
|---|
| 388 |
|
|---|
| 389 |
|
|---|