Reactos
at master 868 lines 18 kB view raw
1// this is a little 'sandbox' application I put together that duplicates 2// the 'guts' of the Polygon algorithm. It allows for quick turn-around 3// in testing the algorithm to see what effect your changes have. 4// 5// Royce3 6 7// the stuff immediately following is support so that the sandbox code 8// is nearly identical to the real thing. 9// search for the _tagFILL_EDGE struct to find the beginning of the 10// real stuff. 11 12#include <memory.h> 13#include <malloc.h> 14#include <stdio.h> 15#include <string.h> 16#include <conio.h> 17#include <assert.h> 18 19#define FASTCALL 20#define INT int 21#define CLIPOBJ int 22#define SURFOBJ int 23#define PBRUSHOBJ int 24#define MIX char 25#define BOOL bool 26#define TRUE true 27#define FALSE false 28#define CONST const 29#define MmCopyFromCaller memmove 30#define ALTERNATE 0 31#define WINDING 1 32 33#define ASSERT assert 34 35typedef struct W 36{ 37 int polyFillMode; 38} W; 39 40typedef struct DC 41{ 42 CLIPOBJ CombinedClip; 43 W w; 44} DC, *PDC; 45 46typedef struct tagPOINT 47{ 48 long x, y; 49} POINT, *PPOINT, *LPPOINT; 50 51typedef struct RECTL 52{ 53 long left, top, right, bottom; 54} RECTL, *PRECTL; 55 56#define EngFreeMem free 57 58#define FL_ZERO_MEMORY 1 59 60#define DPRINT1 printf("%i:",__LINE__);printf 61inline void DPRINT(...){} 62 63#define SCREENX 25 64#define SCREENY 15 65char screen[SCREENY][SCREENX]; 66 67#define EDGE_CHAR '*' 68#define FILL_CHAR 'o' 69 70void* EngAllocMem ( int zero, unsigned long size, int tag=0 ) 71{ 72 void* p = malloc ( size ); 73 if ( zero ) 74 memset ( p, 0, size ); 75 return p; 76} 77 78template <class T> 79inline T MIN ( T a, T b ) 80{ 81 return a < b ? a : b; 82} 83 84template <class T> 85inline T MAX ( T a, T b ) 86{ 87 return a > b ? a : b; 88} 89 90template <class T> 91inline T abs ( T t ) 92{ 93 return t < 0 ? -t : t; 94} 95 96void putpixel ( int x, int y, char c ) 97{ 98 ASSERT( x >= 0 && x < SCREENX && y >= 0 && y < SCREENY ); 99 if ( screen[y][x] == c ) 100 return; 101 if ( screen[y][x] == ' ' ) 102 screen[y][x] = c; 103 else 104 screen[y][x] = '#'; 105} 106 107void IntEngLineTo ( 108 SURFOBJ*, 109 CLIPOBJ, 110 PBRUSHOBJ, 111 int x1, int y1, int x2, int y2, 112 RECTL*, 113 MIX mix ) 114{ 115 int dx = x2 - x1; 116 int dy = y2 - y1; 117 int absdx = abs(dx); 118 int absdy = abs(dy); 119 int EMax = MAX(absdx,absdy); 120 int E = EMax/2; 121 int xinc = dx < 0 ? -1 : 1, 122 yinc = dy < 0 ? -1 : 1; 123 if ( !dy ) 124 { 125 while ( x1 != x2 ) 126 { 127 putpixel ( x1, y1, mix ); 128 x1 += xinc; 129 } 130 return; 131 } 132 if ( !dx ) 133 { 134 while ( y1 != y2 ) 135 { 136 putpixel ( x1, y1, mix ); 137 y1 += yinc; 138 } 139 return; 140 } 141 for ( int i = 0; i < EMax; i++ ) 142 { 143 putpixel ( x1, y1, mix ); 144 if ( absdy > absdx ) 145 { 146 y1 += yinc; 147 E += absdx; 148 if ( E >= EMax ) 149 { 150 E -= absdy; 151 x1 += xinc; 152 } 153 } 154 else 155 { 156 x1 += xinc; 157 E += absdy; 158 if ( E >= EMax ) 159 { 160 E -= absdx; 161 y1 += yinc; 162 } 163 } 164 } 165} 166 167#define FILL_EDGE_ALLOC_TAG 0x45465044 168 169/* 170** This struct is used for book keeping during polygon filling routines. 171*/ 172typedef struct _tagFILL_EDGE 173{ 174 /*Basic line information*/ 175 int FromX; 176 int FromY; 177 int ToX; 178 int ToY; 179 int dx; 180 int dy; 181 int absdx, absdy; 182 int x, y; 183 int xmajor; 184 185 /*Active Edge List information*/ 186 int XIntercept[2]; 187 int Error; 188 int ErrorMax; 189 int XDirection, YDirection; 190 191 /* The next edge in the active Edge List*/ 192 struct _tagFILL_EDGE * pNext; 193} FILL_EDGE; 194 195typedef struct _FILL_EDGE_LIST 196{ 197 int Count; 198 FILL_EDGE** Edges; 199} FILL_EDGE_LIST; 200 201#if 0 202static 203void 204DEBUG_PRINT_ACTIVE_EDGELIST ( FILL_EDGE* list ) 205{ 206 FILL_EDGE* pThis = list; 207 if (0 == list) 208 { 209 DPRINT1("List is NULL\n"); 210 return; 211 } 212 213 while(0 != pThis) 214 { 215 //DPRINT1("EDGE: (%d, %d) to (%d, %d)\n", pThis->FromX, pThis->FromY, pThis->ToX, pThis->ToY); 216 DPRINT1("EDGE: [%d,%d]\n", pThis->XIntercept[0], pThis->XIntercept[1] ); 217 pThis = pThis->pNext; 218 } 219} 220#else 221#define DEBUG_PRINT_ACTIVE_EDGELIST(x) 222#endif 223 224/* 225** Hide memory clean up. 226*/ 227static 228void 229FASTCALL 230POLYGONFILL_DestroyEdgeList(FILL_EDGE_LIST* list) 231{ 232 int i; 233 if ( list ) 234 { 235 if ( list->Edges ) 236 { 237 for ( i = 0; i < list->Count; i++ ) 238 { 239 if ( list->Edges[i] ) 240 EngFreeMem ( list->Edges[i] ); 241 } 242 EngFreeMem ( list->Edges ); 243 } 244 EngFreeMem ( list ); 245 } 246} 247 248/* 249** This makes and initiaizes an Edge struct for a line between two points. 250*/ 251static 252FILL_EDGE* 253FASTCALL 254POLYGONFILL_MakeEdge(POINT From, POINT To) 255{ 256 FILL_EDGE* rc = (FILL_EDGE*)EngAllocMem(FL_ZERO_MEMORY, sizeof(FILL_EDGE), FILL_EDGE_ALLOC_TAG); 257 258 if (0 == rc) 259 return NULL; 260 261 //DPRINT1("Making Edge: (%d, %d) to (%d, %d)\n", From.x, From.y, To.x, To.y); 262 //Now Fill the struct. 263 if ( To.y < From.y ) 264 { 265 rc->FromX = To.x; 266 rc->FromY = To.y; 267 rc->ToX = From.x; 268 rc->ToY = From.y; 269 rc->YDirection = -1; 270 271 // lines that go up get walked backwards, so need to be offset 272 // by -1 in order to make the walk identically on a pixel-level 273 rc->Error = -1; 274 } 275 else 276 { 277 rc->FromX = From.x; 278 rc->FromY = From.y; 279 rc->ToX = To.x; 280 rc->ToY = To.y; 281 rc->YDirection = 1; 282 283 rc->Error = 0; 284 } 285 286 rc->x = rc->FromX; 287 rc->y = rc->FromY; 288 rc->dx = rc->ToX - rc->FromX; 289 rc->dy = rc->ToY - rc->FromY; 290 rc->absdx = abs(rc->dx); 291 rc->absdy = abs(rc->dy); 292 293 rc->xmajor = rc->absdx > rc->absdy; 294 295 rc->ErrorMax = MAX(rc->absdx,rc->absdy); 296 297 rc->Error += rc->ErrorMax / 2; 298 299 rc->XDirection = (rc->dx < 0)?(-1):(1); 300 301 rc->pNext = 0; 302 303 DPRINT("MakeEdge (%i,%i)->(%i,%i) d=(%i,%i) dir=(%i,%i) err=%i max=%i\n", 304 From.x, From.y, To.x, To.y, rc->dx, rc->dy, rc->XDirection, rc->YDirection, rc->Error, rc->ErrorMax ); 305 306 return rc; 307} 308/* 309** My Edge comparison routine. 310** This is for scan converting polygon fill. 311** First sort by MinY, then Minx, then slope. 312** 313** This comparison will help us determine which 314** lines will become active first when scanning from 315** top (min y) to bottom (max y). 316** 317** Return Value Meaning 318** Negative integer element1 < element2 319** Zero element1 = element2 320** Positive integer element1 > element2 321*/ 322static 323INT 324FASTCALL 325FILL_EDGE_Compare(FILL_EDGE* Edge1, FILL_EDGE* Edge2) 326{ 327 int e1 = Edge1->XIntercept[0] + Edge1->XIntercept[1]; 328 int e2 = Edge2->XIntercept[0] + Edge2->XIntercept[1]; 329 330 return e1 - e2; 331} 332 333 334/* 335** Insert an edge into a list keeping the list in order. 336*/ 337static 338void 339FASTCALL 340POLYGONFILL_ActiveListInsert(FILL_EDGE** activehead, FILL_EDGE* NewEdge ) 341{ 342 FILL_EDGE *pPrev, *pThis; 343 //DPRINT1("In POLYGONFILL_ActiveListInsert()\n"); 344 ASSERT ( activehead && NewEdge ); 345 if ( !*activehead ) 346 { 347 NewEdge->pNext = NULL; 348 *activehead = NewEdge; 349 return; 350 } 351 /* 352 ** First lets check to see if we have a new smallest value. 353 */ 354 if (FILL_EDGE_Compare(NewEdge, *activehead) <= 0) 355 { 356 NewEdge->pNext = *activehead; 357 *activehead = NewEdge; 358 return; 359 } 360 /* 361 ** Ok, now scan to the next spot to put this item. 362 */ 363 pThis = *activehead; 364 pPrev = NULL; 365 while ( pThis && FILL_EDGE_Compare(pThis, NewEdge) < 0 ) 366 { 367 pPrev = pThis; 368 pThis = pThis->pNext; 369 } 370 371 ASSERT(pPrev); 372 NewEdge->pNext = pPrev->pNext; 373 pPrev->pNext = NewEdge; 374 //DEBUG_PRINT_ACTIVE_EDGELIST(*activehead); 375} 376 377/* 378** Create a list of edges for a list of points. 379*/ 380static 381FILL_EDGE_LIST* 382FASTCALL 383POLYGONFILL_MakeEdgeList(PPOINT Points, int Count) 384{ 385 int CurPt = 0; 386 FILL_EDGE_LIST* list = 0; 387 FILL_EDGE* e = 0; 388 389 if ( 0 == Points || 2 > Count ) 390 return 0; 391 392 list = (FILL_EDGE_LIST*)EngAllocMem(FL_ZERO_MEMORY, sizeof(FILL_EDGE_LIST), FILL_EDGE_ALLOC_TAG); 393 if ( 0 == list ) 394 goto fail; 395 list->Count = 0; 396 list->Edges = (FILL_EDGE**)EngAllocMem(FL_ZERO_MEMORY, Count*sizeof(FILL_EDGE*), FILL_EDGE_ALLOC_TAG); 397 if ( !list->Edges ) 398 goto fail; 399 memset ( list->Edges, 0, Count * sizeof(FILL_EDGE*) ); 400 401 for ( CurPt = 1; CurPt < Count; ++CurPt ) 402 { 403 e = POLYGONFILL_MakeEdge ( Points[CurPt-1], Points[CurPt] ); 404 if ( !e ) 405 goto fail; 406 // if a straight horizontal line - who cares? 407 if ( !e->absdy ) 408 EngFreeMem ( e ); 409 else 410 list->Edges[list->Count++] = e; 411 } 412 e = POLYGONFILL_MakeEdge ( Points[CurPt-1], Points[0] ); 413 if ( !e ) 414 goto fail; 415 if ( !e->absdy ) 416 EngFreeMem ( e ); 417 else 418 list->Edges[list->Count++] = e; 419 return list; 420 421fail: 422 DPRINT1("Out Of MEMORY!!\n"); 423 POLYGONFILL_DestroyEdgeList ( list ); 424 return 0; 425} 426 427 428/* 429** This slow routine uses the data stored in the edge list to 430** calculate the x intercepts for each line in the edge list 431** for scanline Scanline. 432**TODO: Get rid of this floating point arithmetic 433*/ 434static 435void 436FASTCALL 437POLYGONFILL_UpdateScanline(FILL_EDGE* pEdge, int Scanline) 438{ 439 if ( 0 == pEdge->dy ) 440 return; 441 442 ASSERT ( pEdge->FromY <= Scanline && pEdge->ToY > Scanline ); 443 444 if ( pEdge->xmajor ) 445 { 446 int steps; 447 448 ASSERT ( pEdge->y == Scanline ); 449 450 // now shoot to end of scanline collision 451 steps = (pEdge->ErrorMax-pEdge->Error-1)/pEdge->absdy; 452 if ( steps ) 453 { 454 // record first collision with scanline 455 int x1 = pEdge->x; 456 pEdge->x += steps * pEdge->XDirection; 457 pEdge->Error += steps * pEdge->absdy; 458 ASSERT ( pEdge->Error < pEdge->ErrorMax ); 459 pEdge->XIntercept[0] = MIN(x1,pEdge->x); 460 pEdge->XIntercept[1] = MAX(x1,pEdge->x); 461 } 462 else 463 { 464 pEdge->XIntercept[0] = pEdge->x; 465 pEdge->XIntercept[1] = pEdge->x; 466 } 467 468 // we should require exactly 1 step to step onto next scanline... 469 ASSERT ( (pEdge->ErrorMax-pEdge->Error-1) / pEdge->absdy == 0 ); 470 pEdge->x += pEdge->XDirection; 471 pEdge->Error += pEdge->absdy; 472 ASSERT ( pEdge->Error >= pEdge->ErrorMax ); 473 474 // now step onto next scanline... 475 pEdge->Error -= pEdge->absdx; 476 pEdge->y++; 477 } 478 else // then this is a y-major line 479 { 480 pEdge->XIntercept[0] = pEdge->x; 481 pEdge->XIntercept[1] = pEdge->x; 482 483 pEdge->Error += pEdge->absdx; 484 pEdge->y++; 485 486 if ( pEdge->Error >= pEdge->ErrorMax ) 487 { 488 pEdge->Error -= pEdge->ErrorMax; 489 pEdge->x += pEdge->XDirection; 490 ASSERT ( pEdge->Error < pEdge->ErrorMax ); 491 } 492 } 493 494 DPRINT("Line (%d, %d) to (%d, %d) intersects scanline %d at (%d,%d)\n", 495 pEdge->FromX, pEdge->FromY, pEdge->ToX, pEdge->ToY, Scanline, pEdge->XIntercept[0], pEdge->XIntercept[1] ); 496} 497 498/* 499** This method updates the Active edge collection for the scanline Scanline. 500*/ 501static 502void 503POLYGONFILL_BuildActiveList ( int Scanline, FILL_EDGE_LIST* list, FILL_EDGE** ActiveHead ) 504{ 505 int i; 506 507 ASSERT ( list && ActiveHead ); 508 *ActiveHead = 0; 509 for ( i = 0; i < list->Count; i++ ) 510 { 511 FILL_EDGE* pEdge = list->Edges[i]; 512 ASSERT(pEdge); 513 if ( pEdge->FromY <= Scanline && pEdge->ToY > Scanline ) 514 { 515 POLYGONFILL_UpdateScanline ( pEdge, Scanline ); 516 POLYGONFILL_ActiveListInsert ( ActiveHead, pEdge ); 517 } 518 } 519} 520 521/* 522** This method fills the portion of the polygon that intersects with the scanline 523** Scanline. 524*/ 525static 526void 527POLYGONFILL_FillScanLineAlternate( 528 PDC dc, 529 int ScanLine, 530 FILL_EDGE* ActiveHead, 531 SURFOBJ *SurfObj, 532 PBRUSHOBJ BrushObj, 533 MIX RopMode ) 534{ 535 FILL_EDGE *pLeft, *pRight; 536 537 if ( !ActiveHead ) 538 return; 539 540 pLeft = ActiveHead; 541 pRight = pLeft->pNext; 542 ASSERT(pRight); 543 544 while ( NULL != pRight ) 545 { 546 int x1 = pLeft->XIntercept[0]; 547 int x2 = pRight->XIntercept[1]; 548 if ( x2 > x1 ) 549 { 550 RECTL BoundRect; 551 BoundRect.top = ScanLine; 552 BoundRect.bottom = ScanLine + 1; 553 BoundRect.left = x1; 554 BoundRect.right = x2; 555 556 DPRINT("Fill Line (%d, %d) to (%d, %d)\n",x1, ScanLine, x2, ScanLine); 557 IntEngLineTo( SurfObj, 558 dc->CombinedClip, 559 BrushObj, 560 x1, 561 ScanLine, 562 x2, 563 ScanLine, 564 &BoundRect, // Bounding rectangle 565 RopMode); // MIX 566 } 567 pLeft = pRight->pNext; 568 pRight = pLeft ? pLeft->pNext : NULL; 569 } 570} 571 572static 573void 574POLYGONFILL_FillScanLineWinding( 575 PDC dc, 576 int ScanLine, 577 FILL_EDGE* ActiveHead, 578 SURFOBJ *SurfObj, 579 PBRUSHOBJ BrushObj, 580 MIX RopMode ) 581{ 582 FILL_EDGE *pLeft, *pRight; 583 int x1, x2, winding = 0; 584 RECTL BoundRect; 585 586 if ( !ActiveHead ) 587 return; 588 589 BoundRect.top = ScanLine; 590 BoundRect.bottom = ScanLine + 1; 591 592 pLeft = ActiveHead; 593 winding = pLeft->YDirection; 594 pRight = pLeft->pNext; 595 ASSERT(pRight); 596 597 // setup first line... 598 x1 = pLeft->XIntercept[0]; 599 x2 = pRight->XIntercept[1]; 600 601 pLeft = pRight; 602 pRight = pLeft->pNext; 603 winding += pLeft->YDirection; 604 605 while ( NULL != pRight ) 606 { 607 int newx1 = pLeft->XIntercept[0]; 608 int newx2 = pRight->XIntercept[1]; 609 if ( winding ) 610 { 611 // check and see if this new line touches the previous... 612 if ( (newx1 >= x1 && newx1 <= x2) 613 || (newx2 >= x1 && newx2 <= x2) 614 || (x1 >= newx1 && x1 <= newx2) 615 || (x2 >= newx2 && x2 <= newx2) 616 ) 617 { 618 // yup, just tack it on to our existing line 619 x1 = MIN(x1,newx1); 620 x2 = MAX(x2,newx2); 621 } 622 else 623 { 624 // nope - render the old line.. 625 BoundRect.left = x1; 626 BoundRect.right = x2; 627 628 DPRINT("Fill Line (%d, %d) to (%d, %d)\n",x1, ScanLine, x2, ScanLine); 629 IntEngLineTo( SurfObj, 630 dc->CombinedClip, 631 BrushObj, 632 x1, 633 ScanLine, 634 x2, 635 ScanLine, 636 &BoundRect, // Bounding rectangle 637 RopMode); // MIX 638 639 x1 = newx1; 640 x2 = newx2; 641 } 642 } 643 pLeft = pRight; 644 pRight = pLeft->pNext; 645 winding += pLeft->YDirection; 646 } 647 // there will always be a line left-over, render it now... 648 BoundRect.left = x1; 649 BoundRect.right = x2; 650 651 DPRINT("Fill Line (%d, %d) to (%d, %d)\n",x1, ScanLine, x2, ScanLine); 652 IntEngLineTo( SurfObj, 653 dc->CombinedClip, 654 BrushObj, 655 x1, 656 ScanLine, 657 x2, 658 ScanLine, 659 &BoundRect, // Bounding rectangle 660 RopMode); // MIX 661} 662 663//When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and 664//even-numbered polygon sides on each scan line. That is, GDI fills the area between the 665//first and second side, between the third and fourth side, and so on. 666 667//WINDING Selects winding mode (fills any region with a nonzero winding value). 668//When the fill mode is WINDING, GDI fills any region that has a nonzero winding value. 669//This value is defined as the number of times a pen used to draw the polygon would go around the region. 670//The direction of each edge of the polygon is important. 671 672BOOL 673FillPolygon( 674 PDC dc, 675 SURFOBJ *SurfObj, 676 PBRUSHOBJ BrushObj, 677 MIX RopMode, 678 CONST PPOINT Points, 679 int Count, 680 RECTL BoundRect ) 681{ 682 FILL_EDGE_LIST *list = 0; 683 FILL_EDGE *ActiveHead = 0; 684 int ScanLine; 685 686 void 687 (*FillScanLine)( 688 PDC dc, 689 int ScanLine, 690 FILL_EDGE* ActiveHead, 691 SURFOBJ *SurfObj, 692 PBRUSHOBJ BrushObj, 693 MIX RopMode ); 694 695 DPRINT("FillPolygon\n"); 696 697 /* Create Edge List. */ 698 list = POLYGONFILL_MakeEdgeList(Points, Count); 699 /* DEBUG_PRINT_EDGELIST(list); */ 700 if (NULL == list) 701 return FALSE; 702 703 if ( WINDING == dc->w.polyFillMode ) 704 FillScanLine = POLYGONFILL_FillScanLineWinding; 705 else /* default */ 706 FillScanLine = POLYGONFILL_FillScanLineAlternate; 707 708 /* For each Scanline from BoundRect.bottom to BoundRect.top, 709 * determine line segments to draw 710 */ 711 for ( ScanLine = BoundRect.top; ScanLine < BoundRect.bottom; ++ScanLine ) 712 { 713 POLYGONFILL_BuildActiveList(ScanLine, list, &ActiveHead); 714 //DEBUG_PRINT_ACTIVE_EDGELIST(ActiveHead); 715 FillScanLine ( dc, ScanLine, ActiveHead, SurfObj, BrushObj, RopMode ); 716 } 717 718 /* Free Edge List. If any are left. */ 719 POLYGONFILL_DestroyEdgeList(list); 720 721 return TRUE; 722} 723 724 725 726 727 728// this is highly hacked from W32kPolygon... 729BOOL 730Polygon ( CONST PPOINT UnsafePoints, int Count, int polyFillMode ) 731{ 732 BOOL ret; 733 RECTL DestRect; 734 int CurrentPoint; 735 PPOINT Points; 736 SURFOBJ* SurfObj = 0; 737 DC dc; 738 PBRUSHOBJ OutBrushObj = 0; 739 740 dc.CombinedClip = 0; 741 dc.w.polyFillMode = polyFillMode; 742 743 DPRINT1("In W32kPolygon()\n"); 744 745 if ( NULL == UnsafePoints || Count < 2) 746 { 747 DPRINT1("ERROR_INVALID_PARAMETER\n"); 748 return FALSE; 749 } 750 751 /* Copy points from userspace to kernelspace */ 752 Points = (PPOINT)EngAllocMem(0, Count * sizeof(POINT)); 753 if (NULL == Points) 754 { 755 DPRINT1("ERROR_NOT_ENOUGH_MEMORY\n"); 756 return FALSE; 757 } 758 MmCopyFromCaller(Points, UnsafePoints, Count * sizeof(POINT)); 759 if ( memcmp ( Points, UnsafePoints, Count * sizeof(POINT) ) ) 760 { 761 free(Points); 762 return FALSE; 763 } 764 765 DestRect.left = Points[0].x; 766 DestRect.right = Points[0].x; 767 DestRect.top = Points[0].y; 768 DestRect.bottom = Points[0].y; 769 770 for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint) 771 { 772 DestRect.left = MIN(DestRect.left, Points[CurrentPoint].x); 773 DestRect.right = MAX(DestRect.right, Points[CurrentPoint].x); 774 DestRect.top = MIN(DestRect.top, Points[CurrentPoint].y); 775 DestRect.bottom = MAX(DestRect.bottom, Points[CurrentPoint].y); 776 } 777 778 // Draw the Polygon Edges with the current pen 779 for (CurrentPoint = 0; CurrentPoint < Count; ++CurrentPoint) 780 { 781 POINT To, From; //, Next; 782 783 /* Let CurrentPoint be i 784 * if i+1 > Count, Draw a line from Points[i] to Points[0] 785 * Draw a line from Points[i] to Points[i+1] 786 */ 787 From = Points[CurrentPoint]; 788 if ( CurrentPoint + 1 >= Count) 789 { 790 To = Points[0]; 791 } 792 else 793 { 794 To = Points[CurrentPoint + 1]; 795 } 796 797 DPRINT1("Polygon Making line from (%ld,%ld) to (%ld,%ld)\n", From.x, From.y, To.x, To.y ); 798 IntEngLineTo(SurfObj, 799 dc.CombinedClip, 800 OutBrushObj, 801 From.x, 802 From.y, 803 To.x, 804 To.y, 805 &DestRect, 806 EDGE_CHAR); /* MIX */ 807 } 808 /* determine the fill mode to fill the polygon. */ 809 ret = FillPolygon(&dc, SurfObj, OutBrushObj, FILL_CHAR, Points, Count, DestRect ); 810 free(Points); 811 812 return ret; 813} 814 815 816int main() 817{ 818 memset ( screen, ' ', sizeof(screen) ); 819 POINT pts[] = 820 { 821#if 0 822 { 0, 0 }, 823 { 12, 4 }, 824 { 4, 8 }, 825#elif 0 826 { 3, 0 }, 827 { 0, 3 }, 828 { 3, 6 }, 829#elif 0 830 { 1, 1 }, 831 { 3, 1 }, 832 { 3, 3 }, 833 { 1, 3 } 834#elif 0 835 { 0, 0 }, 836 { 4, 0 }, 837 { 4, 4 }, 838 { 8, 4 }, 839 { 8, 8 }, 840 { 4, 8 }, 841 { 4, 4 }, 842 { 0, 4 }, 843#else 844 { 4, 12 }, 845 { 12, 0 }, 846 { 18, 12 }, 847 { 4, 4 }, 848 { 20, 4 } 849#endif 850 }; 851 const int pts_count = sizeof(pts)/sizeof(pts[0]); 852 853 // use ALTERNATE or WINDING for 3rd param 854 Polygon ( pts, pts_count, ALTERNATE ); 855 856 // print out our "screen" 857 for ( int y = 0; y < SCREENY; y++ ) 858 { 859 for ( int x = 0; x < SCREENX; x++ ) 860 { 861 printf("%c", screen[y][x] ); 862 } 863 printf("\n"); 864 } 865 DPRINT1("Done!\n"); 866 (void)_getch(); 867} 868/* EOF */