Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenbezier.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
1.7.6.1
|