|
|
1.1 ! root 1: #ifndef lint ! 2: static char *rcsid_makemask_c = "$Header: makemask.c,v 10.1 86/11/19 10:42:30 jg Exp $"; ! 3: #endif lint ! 4: /* makemask.c - builds a mask from vertex list ! 5: * ! 6: * MakeMask builds a mask from vertex list ! 7: * AddEdge adds edges to edge table for fill operation ! 8: * FillMask fills mask using scan line algorithm ! 9: * ! 10: * Author: ! 11: * Scott Bates ! 12: * Brown University ! 13: * IRIS, Box 1946 ! 14: * Providence, RI 02912 ! 15: * ! 16: * ! 17: * Copyright (c) 1986 Brown University ! 18: * ! 19: * Permission to use, copy, modify and distribute this software and its ! 20: * documentation for any purpose and without fee is hereby granted, provided ! 21: * that the above copyright notice appear in all copies, and that both ! 22: * that copyright notice and this permission notice appear in supporting ! 23: * documentation, and that the name of Brown University not be used in ! 24: * advertising or publicity pertaining to distribution of the software ! 25: * without specific, written prior permission. Brown University makes no ! 26: * representations about the suitability of this software for any purpose. ! 27: * It is provided "as-is" without express or implied warranty. ! 28: */ ! 29: ! 30: #include "private.h" ! 31: #include "makemask.h" ! 32: #include "pathlist.h" ! 33: ! 34: /* ! 35: * Build mask from vertex list ! 36: */ ! 37: ! 38: BITMAP * ! 39: MakeMask(Verts, VertCount) ! 40: Vertex *Verts; ! 41: int VertCount; ! 42: { ! 43: register Vertex *LastPoint; ! 44: register Vertex *ThisPoint; ! 45: register Vertex *NextPoint; ! 46: register Vertex *Poly; ! 47: register struct Polygon *PolyData; ! 48: register End; ! 49: int Width = 0, Height = 0; ! 50: int FirstScanLine = 10240; ! 51: int Index, Size; ! 52: BITMAP *BitMap; ! 53: struct Polygon *FirstPoly; ! 54: ! 55: #ifdef TRACE_X ! 56: fprintf (stderr, "In MakeMask\n"); ! 57: fflush (stderr); ! 58: #endif TRACE_X ! 59: ! 60: /* ! 61: * Allocate space for polygon pointers ! 62: */ ! 63: ! 64: FirstPoly = (struct Polygon *) calloc(VertCount << 1, ! 65: sizeof(struct Polygon)); ! 66: if (FirstPoly == NULL) { ! 67: return (NULL); ! 68: } ! 69: ! 70: /* ! 71: * Determine width and height of off-screen bitmap ! 72: * and the first scan line to be filled. ! 73: */ ! 74: ! 75: PolyData = FirstPoly - 1; ! 76: for(Index = 0; Index < VertCount; Index += 2) { ! 77: if(Width < Verts[Index].x) ! 78: Width = Verts[Index].x; ! 79: if(Height < Verts[Index].y) ! 80: Height = Verts[Index].y; ! 81: if(FirstScanLine > Verts[Index].y) ! 82: FirstScanLine = Verts[Index].y; ! 83: if(Verts[Index].flags & START_OF_CLOSED_POLY) { ! 84: (++PolyData)->PolyPoints = &Verts[Index]; ! 85: PolyData->PolyCount = 2; ! 86: } else { ! 87: PolyData->PolyCount += 2; ! 88: } ! 89: } ! 90: (++PolyData)->PolyPoints = (Vertex *)NULL; ! 91: ! 92: /* ! 93: * Allocate space for bitmap structure ! 94: */ ! 95: ! 96: BitMap = (BITMAP *) Xalloc (sizeof (BITMAP)); ! 97: ! 98: /* ! 99: * Fill in bitmap structure ! 100: * ! 101: * NOTE: The bitmaps width has been rounded up ! 102: * to the nearest 32 bit bound. This was done ! 103: * so that the mask could be fill 32 bits at ! 104: * a time instead of the usual 16. ! 105: */ ! 106: ! 107: BitMap->width = Width = ((Width + 32) >> 5) << 5; ! 108: BitMap->height = ++Height; ! 109: ! 110: /* ! 111: * Allocated space to hold bitimage data ! 112: */ ! 113: ! 114: if((BitMap->data = calloc(1, BitmapSize(Width, Height))) == NULL) { ! 115: free ((caddr_t) BitMap); ! 116: return (NULL); ! 117: } ! 118: ! 119: /* ! 120: * Allocate space for edges and reset EdgeCount ! 121: */ ! 122: ! 123: Edges = (struct edge *) calloc(VertCount << 1, sizeof(struct edge)); ! 124: if (Edges == NULL) { ! 125: free ((caddr_t) BitMap->data); ! 126: free ((caddr_t) BitMap); ! 127: return (NULL); ! 128: } ! 129: if ((EdgeTable = (struct edge **)calloc(Height + 1, 4)) == NULL) { ! 130: free((caddr_t) Edges); ! 131: free ((caddr_t) BitMap->data); ! 132: free ((caddr_t) BitMap); ! 133: return (NULL); ! 134: } ! 135: EdgeCount = 0; ! 136: ! 137: /* ! 138: * Add the edges of all polygons to ! 139: * the edge table ! 140: */ ! 141: ! 142: Poly = (PolyData = FirstPoly)->PolyPoints; ! 143: do { ! 144: /* ! 145: * Test for valid polygon ! 146: */ ! 147: ! 148: if(PolyData->PolyCount > 5) { ! 149: /* ! 150: * AddEdge() initialization before adding ! 151: * each polygon ! 152: */ ! 153: ! 154: ShortenStartOfEdge = 0; ! 155: Direction = Poly[PolyData->PolyCount - 2].y > Poly[0].y; ! 156: End = PolyData->PolyCount - 4; ! 157: LastPoint = Poly; ! 158: ThisPoint = NextPoint = Poly + 2; ! 159: ! 160: /* ! 161: * Add edges of this polygon to edge table ! 162: */ ! 163: ! 164: while(End) { ! 165: NextPoint += 2; ! 166: AddEdge(LastPoint, ThisPoint, NextPoint); ! 167: LastPoint = ThisPoint; ! 168: ThisPoint = NextPoint; ! 169: End -= 2; ! 170: } ! 171: NextPoint = &Poly[0]; ! 172: AddEdge(LastPoint, ThisPoint, NextPoint); ! 173: LastPoint = ThisPoint; ! 174: ThisPoint = NextPoint; ! 175: NextPoint += 2; ! 176: AddEdge(LastPoint, ThisPoint, NextPoint); ! 177: } ! 178: ! 179: /* ! 180: * Increment pointer to next polygon to add ! 181: */ ! 182: ! 183: Poly = (++PolyData)->PolyPoints; ! 184: ! 185: } while(Poly); ! 186: ! 187: if(EdgeCount) { ! 188: /* ! 189: * Fill the mask ! 190: */ ! 191: ! 192: FillMask(BitMap, FirstScanLine); ! 193: ! 194: /* ! 195: * Frame mask to remove any abnomalities ! 196: */ ! 197: ! 198: for (Index = 0; Index < VertCount; Index += 2) { ! 199: SinglePixelLine(BitMap, Verts[Index].x, Verts[Index].y, ! 200: Verts[Index + 1].x, Verts[Index + 1].y, ! 201: (CLIP *) 0, GXor, DrawSolidLine, 1, 0, ! 202: 0, 0, 0); ! 203: } ! 204: ! 205: /* ! 206: * Return mask bitmap ! 207: */ ! 208: ! 209: return(BitMap); ! 210: } ! 211: ! 212: /* ! 213: * Indicate nothing to fill ! 214: */ ! 215: ! 216: return(NULL); ! 217: } ! 218: ! 219: /* ! 220: * Add edge to edge table ! 221: */ ! 222: ! 223: static ! 224: AddEdge(LastPoint, ThisPoint, NextPoint) ! 225: register Vertex *LastPoint; ! 226: register Vertex *ThisPoint; ! 227: register Vertex *NextPoint; ! 228: { ! 229: register struct edge *NewEdge = &Edges[EdgeCount]; ! 230: ! 231: #ifdef TRACE_X ! 232: fprintf (stderr, "In AddEdge\n"); ! 233: fflush (stderr); ! 234: #endif TRACE_X ! 235: ! 236: /* ! 237: * Fill in new edge data ! 238: */ ! 239: ! 240: if (ThisPoint->y != LastPoint->y) { ! 241: register Min_Y; ! 242: ! 243: if (ThisPoint->y < LastPoint->y) { ! 244: Min_Y = ThisPoint->y; ! 245: NewEdge->Min_X = SHIFT_LEFT_16(ThisPoint->x); ! 246: NewEdge->Max_Y = LastPoint->y; ! 247: NewEdge->Delta_X = SHIFT_LEFT_16(LastPoint->x - ThisPoint->x) / ! 248: (LastPoint->y - ThisPoint->y); ! 249: } else { ! 250: Min_Y = LastPoint->y; ! 251: NewEdge->Min_X = SHIFT_LEFT_16(LastPoint->x); ! 252: NewEdge->Max_Y = ThisPoint->y; ! 253: NewEdge->Delta_X = SHIFT_LEFT_16(ThisPoint->x - LastPoint->x) / ! 254: (ThisPoint->y - LastPoint->y); ! 255: } ! 256: ! 257: /* ! 258: * Shorten edge if not maxima or minima (shortens end of edge) ! 259: */ ! 260: ! 261: if((ThisPoint->y > LastPoint->y) ? ! 262: (NextPoint->y > ThisPoint->y) : (NextPoint->y < ThisPoint->y)) { ! 263: if (LastPoint->y > ThisPoint->y) { ! 264: Min_Y++; ! 265: NewEdge->Min_X += NewEdge->Delta_X; ! 266: } else { ! 267: NewEdge->Max_Y--; ! 268: } ! 269: } ! 270: ! 271: /* ! 272: * Check to see if this edge needs to be shortened ! 273: * at its start. ! 274: */ ! 275: ! 276: if(ShortenStartOfEdge) { ! 277: if (ThisPoint->y > LastPoint->y) { ! 278: Min_Y++; ! 279: NewEdge->Min_X += NewEdge->Delta_X; ! 280: } else { ! 281: NewEdge->Max_Y--; ! 282: } ! 283: ShortenStartOfEdge = 0; ! 284: } ! 285: ! 286: /* ! 287: * Save direction of this edge ! 288: */ ! 289: ! 290: if (NextPoint->y == ThisPoint->y) { ! 291: Direction = LastPoint->y > ThisPoint->y; ! 292: } ! 293: ! 294: /* ! 295: * Insert edge into edge table ! 296: */ ! 297: ! 298: if (NewEdge->Max_Y >= Min_Y) { ! 299: register struct edge *EdgeList = (struct edge *)&EdgeTable[Min_Y]; ! 300: ! 301: while(EdgeList->NextEdge) { ! 302: if(EdgeList->NextEdge->Min_X >= NewEdge->Min_X) ! 303: break; ! 304: EdgeList = EdgeList->NextEdge; ! 305: } ! 306: NewEdge->NextEdge = EdgeList->NextEdge; ! 307: EdgeList->NextEdge = NewEdge; ! 308: EdgeCount++; ! 309: } ! 310: } else { ! 311: /* ! 312: * This is a horizontal edge. Therefore, if there is ! 313: * a change of direction between the preceding edge and ! 314: * and the next edge the next edge must be shortened at its ! 315: * start. ! 316: */ ! 317: ! 318: if(NextPoint->y != ThisPoint->y && ! 319: (Direction != (NextPoint->y > ThisPoint->y))) { ! 320: ShortenStartOfEdge++; ! 321: } ! 322: } ! 323: } ! 324: ! 325: /* ! 326: * Fill polygon(s) to create mask ! 327: */ ! 328: ! 329: static ! 330: FillMask(BitMap, FirstScanLine) ! 331: BITMAP *BitMap; ! 332: int FirstScanLine; ! 333: { ! 334: register long *Bits; ! 335: register Start, Stop; ! 336: register FirstWord, LastWord; ! 337: register struct edge *AET; ! 338: struct edge *ActiveEdgeTable; ! 339: struct edge *TempEdge; ! 340: int NumberOfWords, CurrentScanLine, SortAgain; ! 341: ! 342: #ifdef TRACE_X ! 343: fprintf (stderr, "In FillMask\n"); ! 344: fflush (stderr); ! 345: #endif TRACE_X ! 346: ! 347: NumberOfWords = (BitMap->width + 31) >> 5; ! 348: Bits = (long *)BitMap->data + FirstScanLine * NumberOfWords; ! 349: ActiveEdgeTable = EdgeTable[FirstScanLine]; ! 350: CurrentScanLine = FirstScanLine; ! 351: ! 352: while(EdgeCount) { ! 353: /* ! 354: * Fill all ranges for current scan line ! 355: */ ! 356: ! 357: AET = (struct edge *)&ActiveEdgeTable; ! 358: ! 359: while(AET->NextEdge && AET->NextEdge->NextEdge) { ! 360: Start = ROUND_16(AET->NextEdge->Min_X); ! 361: Stop = ROUND_16(AET->NextEdge->NextEdge->Min_X); ! 362: ! 363: if ((FirstWord = Start >> 5) < (LastWord = Stop >> 5)) { ! 364: Bits[FirstWord] |= RightMasks[Start & 0x1F]; ! 365: while (++FirstWord < LastWord) ! 366: Bits[FirstWord] = 0xFFFFFFFF; ! 367: Bits[LastWord] |= LeftMasks[Stop & 0x1F]; ! 368: } else { ! 369: Bits[FirstWord] |= (RightMasks[Start & 0x1F] & ! 370: LeftMasks[Stop & 0x1F]); ! 371: } ! 372: ! 373: AET = AET->NextEdge->NextEdge; ! 374: } ! 375: Bits += NumberOfWords; ! 376: ! 377: /* ! 378: * Remove finished edges from active edge table ! 379: * and add any new edges for next scan line. ! 380: */ ! 381: ! 382: AET = (struct edge *)&ActiveEdgeTable; ! 383: while(AET->NextEdge) { ! 384: if(AET->NextEdge->Max_Y == CurrentScanLine) { ! 385: AET->NextEdge = AET->NextEdge->NextEdge; ! 386: EdgeCount--; ! 387: } else { ! 388: AET->NextEdge->Min_X += AET->NextEdge->Delta_X; ! 389: AET = AET->NextEdge; ! 390: } ! 391: } ! 392: AET->NextEdge = EdgeTable[++CurrentScanLine]; ! 393: ! 394: /* ! 395: * Sort active edge table ! 396: */ ! 397: ! 398: do { ! 399: SortAgain = 0; ! 400: AET = (struct edge *)&ActiveEdgeTable; ! 401: while(AET->NextEdge && AET->NextEdge->NextEdge) { ! 402: if(AET->NextEdge->Min_X > AET->NextEdge->NextEdge->Min_X) { ! 403: TempEdge = AET->NextEdge; ! 404: AET->NextEdge = AET->NextEdge->NextEdge; ! 405: TempEdge->NextEdge = AET->NextEdge->NextEdge; ! 406: AET->NextEdge->NextEdge = TempEdge; ! 407: SortAgain = 1; ! 408: } ! 409: AET = AET->NextEdge; ! 410: } ! 411: }while(SortAgain); ! 412: } ! 413: free((caddr_t) EdgeTable); ! 414: free((caddr_t) Edges); ! 415: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.