ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

polyfill.c
Go to the documentation of this file.
00001 /*
00002  * COPYRIGHT:         See COPYING in the top level directory
00003  * PROJECT:           ReactOS Win32k subsystem
00004  * PURPOSE:           Various Polygon Filling routines for Polygon()
00005  * FILE:              subsystems/win32/win32k/objects/polyfill.c
00006  * PROGRAMER:         Mark Tempel
00007  */
00008 
00009 #include <win32k.h>
00010 
00011 #define NDEBUG
00012 #include <debug.h>
00013 
00014 #define FILL_EDGE_ALLOC_TAG 0x45465044
00015 
00016 /*
00017 ** This struct is used for book keeping during polygon filling routines.
00018 */
00019 typedef struct _tagFILL_EDGE
00020 {
00021   /* Basic line information */
00022   int FromX;
00023   int FromY;
00024   int ToX;
00025   int ToY;
00026   int dx;
00027   int dy;
00028   int absdx, absdy;
00029   int x, y;
00030   int xmajor;
00031 
00032   /* Active Edge List information */
00033   int XIntercept[2];
00034   int Error;
00035   int ErrorMax;
00036   int XDirection, YDirection;
00037 
00038   /* The next edge in the active Edge List */
00039   struct _tagFILL_EDGE * pNext;
00040 } FILL_EDGE;
00041 
00042 typedef struct _FILL_EDGE_LIST
00043 {
00044   int Count;
00045   FILL_EDGE** Edges;
00046 } FILL_EDGE_LIST;
00047 
00048 #if 0
00049 static
00050 void
00051 DEBUG_PRINT_ACTIVE_EDGELIST ( FILL_EDGE* list )
00052 {
00053   FILL_EDGE* pThis = list;
00054   if (0 == list)
00055   {
00056     DPRINT1("List is NULL\n");
00057     return;
00058   }
00059 
00060   while(0 != pThis)
00061   {
00062     //DPRINT1("EDGE: (%d, %d) to (%d, %d)\n", pThis->FromX, pThis->FromY, pThis->ToX, pThis->ToY);
00063     DPRINT1("EDGE: [%d,%d]\n", pThis->XIntercept[0], pThis->XIntercept[1] );
00064     pThis = pThis->pNext;
00065   }
00066 }
00067 #else
00068 #define DEBUG_PRINT_ACTIVE_EDGELIST(x)
00069 #endif
00070 
00071 /*
00072 **  Hide memory clean up.
00073 */
00074 static
00075 void
00076 FASTCALL
00077 POLYGONFILL_DestroyEdgeList(FILL_EDGE_LIST* list)
00078 {
00079   int i;
00080   if ( list )
00081   {
00082     if ( list->Edges )
00083     {
00084       for ( i = 0; i < list->Count; i++ )
00085       {
00086     if ( list->Edges[i] )
00087       EngFreeMem ( list->Edges[i] );
00088       }
00089       EngFreeMem ( list->Edges );
00090     }
00091     EngFreeMem ( list );
00092   }
00093 }
00094 
00095 /*
00096 ** This makes and initiaizes an Edge struct for a line between two points.
00097 */
00098 static
00099 FILL_EDGE*
00100 FASTCALL
00101 POLYGONFILL_MakeEdge(POINT From, POINT To)
00102 {
00103   FILL_EDGE* rc = (FILL_EDGE*)EngAllocMem(FL_ZERO_MEMORY, sizeof(FILL_EDGE), FILL_EDGE_ALLOC_TAG);
00104 
00105   if (0 == rc)
00106     return NULL;
00107 
00108   //DPRINT1("Making Edge: (%d, %d) to (%d, %d)\n", From.x, From.y, To.x, To.y);
00109   // Now fill the struct.
00110   if ( To.y < From.y )
00111   {
00112     rc->FromX = To.x;
00113     rc->FromY = To.y;
00114     rc->ToX = From.x;
00115     rc->ToY = From.y;
00116     rc->YDirection = -1;
00117 
00118     // Lines that go up get walked backwards, so need to be offset
00119     // by -1 in order to make the walk identically on a pixel-level
00120     rc->Error = -1;
00121   }
00122   else
00123   {
00124     rc->FromX = From.x;
00125     rc->FromY = From.y;
00126     rc->ToX = To.x;
00127     rc->ToY = To.y;
00128     rc->YDirection = 1;
00129 
00130     rc->Error = 0;
00131   }
00132 
00133   rc->x = rc->FromX;
00134   rc->y = rc->FromY;
00135   rc->dx   = rc->ToX - rc->FromX;
00136   rc->dy   = rc->ToY - rc->FromY;
00137   rc->absdx = abs(rc->dx);
00138   rc->absdy = abs(rc->dy);
00139 
00140   rc->xmajor = rc->absdx > rc->absdy;
00141 
00142   rc->ErrorMax = max(rc->absdx,rc->absdy);
00143 
00144   rc->Error += rc->ErrorMax / 2;
00145 
00146   rc->XDirection = (rc->dx < 0)?(-1):(1);
00147 
00148   rc->pNext = 0;
00149 
00150   //DPRINT("MakeEdge (%i,%i)->(%i,%i) d=(%i,%i) dir=(%i,%i) err=%i max=%i\n",
00151   //  From.x, From.y, To.x, To.y, rc->dx, rc->dy, rc->XDirection, rc->YDirection, rc->Error, rc->ErrorMax );
00152 
00153   return rc;
00154 }
00155 /*
00156 ** My Edge comparison routine.
00157 ** This is for scan converting polygon fill.
00158 ** First sort by MinY, then Minx, then slope.
00159 **
00160 ** This comparison will help us determine which
00161 ** lines will become active first when scanning from
00162 ** top (min y) to bottom (max y).
00163 **
00164 ** Return Value Meaning
00165 ** Negative integer element1 < element2
00166 ** Zero element1 = element2
00167 ** Positive integer element1 > element2
00168 */
00169 static
00170 INT
00171 FASTCALL
00172 FILL_EDGE_Compare(FILL_EDGE* Edge1, FILL_EDGE* Edge2)
00173 {
00174   int e1 = Edge1->XIntercept[0] + Edge1->XIntercept[1];
00175   int e2 = Edge2->XIntercept[0] + Edge2->XIntercept[1];
00176 
00177   return e1 - e2;
00178 }
00179 
00180 
00181 /*
00182 ** Insert an edge into a list keeping the list in order.
00183 */
00184 static
00185 void
00186 FASTCALL
00187 POLYGONFILL_ActiveListInsert(FILL_EDGE** activehead, FILL_EDGE* NewEdge )
00188 {
00189   FILL_EDGE *pPrev, *pThis;
00190   //DPRINT1("In POLYGONFILL_ActiveListInsert()\n");
00191   ASSERT ( activehead && NewEdge );
00192   if ( !*activehead )
00193   {
00194     NewEdge->pNext = NULL;
00195     *activehead = NewEdge;
00196     return;
00197   }
00198   /*
00199   ** First lets check to see if we have a new smallest value.
00200   */
00201   if (FILL_EDGE_Compare(NewEdge, *activehead) <= 0)
00202   {
00203     NewEdge->pNext = *activehead;
00204     *activehead = NewEdge;
00205     return;
00206   }
00207   /*
00208   ** Ok, now scan to the next spot to put this item.
00209   */
00210   pThis = *activehead;
00211   pPrev = NULL;
00212   while ( pThis && FILL_EDGE_Compare(pThis, NewEdge) < 0 )
00213   {
00214     pPrev = pThis;
00215     pThis = pThis->pNext;
00216   }
00217 
00218   ASSERT(pPrev);
00219   NewEdge->pNext = pPrev->pNext;
00220   pPrev->pNext = NewEdge;
00221   //DEBUG_PRINT_ACTIVE_EDGELIST(*activehead);
00222 }
00223 
00224 /*
00225 ** Create a list of edges for a list of points.
00226 */
00227 static
00228 FILL_EDGE_LIST*
00229 FASTCALL
00230 POLYGONFILL_MakeEdgeList(PPOINT Points, int Count)
00231 {
00232   int CurPt = 0;
00233   FILL_EDGE_LIST* list = 0;
00234   FILL_EDGE* e = 0;
00235 
00236   if ( 0 == Points || 2 > Count )
00237     return 0;
00238 
00239   list = (FILL_EDGE_LIST*)EngAllocMem(FL_ZERO_MEMORY, sizeof(FILL_EDGE_LIST), FILL_EDGE_ALLOC_TAG);
00240   if ( 0 == list )
00241     goto fail;
00242   list->Count = 0;
00243   list->Edges = (FILL_EDGE**)EngAllocMem(FL_ZERO_MEMORY, Count*sizeof(FILL_EDGE*), FILL_EDGE_ALLOC_TAG);
00244   if ( !list->Edges )
00245     goto fail;
00246 
00247   memset ( list->Edges, 0, Count * sizeof(FILL_EDGE*) );
00248 
00249   for ( CurPt = 1; CurPt < Count; ++CurPt )
00250   {
00251     e = POLYGONFILL_MakeEdge ( Points[CurPt-1], Points[CurPt] );
00252     if ( !e )
00253       goto fail;
00254 
00255     // If a straight horizontal line - who cares?
00256     if ( !e->absdy )
00257       EngFreeMem ( e );
00258     else
00259       list->Edges[list->Count++] = e;
00260   }
00261   e = POLYGONFILL_MakeEdge ( Points[CurPt-1], Points[0] );
00262   if ( !e )
00263     goto fail;
00264 
00265   if ( !e->absdy )
00266     EngFreeMem ( e );
00267   else
00268     list->Edges[list->Count++] = e;
00269   return list;
00270 
00271 fail:
00272 
00273   DPRINT1("Out Of MEMORY!!\n");
00274   POLYGONFILL_DestroyEdgeList ( list );
00275   return 0;
00276 }
00277 
00278 
00279 /*
00280 ** This slow routine uses the data stored in the edge list to
00281 ** calculate the x intercepts for each line in the edge list
00282 ** for scanline Scanline.
00283 **TODO: Get rid of this floating point arithmetic
00284 */
00285 static
00286 void
00287 FASTCALL
00288 POLYGONFILL_UpdateScanline(FILL_EDGE* pEdge, int Scanline)
00289 {
00290   if ( 0 == pEdge->dy )
00291     return;
00292 
00293   ASSERT ( pEdge->FromY <= Scanline && pEdge->ToY > Scanline );
00294 
00295   if ( pEdge->xmajor )
00296   {
00297     int steps;
00298 
00299     ASSERT ( pEdge->y == Scanline );
00300 
00301     // Now shoot to end of scanline collision
00302     steps = (pEdge->ErrorMax-pEdge->Error-1)/pEdge->absdy;
00303     if ( steps )
00304     {
00305       // Record first collision with scanline
00306       int x1 = pEdge->x;
00307       pEdge->x += steps * pEdge->XDirection;
00308       pEdge->Error += steps * pEdge->absdy;
00309       ASSERT ( pEdge->Error < pEdge->ErrorMax );
00310       pEdge->XIntercept[0] = min(x1,pEdge->x);
00311       pEdge->XIntercept[1] = max(x1,pEdge->x);
00312     }
00313     else
00314     {
00315       pEdge->XIntercept[0] = pEdge->x;
00316       pEdge->XIntercept[1] = pEdge->x;
00317     }
00318 
00319     // We should require exactly 1 step to step onto next scanline...
00320     ASSERT ( (pEdge->ErrorMax-pEdge->Error-1) / pEdge->absdy == 0 );
00321     pEdge->x += pEdge->XDirection;
00322     pEdge->Error += pEdge->absdy;
00323     ASSERT ( pEdge->Error >= pEdge->ErrorMax );
00324 
00325     // Now step onto next scanline...
00326     pEdge->Error -= pEdge->absdx;
00327     pEdge->y++;
00328   }
00329   else // Then this is a y-major line
00330   {
00331     pEdge->XIntercept[0] = pEdge->x;
00332     pEdge->XIntercept[1] = pEdge->x;
00333 
00334     pEdge->Error += pEdge->absdx;
00335     pEdge->y++;
00336 
00337     if ( pEdge->Error >= pEdge->ErrorMax )
00338     {
00339       pEdge->Error -= pEdge->ErrorMax;
00340       pEdge->x += pEdge->XDirection;
00341       ASSERT ( pEdge->Error < pEdge->ErrorMax );
00342     }
00343   }
00344 
00345   //DPRINT("Line (%d, %d) to (%d, %d) intersects scanline %d at (%d,%d)\n",
00346   //        pEdge->FromX, pEdge->FromY, pEdge->ToX, pEdge->ToY, Scanline, pEdge->XIntercept[0], pEdge->XIntercept[1] );
00347 }
00348 
00349 /*
00350  * This method updates the Active edge collection for the scanline Scanline.
00351  */
00352 static
00353 void
00354 APIENTRY
00355 POLYGONFILL_BuildActiveList ( int Scanline, FILL_EDGE_LIST* list, FILL_EDGE** ActiveHead )
00356 {
00357   int i;
00358 
00359   ASSERT ( list && ActiveHead );
00360   *ActiveHead = 0;
00361   for ( i = 0; i < list->Count; i++ )
00362   {
00363     FILL_EDGE* pEdge = list->Edges[i];
00364     ASSERT(pEdge);
00365     if ( pEdge->FromY <= Scanline && pEdge->ToY > Scanline )
00366     {
00367       POLYGONFILL_UpdateScanline ( pEdge, Scanline );
00368       POLYGONFILL_ActiveListInsert ( ActiveHead, pEdge );
00369     }
00370   }
00371 }
00372 
00373 /*
00374 ** This method fills the portion of the polygon that intersects with the scanline
00375 ** Scanline.
00376 */
00377 static
00378 void
00379 APIENTRY
00380 POLYGONFILL_FillScanLineAlternate(
00381   PDC dc,
00382   int ScanLine,
00383   FILL_EDGE* ActiveHead,
00384   SURFACE *psurf,
00385   BRUSHOBJ *BrushObj,
00386   MIX RopMode )
00387 {
00388   FILL_EDGE *pLeft, *pRight;
00389 
00390   if ( !ActiveHead )
00391     return;
00392 
00393   pLeft = ActiveHead;
00394   pRight = pLeft->pNext;
00395   ASSERT(pRight);
00396 
00397   while ( NULL != pRight )
00398   {
00399     int x1 = pLeft->XIntercept[0];
00400     int x2 = pRight->XIntercept[1];
00401     if ( x2 > x1 )
00402     {
00403       RECTL BoundRect;
00404       BoundRect.top = ScanLine;
00405       BoundRect.bottom = ScanLine + 1;
00406       BoundRect.left = x1;
00407       BoundRect.right = x2;
00408 
00409       //DPRINT("Fill Line (%d, %d) to (%d, %d)\n",x1, ScanLine, x2, ScanLine);
00410       IntEngLineTo(&psurf->SurfObj,
00411                    dc->rosdc.CombinedClip,
00412                    BrushObj,
00413                    x1,
00414                    ScanLine,
00415                    x2,
00416                    ScanLine,
00417                    &BoundRect,  // Bounding rectangle
00418                    RopMode);    // MIX
00419     }
00420     pLeft = pRight->pNext;
00421     pRight = pLeft ? pLeft->pNext : NULL;
00422   }
00423 }
00424 
00425 static
00426 void
00427 APIENTRY
00428 POLYGONFILL_FillScanLineWinding(
00429   PDC dc,
00430   int ScanLine,
00431   FILL_EDGE* ActiveHead,
00432   SURFACE *psurf,
00433   BRUSHOBJ *BrushObj,
00434   MIX RopMode )
00435 {
00436   FILL_EDGE *pLeft, *pRight;
00437   int x1, x2, winding = 0;
00438   RECTL BoundRect;
00439 
00440   if ( !ActiveHead )
00441     return;
00442 
00443   BoundRect.top = ScanLine;
00444   BoundRect.bottom = ScanLine + 1;
00445 
00446   pLeft = ActiveHead;
00447   winding = pLeft->YDirection;
00448   pRight = pLeft->pNext;
00449   ASSERT(pRight);
00450 
00451   // Setup first line...
00452   x1 = pLeft->XIntercept[0];
00453   x2 = pRight->XIntercept[1];
00454 
00455   pLeft = pRight;
00456   pRight = pLeft->pNext;
00457   winding += pLeft->YDirection;
00458 
00459   while ( NULL != pRight )
00460   {
00461     int newx1 = pLeft->XIntercept[0];
00462     int newx2 = pRight->XIntercept[1];
00463     if ( winding )
00464     {
00465       // Check and see if this new line touches the previous...
00466       if ( (newx1 >= x1 && newx1 <= x2)
00467     || (newx2 >= x1 && newx2 <= x2)
00468     || (x1 >= newx1 && x1 <= newx2)
00469     || (x2 >= newx2 && x2 <= newx2)
00470     )
00471       {
00472     // Yup, just tack it on to our existing line
00473     x1 = min(x1,newx1);
00474     x2 = max(x2,newx2);
00475       }
00476       else
00477       {
00478     // Nope - render the old line..
00479     BoundRect.left = x1;
00480     BoundRect.right = x2;
00481 
00482     //DPRINT("Fill Line (%d, %d) to (%d, %d)\n",x1, ScanLine, x2, ScanLine);
00483     IntEngLineTo(&psurf->SurfObj,
00484                      dc->rosdc.CombinedClip,
00485                      BrushObj,
00486                      x1,
00487                      ScanLine,
00488                      x2,
00489                      ScanLine,
00490                      &BoundRect,  // Bounding rectangle
00491                      RopMode);    // MIX
00492 
00493     x1 = newx1;
00494     x2 = newx2;
00495       }
00496     }
00497     pLeft = pRight;
00498     pRight = pLeft->pNext;
00499     winding += pLeft->YDirection;
00500   }
00501   // There will always be a line left-over, render it now...
00502   BoundRect.left = x1;
00503   BoundRect.right = x2;
00504 
00505   //DPRINT("Fill Line (%d, %d) to (%d, %d)\n",x1, ScanLine, x2, ScanLine);
00506   IntEngLineTo(&psurf->SurfObj,
00507                dc->rosdc.CombinedClip,
00508                BrushObj,
00509                x1,
00510                ScanLine,
00511                x2,
00512                ScanLine,
00513                &BoundRect,  // Bounding rectangle
00514                RopMode);    // MIX
00515 }
00516 
00517 // When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and
00518 // even-numbered polygon sides on each scan line. That is, GDI fills the area between the
00519 // first and second side, between the third and fourth side, and so on.
00520 
00521 // WINDING Selects winding mode (fills any region with a nonzero winding value).
00522 // When the fill mode is WINDING, GDI fills any region that has a nonzero winding value.
00523 // This value is defined as the number of times a pen used to draw the polygon would go around the region.
00524 // The direction of each edge of the polygon is important.
00525 
00526 BOOL
00527 APIENTRY
00528 FillPolygon(
00529   PDC dc,
00530   SURFACE *psurf,
00531   BRUSHOBJ *BrushObj,
00532   MIX RopMode,
00533   CONST PPOINT Points,
00534   int Count,
00535   RECTL BoundRect )
00536 {
00537   FILL_EDGE_LIST *list = 0;
00538   FILL_EDGE *ActiveHead = 0;
00539   int ScanLine;
00540   PDC_ATTR pdcattr = dc->pdcattr;
00541   void
00542   (APIENTRY *FillScanLine)(
00543     PDC dc,
00544     int ScanLine,
00545     FILL_EDGE* ActiveHead,
00546     SURFACE *psurf,
00547     BRUSHOBJ *BrushObj,
00548     MIX RopMode );
00549 
00550   //DPRINT("FillPolygon\n");
00551 
00552   /* Create Edge List. */
00553   list = POLYGONFILL_MakeEdgeList(Points, Count);
00554   /* DEBUG_PRINT_EDGELIST(list); */
00555   if (NULL == list)
00556     return FALSE;
00557 
00558   if ( WINDING == pdcattr->jFillMode )
00559     FillScanLine = POLYGONFILL_FillScanLineWinding;
00560   else /* Default */
00561     FillScanLine = POLYGONFILL_FillScanLineAlternate;
00562 
00563   /* For each Scanline from BoundRect.bottom to BoundRect.top,
00564    * determine line segments to draw
00565    */
00566   for ( ScanLine = BoundRect.top; ScanLine < BoundRect.bottom; ++ScanLine )
00567   {
00568     POLYGONFILL_BuildActiveList(ScanLine, list, &ActiveHead);
00569     //DEBUG_PRINT_ACTIVE_EDGELIST(ActiveHead);
00570     FillScanLine ( dc, ScanLine, ActiveHead, psurf, BrushObj, RopMode );
00571   }
00572 
00573   /* Free Edge List. If any are left. */
00574   POLYGONFILL_DestroyEdgeList(list);
00575 
00576   return TRUE;
00577 }
00578 
00579 BOOL FASTCALL
00580 IntFillPolygon(
00581     PDC dc,
00582     SURFACE *psurf,
00583     BRUSHOBJ *BrushObj,
00584     CONST PPOINT Points,
00585     int Count,
00586     RECTL DestRect,
00587     POINTL *BrushOrigin)
00588 {
00589     FILL_EDGE_LIST *list = 0;
00590     FILL_EDGE *ActiveHead = 0;
00591     FILL_EDGE *pLeft, *pRight;
00592     int ScanLine;
00593 
00594     //DPRINT("IntFillPolygon\n");
00595 
00596     /* Create Edge List. */
00597     list = POLYGONFILL_MakeEdgeList(Points, Count);
00598     /* DEBUG_PRINT_EDGELIST(list); */
00599     if (NULL == list)
00600         return FALSE;
00601 
00602     /* For each Scanline from DestRect.top to DestRect.bottom, determine line segments to draw */
00603     for ( ScanLine = DestRect.top; ScanLine < DestRect.bottom; ++ScanLine )
00604     {
00605         POLYGONFILL_BuildActiveList(ScanLine, list, &ActiveHead);
00606         //DEBUG_PRINT_ACTIVE_EDGELIST(ActiveHead);
00607 
00608         if ( !ActiveHead )
00609           return FALSE;
00610 
00611         pLeft = ActiveHead;
00612         pRight = pLeft->pNext;
00613         ASSERT(pRight);
00614 
00615         while ( NULL != pRight )
00616         {
00617             int x1 = pLeft->XIntercept[0];
00618             int x2 = pRight->XIntercept[1];
00619             if ( x2 > x1 )
00620             {
00621                 RECTL LineRect;
00622                 LineRect.top = ScanLine;
00623                 LineRect.bottom = ScanLine + 1;
00624                 LineRect.left = x1;
00625                 LineRect.right = x2;
00626 
00627                 IntEngBitBlt(&psurf->SurfObj,
00628                                  NULL,
00629                                  NULL,
00630                                  dc->rosdc.CombinedClip,
00631                                  NULL,
00632                                  &LineRect,
00633                                  NULL,
00634                                  NULL,
00635                                  BrushObj,
00636                                  BrushOrigin,
00637                                  ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
00638             }
00639             pLeft = pRight->pNext;
00640             pRight = pLeft ? pLeft->pNext : NULL;
00641         }
00642     }
00643 
00644     /* Free Edge List. If any are left. */
00645     POLYGONFILL_DestroyEdgeList(list);
00646 
00647     return TRUE;
00648 }
00649 
00650 /* EOF */

Generated on Sat May 26 2012 04:37:15 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.