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

bezier.c
Go to the documentation of this file.
00001 /*
00002  * COPYRIGHT:        GNU GPL, See COPYING in the top level directory
00003  * PROJECT:          ReactOS kernel
00004  * PURPOSE:          Bezier functions
00005  * FILE:             subsys/win32k/objects/bezier.c
00006  * PROGRAMER:        Unknown
00007  */
00008 
00009 #include <win32k.h>
00010 
00011 #define NDEBUG
00012 #include <debug.h>
00013 
00014 /******************************************************************
00015  *
00016  *   *Very* simple bezier drawing code,
00017  *
00018  *   It uses a recursive algorithm to divide the curve in a series
00019  *   of straight line segements. Not ideal but for me sufficient.
00020  *   If you are in need for something better look for some incremental
00021  *   algorithm.
00022  *
00023  *   7 July 1998 Rein Klazes
00024  */
00025 
00026  /*
00027   * Some macro definitions for bezier drawing.
00028   *
00029   * To avoid trucation errors the coordinates are
00030   * shifted upwards. When used in drawing they are
00031   * shifted down again, including correct rounding
00032   * and avoiding floating point arithmatic
00033   * 4 bits should allow 27 bits coordinates which I saw
00034   * somewere in the win32 doc's
00035   *
00036   */
00037 
00038 #define BEZIERSHIFTBITS 4
00039 #define BEZIERSHIFTUP(x)    ((x)<<BEZIERSHIFTBITS)
00040 #define BEZIERPIXEL        BEZIERSHIFTUP(1)
00041 #define BEZIERSHIFTDOWN(x)  (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
00042 /* Maximum depth of recursion */
00043 #define BEZIERMAXDEPTH  8
00044 
00045 /* Size of array to store points on */
00046 /* enough for one curve */
00047 #define BEZIER_INITBUFSIZE    (150)
00048 
00049 /* Calculate Bezier average, in this case the middle
00050  * correctly rounded...
00051  * */
00052 
00053 #define BEZIERMIDDLE(Mid, P1, P2) \
00054   (Mid).x=((P1).x+(P2).x + 1) >> 1;\
00055   (Mid).y=((P1).y+(P2).y + 1) >> 1;
00056 
00057 /**********************************************************
00058 * BezierCheck helper function to check
00059 * that recursion can be terminated
00060 *       Points[0] and Points[3] are begin and endpoint
00061 *       Points[1] and Points[2] are control points
00062 *       level is the recursion depth
00063 *       returns true if the recusion can be terminated
00064 */
00065 static BOOL FASTCALL BezierCheck( int level, POINT *Points)
00066 {
00067   INT dx, dy;
00068 
00069   dx=Points[3].x-Points[0].x;
00070   dy=Points[3].y-Points[0].y;
00071   if ( abs(dy) <= abs(dx) ) /* Shallow line */
00072   {
00073     /* Check that control points are between begin and end */
00074     if ( Points[1].x < Points[0].x )
00075     {
00076       if ( Points[1].x < Points[3].x )
00077     return FALSE;
00078     }
00079     else if ( Points[1].x > Points[3].x )
00080       return FALSE;
00081     if ( Points[2].x < Points[0].x)
00082     {
00083       if ( Points[2].x < Points[3].x )
00084     return FALSE;
00085     }
00086     else if ( Points[2].x > Points[3].x )
00087       return FALSE;
00088     dx = BEZIERSHIFTDOWN(dx);
00089     if ( !dx )
00090       return TRUE;
00091     if ( abs(Points[1].y-Points[0].y-(dy/dx)*
00092     BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
00093     abs(Points[2].y-Points[0].y-(dy/dx)*
00094     BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL
00095     )
00096     return FALSE;
00097       else
00098         return TRUE;
00099   }
00100   else
00101   {   
00102       /* Steep line */
00103       /* Check that control points are between begin and end */
00104       if(Points[1].y < Points[0].y)
00105       {
00106         if(Points[1].y < Points[3].y)
00107       return FALSE;
00108       }
00109       else if(Points[1].y > Points[3].y)
00110     return FALSE;
00111       if ( Points[2].y < Points[0].y )
00112       {
00113         if ( Points[2].y < Points[3].y )
00114       return FALSE;
00115       }
00116       else if ( Points[2].y > Points[3].y )
00117     return FALSE;
00118       dy = BEZIERSHIFTDOWN(dy);
00119       if ( !dy )
00120     return TRUE;
00121       if ( abs(Points[1].x-Points[0].x-(dx/dy)*
00122         BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
00123         abs(Points[2].x-Points[0].x-(dx/dy)*
00124         BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL
00125     )
00126     return FALSE;
00127       else
00128         return TRUE;
00129     }
00130 }
00131 
00132 /* Helper for GDI_Bezier.
00133  * Just handles one Bezier, so Points should point to four POINTs
00134  */
00135 static void APIENTRY GDI_InternalBezier( POINT *Points, POINT **PtsOut, INT *dwOut,
00136                 INT *nPtsOut, INT level )
00137 {
00138   if(*nPtsOut == *dwOut) {
00139     *dwOut *= 2;
00140     *PtsOut = ExAllocatePoolWithTag(PagedPool, *dwOut * sizeof(POINT), TAG_BEZIER);
00141   }
00142 
00143   if(!level || BezierCheck(level, Points)) {
00144     if(*nPtsOut == 0) {
00145       (*PtsOut)[0].x = BEZIERSHIFTDOWN(Points[0].x);
00146       (*PtsOut)[0].y = BEZIERSHIFTDOWN(Points[0].y);
00147        *nPtsOut = 1;
00148     }
00149     (*PtsOut)[*nPtsOut].x = BEZIERSHIFTDOWN(Points[3].x);
00150     (*PtsOut)[*nPtsOut].y = BEZIERSHIFTDOWN(Points[3].y);
00151     (*nPtsOut) ++;
00152   } else {
00153     POINT Points2[4]; /* For the second recursive call */
00154     Points2[3]=Points[3];
00155     BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
00156     BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
00157     BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
00158 
00159     BEZIERMIDDLE(Points[1], Points[0],  Points[1]);
00160     BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
00161     BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
00162 
00163     Points2[0]=Points[3];
00164 
00165     /* Do the two halves */
00166     GDI_InternalBezier(Points, PtsOut, dwOut, nPtsOut, level-1);
00167     GDI_InternalBezier(Points2, PtsOut, dwOut, nPtsOut, level-1);
00168   }
00169 }
00170 
00171 /***********************************************************************
00172  *           GDI_Bezier   [INTERNAL]
00173  *   Calculate line segments that approximate -what microsoft calls- a bezier
00174  *   curve.
00175  *   The routine recursively divides the curve in two parts until a straight
00176  *   line can be drawn
00177  *
00178  *  PARAMS
00179  *
00180  *  Points  [I] Ptr to count POINTs which are the end and control points
00181  *              of the set of Bezier curves to flatten.
00182  *  count   [I] Number of Points.  Must be 3n+1.
00183  *  nPtsOut [O] Will contain no of points that have been produced (i.e. no. of
00184  *              lines+1).
00185  *
00186  *  RETURNS
00187  *
00188  *  Ptr to an array of POINTs that contain the lines that approximinate the
00189  *  Beziers.  The array is allocated on the process heap and it is the caller's
00190  *  responsibility to HeapFree it. [this is not a particularly nice interface
00191  *  but since we can't know in advance how many points will generate, the
00192  *  alternative would be to call the function twice, once to determine the size
00193  *  and a second time to do the work - I decided this was too much of a pain].
00194  */
00195 POINT * FASTCALL GDI_Bezier( const POINT *Points, INT count, INT *nPtsOut )
00196 {
00197   POINT *out;
00198   INT Bezier, dwOut = BEZIER_INITBUFSIZE, i;
00199 
00200   if((count - 1) % 3 != 0) {
00201     return NULL;
00202   }
00203   *nPtsOut = 0;
00204 
00205   out = ExAllocatePoolWithTag(PagedPool, dwOut * sizeof(POINT), TAG_BEZIER);
00206   if(!out) {
00207     return NULL;
00208   }
00209 
00210   for(Bezier = 0; Bezier < (count-1)/3; Bezier++) {
00211     POINT ptBuf[4];
00212     memcpy(ptBuf, Points + Bezier * 3, sizeof(POINT) * 4);
00213     for(i = 0; i < 4; i++) {
00214       ptBuf[i].x = BEZIERSHIFTUP(ptBuf[i].x);
00215       ptBuf[i].y = BEZIERSHIFTUP(ptBuf[i].y);
00216     }
00217     GDI_InternalBezier( ptBuf, &out, &dwOut, nPtsOut, BEZIERMAXDEPTH );
00218   }
00219 
00220   return out;
00221 }
00222 /* EOF */

Generated on Sun May 27 2012 04:38:24 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.