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