int CreateScanLinesFromSimplePolygon (int iVertexCount, SPoint *pVertexList, CG16bitBinaryRegion::SRun **retpLines) // CreateScanLinesFromSimplePolygon // // Creates a new array of scanlines from the given polygon. Returns the number of scanlines // in the array. The caller is responsible for freeing the newly allocated array. // // The polygon must be monotone-vertical, meaning polygons in which a scanline intersects the edges // exactly twice. // // Michael Abrash. Graphics Programming Black Book. Chapter 41. { int i, MinIndex, MaxIndex, MinPoint_Y, MaxPoint_Y; int CurrentIndex, PreviousIndex; CG16bitBinaryRegion::SRun *EdgePointPtr; SPoint *VertexPtr; // Point to the vertex list VertexPtr = pVertexList; // Scan the list to find the top and bottom of the polygon if (iVertexCount == 0) return 0; // reject null polygons MaxPoint_Y = MinPoint_Y = VertexPtr[MinIndex = MaxIndex = 0].y; for (i = 1; i < iVertexCount; i++) { if (VertexPtr[i].y < MinPoint_Y) MinPoint_Y = VertexPtr[MinIndex = i].y; // new top else if (VertexPtr[i].y > MaxPoint_Y) MaxPoint_Y = VertexPtr[MaxIndex = i].y; // new bottom } // Set the # of scan lines in the polygon, skipping the bottom edge int iLineCount; if ((iLineCount = MaxPoint_Y - MinPoint_Y) <= 0) return 0; // there’s nothing to draw, so we’re done int yStart = MinPoint_Y; // Allocate and initialize result CG16bitBinaryRegion::SRun *pLine = new CG16bitBinaryRegion::SRun [iLineCount]; for (i = 0; i < iLineCount; i++) pLine[i].y = yStart + i; // Scan the first edge and store the boundary points in the list // Initial pointer for storing scan converted first-edge coords EdgePointPtr = pLine; // Start from the top of the first edge PreviousIndex = CurrentIndex = MinIndex; // Scan convert each line in the first edge from top to bottom do { INDEX_BACKWARD(CurrentIndex); ScanEdge(VertexPtr[PreviousIndex].x, VertexPtr[PreviousIndex].y, VertexPtr[CurrentIndex].x, VertexPtr[CurrentIndex].y, true, 0, &EdgePointPtr); PreviousIndex = CurrentIndex; } while (CurrentIndex != MaxIndex); // Scan the second edge and store the boundary points in the list EdgePointPtr = pLine; PreviousIndex = CurrentIndex = MinIndex; // Scan convert the second edge, top to bottom do { INDEX_FORWARD(CurrentIndex); ScanEdge(VertexPtr[PreviousIndex].x, VertexPtr[PreviousIndex].y, VertexPtr[CurrentIndex].x, VertexPtr[CurrentIndex].y, false, 0, &EdgePointPtr); PreviousIndex = CurrentIndex; } while (CurrentIndex != MaxIndex); // Make sure that xStart and xEnd are oriented correctly for (i = 0; i < iLineCount; i++) { if (pLine[i].xStart > pLine[i].xEnd) Swap(pLine[i].xStart, pLine[i].xEnd); } // Done *retpLines = pLine; return iLineCount; }
int FillConvexPolygon(struct PointListHeader * VertexList, int Color, int XOffset, int YOffset) { int i, MinIndexL, MaxIndex, MinIndexR, SkipFirst, Temp; int MinPoint_Y, MaxPoint_Y, TopIsFlat, LeftEdgeDir; int NextIndex, CurrentIndex, PreviousIndex; int DeltaXN, DeltaYN, DeltaXP, DeltaYP; struct HLineList WorkingHLineList; struct HLine *EdgePointPtr; struct Point *VertexPtr; /* Point to the vertex list */ VertexPtr = VertexList->PointPtr; /* Scan the list to find the top and bottom of the polygon */ if (VertexList->Length == 0) return(1); /* reject null polygons */ MaxPoint_Y = MinPoint_Y = VertexPtr[MinIndexL = MaxIndex = 0].Y; for (i = 1; i < VertexList->Length; i++) { if (VertexPtr[i].Y < MinPoint_Y) MinPoint_Y = VertexPtr[MinIndexL = i].Y; /* new top */ else if (VertexPtr[i].Y > MaxPoint_Y) MaxPoint_Y = VertexPtr[MaxIndex = i].Y; /* new bottom */ } if (MinPoint_Y == MaxPoint_Y) return(1); /* polygon is 0-height; avoid infinite loop below */ /* Scan in ascending order to find the last top-edge point */ MinIndexR = MinIndexL; while (VertexPtr[MinIndexR].Y == MinPoint_Y) INDEX_FORWARD(MinIndexR); INDEX_BACKWARD(MinIndexR); /* back up to last top-edge point */ /* Now scan in descending order to find the first top-edge point */ while (VertexPtr[MinIndexL].Y == MinPoint_Y) INDEX_BACKWARD(MinIndexL); INDEX_FORWARD(MinIndexL); /* back up to first top-edge point */ /* Figure out which direction through the vertex list from the top vertex is the left edge and which is the right */ LeftEdgeDir = -1; /* assume left edge runs down thru vertex list */ if ((TopIsFlat = (VertexPtr[MinIndexL].X != VertexPtr[MinIndexR].X) ? 1 : 0) == 1) { /* If the top is flat, just see which of the ends is leftmost */ if (VertexPtr[MinIndexL].X > VertexPtr[MinIndexR].X) { LeftEdgeDir = 1; /* left edge runs up through vertex list */ Temp = MinIndexL; /* swap the indices so MinIndexL */ MinIndexL = MinIndexR; /* points to the start of the left */ MinIndexR = Temp; /* edge, similarly for MinIndexR */ } } else { /* Point to the downward end of the first line of each of the two edges down from the top */ NextIndex = MinIndexR; INDEX_FORWARD(NextIndex); PreviousIndex = MinIndexL; INDEX_BACKWARD(PreviousIndex); /* Calculate X and Y lengths from the top vertex to the end of the first line down each edge; use those to compare slopes and see which line is leftmost */ DeltaXN = VertexPtr[NextIndex].X - VertexPtr[MinIndexL].X; DeltaYN = VertexPtr[NextIndex].Y - VertexPtr[MinIndexL].Y; DeltaXP = VertexPtr[PreviousIndex].X - VertexPtr[MinIndexL].X; DeltaYP = VertexPtr[PreviousIndex].Y - VertexPtr[MinIndexL].Y; if (((long)DeltaXN * DeltaYP - (long)DeltaYN * DeltaXP) < 0L) { LeftEdgeDir = 1; /* left edge runs up through vertex list */ Temp = MinIndexL; /* swap the indices so MinIndexL */ MinIndexL = MinIndexR; /* points to the start of the left */ MinIndexR = Temp; /* edge, similarly for MinIndexR */ } } /* Set the # of scan lines in the polygon, skipping the bottom edge and also skipping the top vertex if the top isn't flat because in that case the top vertex has a right edge component, and set the top scan line to draw, which is likewise the second line of the polygon unless the top is flat */ if ((WorkingHLineList.Length = MaxPoint_Y - MinPoint_Y - 1 + TopIsFlat) <= 0) return(1); /* there's nothing to draw, so we're done */ WorkingHLineList.YStart = YOffset + MinPoint_Y + 1 - TopIsFlat; /* Get memory in which to store the line list we generate */ if ((WorkingHLineList.HLinePtr = (struct HLine *) (malloc(sizeof(struct HLine) * WorkingHLineList.Length))) == NULL) return(0); /* couldn't get memory for the line list */ /* Scan the left edge and store the boundary points in the list */ /* Initial pointer for storing scan converted left-edge coords */ EdgePointPtr = WorkingHLineList.HLinePtr; /* Start from the top of the left edge */ PreviousIndex = CurrentIndex = MinIndexL; /* Skip the first point of the first line unless the top is flat; if the top isn't flat, the top vertex is exactly on a right edge and isn't drawn */ SkipFirst = TopIsFlat ? 0 : 1; /* Scan convert each line in the left edge from top to bottom */ do { INDEX_MOVE(CurrentIndex,LeftEdgeDir); ScanEdge(VertexPtr[PreviousIndex].X + XOffset, VertexPtr[PreviousIndex].Y, VertexPtr[CurrentIndex].X + XOffset, VertexPtr[CurrentIndex].Y, 1, SkipFirst, &EdgePointPtr); PreviousIndex = CurrentIndex; SkipFirst = 0; /* scan convert the first point from now on */ } while (CurrentIndex != MaxIndex); /* Scan the right edge and store the boundary points in the list */ EdgePointPtr = WorkingHLineList.HLinePtr; PreviousIndex = CurrentIndex = MinIndexR; SkipFirst = TopIsFlat ? 0 : 1; /* Scan convert the right edge, top to bottom. X coordinates are adjusted 1 to the left, effectively causing scan conversion of the nearest points to the left of but not exactly on the edge */ do { INDEX_MOVE(CurrentIndex,-LeftEdgeDir); ScanEdge(VertexPtr[PreviousIndex].X + XOffset - 1, VertexPtr[PreviousIndex].Y, VertexPtr[CurrentIndex].X + XOffset - 1, VertexPtr[CurrentIndex].Y, 0, SkipFirst, &EdgePointPtr); PreviousIndex = CurrentIndex; SkipFirst = 0; /* scan convert the first point from now on */ } while (CurrentIndex != MaxIndex); /* Draw the line list representing the scan converted polygon */ DrawHorizontalLineList(&WorkingHLineList, Color); /* Release the line list's memory and we're successfully done */ free(WorkingHLineList.HLinePtr); return(1); }