BOOL WINAPI UnionRect( LPRECT dest, const RECT *src1, const RECT *src2 ) { if (IsRectEmpty(src1)) { if (IsRectEmpty(src2)) { SetRectEmpty( dest ); return FALSE; } else *dest = *src2; } else { if (IsRectEmpty(src2)) *dest = *src1; else { dest->left = MWMIN( src1->left, src2->left ); dest->right = MWMAX( src1->right, src2->right ); dest->top = MWMIN( src1->top, src2->top ); dest->bottom = MWMAX( src1->bottom, src2->bottom ); } } return TRUE; }
/* * Rectangle-related functions * * Copyright 1993, 1996 Alexandre Julliard * */ BOOL WINAPI IntersectRect( LPRECT dest, const RECT *src1, const RECT *src2 ) { if (IsRectEmpty(src1) || IsRectEmpty(src2) || (src1->left >= src2->right) || (src2->left >= src1->right) || (src1->top >= src2->bottom) || (src2->top >= src1->bottom)) { SetRectEmpty( dest ); return FALSE; } dest->left = MWMAX( src1->left, src2->left ); dest->right = MWMIN( src1->right, src2->right ); dest->top = MWMAX( src1->top, src2->top ); dest->bottom = MWMIN( src1->bottom, src2->bottom ); return TRUE; }
/* * Draw a window's background pixmap. * * The flags mean: * GR_BACKGROUND_TILE- tile the pixmap across the window (default). * GR_BACKGROUND_TOPLEFT- draw the pixmap at (0,0) relative to the window. * GR_BACKGROUND_CENTER- draw the pixmap in the middle of the window. * GR_BACKGROUND_STRETCH- stretch the pixmap within the window. * GR_BACKGROUND_TRANS- if the pixmap is smaller than the window and not * using tile mode, there will be gaps around the pixmap. This flag causes * to not fill in the spaces with the background colour. */ void GsDrawBackgroundPixmap(GR_WINDOW *wp, GR_PIXMAP *pm, GR_COORD x, GR_COORD y, GR_SIZE width, GR_SIZE height) { GR_SIZE destwidth, destheight, fillwidth, fillheight, pmwidth, pmheight; GR_COORD fromx, fromy, destx, desty, pixmapx = 0, pixmapy = 0; if(wp->bgpixmapflags & GR_BACKGROUND_STRETCH) { /* must use whole window coords or stretch will have incorrect ratios*/ GdStretchBlit(wp->psd, wp->x, wp->y, wp->x + wp->width, wp->y + wp->height, pm->psd, 0, 0, pm->width - 1, pm->height - 1, MWROP_SRC_OVER); return; } if(wp->bgpixmapflags == GR_BACKGROUND_TILE) { GsTileBackgroundPixmap(wp, pm, x, y, width, height); return; } if(wp->bgpixmapflags & GR_BACKGROUND_CENTER) { if (pm->width < wp->width) pixmapx = (wp->width - pm->width) / 2; if (pm->height < wp->height) pixmapy = (wp->height - pm->height) / 2; } /* topleft & center calcs*/ pmwidth = MWMIN(pm->width, wp->width); pmheight = MWMIN(pm->height, wp->height); if(x > pixmapx) { destx = x; fromx = x - pixmapx; destwidth = pixmapx + pmwidth - x; } else { destx = pixmapx; fromx = 0; destwidth = x + width - pixmapx; } if(y > pixmapy) { desty = y; fromy = y - pixmapy; destheight = pixmapy + pmheight - desty; } else { desty = pixmapy; fromy = 0; destheight = y + height - pixmapy; } if(destwidth > 0 && destheight > 0) { destwidth = MWMIN(width, destwidth); destheight = MWMIN(height, destheight); GdBlit(wp->psd, wp->x + destx, wp->y + desty, destwidth, destheight, pm->psd, fromx, fromy, MWROP_SRC_OVER); } if(wp->bgpixmapflags & GR_BACKGROUND_TRANS) return; /* Fill in the gaps around the pixmap */ if(x < pixmapx) { fillwidth = pixmapx - x; if(fillwidth > width) fillwidth = width; fillheight = height; GdFillRect(wp->psd, wp->x + x, wp->y + y, fillwidth, fillheight); } if(x + width > pixmapx + pmwidth) { fillwidth = (x + width) - (pixmapx + pmwidth); if(fillwidth > width) fillwidth = width; fillheight = height; if(x < pixmapx + pmwidth) destx = pixmapx + pmwidth + wp->x; else destx = x + wp->x; GdFillRect(wp->psd, destx, wp->y + y, fillwidth, fillheight); } if(y < pixmapy) { fillheight = pixmapy - y; if(fillheight > height) fillheight = height; if(x < pixmapx) destx = pixmapx + wp->x; else destx = x + wp->x; if(x + width > pixmapx + pmwidth) fillwidth = pixmapx + pmwidth - destx; else fillwidth = x + width - destx; if(fillwidth > 0 && fillheight > 0) GdFillRect(wp->psd, destx, wp->y + y, fillwidth, fillheight); } if(y + height > pixmapy + pmheight) { fillheight = (y + height) - (pixmapy + pmheight); if(fillheight > height) fillheight = height; if(x < pixmapx) destx = pixmapx + wp->x; else destx = x + wp->x; if(y < pixmapy + pmheight) desty = pixmapy + pmheight + wp->y; else desty = y + wp->y; if(x + width > pixmapx + pmwidth) fillwidth = pixmapx + pmwidth - destx; else fillwidth = x + width - destx; if(fillwidth > 0 && fillheight > 0) GdFillRect(wp->psd, destx, desty, fillwidth, fillheight); } }
void GdFillPoly(PSD psd, int count, MWPOINT *pointtable) { MWCOORD xl = 0, xr = 0; /* x vals of left and right edges */ int dl = 0, dr = 0; /* decision variables */ int ml = 0, m1l = 0; /* left edge slope and slope+1 */ int mr = 0, m1r = 0; /* right edge slope and slope+1 */ int incr1l = 0, incr2l = 0; /* left edge error increments */ int incr1r = 0, incr2r = 0; /* right edge error increments */ int dy; /* delta y */ MWCOORD y; /* current scanline */ int left, right; /* indices to first endpoints */ int i; /* loop counter */ int nextleft, nextright; /* indices to second endpoints */ MWPOINT *ptsOut, *FirstPoint;/* output buffer */ MWCOORD *width, *FirstWidth;/* output buffer */ int imin; /* index of smallest vertex (in y)*/ int ymin; /* y-extents of polygon */ int ymax; /* * find leftx, bottomy, rightx, topy, and the index * of bottomy. */ imin = getPolyYBounds(pointtable, count, &ymin, &ymax); if (gr_fillmode != MWFILL_SOLID) { int xmin, xmax; getPolyXBounds(pointtable, count, &xmin, &xmax); set_ts_origin(xmin, ymin); } dy = ymax - ymin + 1; if ((count < 3) || (dy < 0)) return; ptsOut = FirstPoint = (MWPOINT *)ALLOCA(sizeof(MWPOINT) * dy); width = FirstWidth = (MWCOORD *)ALLOCA(sizeof(MWCOORD) * dy); if(!FirstPoint || !FirstWidth) { if (FirstWidth) FREEA(FirstWidth); if (FirstPoint) FREEA(FirstPoint); return; } nextleft = nextright = imin; y = pointtable[nextleft].y; /* * loop through all edges of the polygon */ do { /* * add a left edge if we need to */ if (pointtable[nextleft].y == y) { left = nextleft; /* * find the next edge, considering the end * conditions of the array. */ nextleft++; if (nextleft >= count) nextleft = 0; /* * now compute all of the random information * needed to run the iterative algorithm. */ BRESINITPGON(pointtable[nextleft].y-pointtable[left].y, pointtable[left].x,pointtable[nextleft].x, xl, dl, ml, m1l, incr1l, incr2l); } /* * add a right edge if we need to */ if (pointtable[nextright].y == y) { right = nextright; /* * find the next edge, considering the end * conditions of the array. */ nextright--; if (nextright < 0) nextright = count-1; /* * now compute all of the random information * needed to run the iterative algorithm. */ BRESINITPGON(pointtable[nextright].y-pointtable[right].y, pointtable[right].x,pointtable[nextright].x, xr, dr, mr, m1r, incr1r, incr2r); } /* * generate scans to fill while we still have * a right edge as well as a left edge. */ i = MWMIN(pointtable[nextleft].y, pointtable[nextright].y) - y; /* in case we're called with non-convex polygon */ if(i < 0) { FREEA(FirstWidth); FREEA(FirstPoint); return; } while (i-- > 0) { ptsOut->y = y; /* * reverse the edges if necessary */ if (xl < xr) { *(width++) = xr - xl; (ptsOut++)->x = xl; } else { *(width++) = xl - xr; (ptsOut++)->x = xr; } y++; /* increment down the edges */ BRESINCRPGON(dl, xl, ml, m1l, incr1l, incr2l); BRESINCRPGON(dr, xr, mr, m1r, incr1r, incr2r); } } while (y != ymax); /* * Finally, fill the spans */ i = ptsOut-FirstPoint; ptsOut = FirstPoint; width = FirstWidth; while (--i >= 0) { /* calc x extent from width*/ int e = *width++ - 1; if (e >= 0) { if (gr_fillmode != MWFILL_SOLID) ts_drawrow(psd, ptsOut->x, ptsOut->x + e, ptsOut->y); else drawrow(psd, ptsOut->x, ptsOut->x + e, ptsOut->y); } ++ptsOut; } FREEA(FirstWidth); FREEA(FirstPoint); GdFixCursor(psd); }
/* * GdAllocPolyPolygonRegion */ MWCLIPREGION * GdAllocPolyPolygonRegion(MWPOINT *points, int *count, int nbpolygons, int mode) { MWCLIPREGION *rgn; EdgeTableEntry *pAET; /* Active Edge Table */ int y; /* current scanline */ int iPts = 0; /* number of pts in buffer */ EdgeTableEntry *pWETE; /* Winding Edge Table Entry*/ ScanLineList *pSLL; /* current scanLineList */ MWPOINT *pts; /* output buffer */ EdgeTableEntry *pPrevAET; /* ptr to previous AET */ EdgeTable ET; /* header node for ET */ EdgeTableEntry AET; /* header node for AET */ EdgeTableEntry *pETEs; /* EdgeTableEntries pool */ ScanLineListBlock SLLBlock; /* header for scanlinelist */ int fixWAET = FALSE; POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */ POINTBLOCK *tmpPtBlock; int numFullPtBlocks = 0; int poly, total; if(!(rgn = GdAllocRegion())) return NULL; /* special case a rectangle */ if (((nbpolygons == 1) && ((*count == 4) || ((*count == 5) && (points[4].x == points[0].x) && (points[4].y == points[0].y)))) && (((points[0].y == points[1].y) && (points[1].x == points[2].x) && (points[2].y == points[3].y) && (points[3].x == points[0].x)) || ((points[0].x == points[1].x) && (points[1].y == points[2].y) && (points[2].x == points[3].x) && (points[3].y == points[0].y)))) { GdSetRectRegion( rgn, MWMIN(points[0].x, points[2].x), MWMIN(points[0].y, points[2].y), MWMAX(points[0].x, points[2].x), MWMAX(points[0].y, points[2].y) ); return rgn; } for(poly = total = 0; poly < nbpolygons; poly++) total += count[poly]; if (! (pETEs = malloc( sizeof(EdgeTableEntry) * total ))) { GdDestroyRegion( rgn ); return 0; } pts = FirstPtBlock.pts; REGION_CreateETandAET(count, nbpolygons, points, &ET, &AET, pETEs, &SLLBlock); pSLL = ET.scanlines.next; curPtBlock = &FirstPtBlock; if (mode != MWPOLY_WINDING) { /* * for each scanline */ for (y = ET.ymin; y < ET.ymax; y++) { /* * Add a new edge to the active edge table when we * get to the next edge. */ if (pSLL != NULL && y == pSLL->scanline) { REGION_loadAET(&AET, pSLL->edgelist); pSLL = pSLL->next; } pPrevAET = &AET; pAET = AET.next; /* * for each active edge */ while (pAET) { pts->x = pAET->bres.minor_axis, pts->y = y; pts++, iPts++; /* * send out the buffer */ if (iPts == NUMPTSTOBUFFER) { tmpPtBlock = malloc( sizeof(POINTBLOCK)); if(!tmpPtBlock) { return 0; } curPtBlock->next = tmpPtBlock; curPtBlock = tmpPtBlock; pts = curPtBlock->pts; numFullPtBlocks++; iPts = 0; } EVALUATEEDGEEVENODD(pAET, pPrevAET, y); } REGION_InsertionSort(&AET); } } else { /* * for each scanline */ for (y = ET.ymin; y < ET.ymax; y++) { /* * Add a new edge to the active edge table when we * get to the next edge. */ if (pSLL != NULL && y == pSLL->scanline) { REGION_loadAET(&AET, pSLL->edgelist); REGION_computeWAET(&AET); pSLL = pSLL->next; } pPrevAET = &AET; pAET = AET.next; pWETE = pAET; /* * for each active edge */ while (pAET) { /* * add to the buffer only those edges that * are in the Winding active edge table. */ if (pWETE == pAET) { pts->x = pAET->bres.minor_axis, pts->y = y; pts++, iPts++; /* * send out the buffer */ if (iPts == NUMPTSTOBUFFER) { tmpPtBlock = malloc( sizeof(POINTBLOCK) ); if(!tmpPtBlock) { return 0; } curPtBlock->next = tmpPtBlock; curPtBlock = tmpPtBlock; pts = curPtBlock->pts; numFullPtBlocks++; iPts = 0; } pWETE = pWETE->nextWETE; } EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET); } /* * recompute the winding active edge table if * we just resorted or have exited an edge. */ if (REGION_InsertionSort(&AET) || fixWAET) { REGION_computeWAET(&AET); fixWAET = FALSE; } } } REGION_FreeStorage(SLLBlock.next); REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, rgn); for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;) { tmpPtBlock = curPtBlock->next; free( curPtBlock ); curPtBlock = tmpPtBlock; } free( pETEs ); return rgn; }