draw.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2004 Sasha Vasko <sasha at aftercode.net>
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2.1 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017  */
00018 
00019 #undef  LOCAL_DEBUG
00020 
00021 #undef DEBUG_ELLIPS
00022 
00023 #ifdef _WIN32
00024 #include "win32/config.h"
00025 #else
00026 #include "config.h"
00027 #endif
00028 
00029 #ifdef _WIN32
00030 #define Long64_t __int64 
00031 #else
00032 #define Long64_t long long
00033 #endif
00034 
00035 /*#define LOCAL_DEBUG*/
00036 /*#define DO_CLOCKING*/
00037 
00038 #include <string.h>
00039 #include <stdlib.h>
00040 #include <ctype.h>
00041 #ifdef _WIN32
00042 # include "win32/afterbase.h"
00043 #else
00044 # include "afterbase.h"
00045 #endif
00046 #include "asvisual.h"
00047 #include "asimage.h"
00048 #include "draw.h"
00049 
00050 
00051 #define CTX_SELECT_CANVAS(ctx)  (get_flags((ctx)->flags, ASDrawCTX_UsingScratch)?(ctx)->scratch_canvas:(ctx)->canvas)
00052 
00053 #define CTX_PUT_PIXEL(ctx,x,y,ratio) (ctx)->apply_tool_func(ctx,x,y,ratio)
00054 #define CTX_FILL_HLINE(ctx,x_from,y,x_to,ratio) (ctx)->fill_hline_func(ctx,x_from,y,x_to,ratio)
00055 
00056 
00057 #define CTX_DEFAULT_FILL_THRESHOLD      126
00058 #define CTX_ELLIPS_FILL_THRESHOLD       140
00059 
00060 CARD32 _round1x1[1] =
00061 {  255 };
00062 
00063 CARD32 _round3x3[9] =
00064 { 64,  80,  64,
00065   80, 255,  80,
00066   64,  80,  64 };
00067 
00068 CARD32 _round3x3_solid[9] =
00069 { 64,  255,  64,
00070   255, 255,  255,
00071   64,  255,  64 };
00072 
00073 CARD32 _round5x5[25] =
00074 {  0,  24,  64,  24,   0,
00075   24,  64,  80,  64,  24,
00076   64,  80, 255,  80,  64,
00077   24,  64,  80,  64,  24,
00078    0,  24,  64,  24,   0,};
00079 
00080 CARD32 _round5x5_solid[25] =
00081 {  0,  255,  255,  255,   0,
00082   255,  255, 255,  255,  255,
00083   255,  255, 255,  255,  255,
00084   255,  255, 255,  255,  255,
00085    0,  255,  255,  255,   0,};
00086 
00087 ASDrawTool StandardBrushes[AS_DRAW_BRUSHES] = 
00088 {
00089         {1, 1, 0, 0, _round1x1},
00090         {3, 3, 1, 1, _round3x3_solid},
00091         {5, 5, 2, 2, _round5x5_solid}
00092 };       
00093 
00094 /*********************************************************************************/
00095 /* auxilary functions :                                                                                          */
00096 /*********************************************************************************/
00097 
00098 static void
00099 apply_tool_2D( ASDrawContext *ctx, int curr_x, int curr_y, CARD32 ratio )
00100 {
00101 
00102 /*fprintf( stderr, "(%d,%d)- ratio = %u (0x%X)\n", curr_x, curr_y, ratio, ratio);               */
00103         if( ratio  !=  0 ) 
00104         {       
00105                 CARD32 *src = ctx->tool->matrix ;
00106                 int corner_x = curr_x - ctx->tool->center_x ; 
00107                 int corner_y = curr_y - ctx->tool->center_y ; 
00108                 int tw = ctx->tool->width ;
00109                 int th = ctx->tool->height ;
00110                 int cw = ctx->canvas_width ;
00111                 int ch = ctx->canvas_height ;
00112                 int aw = tw ; 
00113                 int ah = th ;
00114                 CARD32 *dst = CTX_SELECT_CANVAS(ctx) ; 
00115                 int x, y ;
00116 
00117                 if( corner_x+tw <= 0 || corner_x >= cw || corner_y+th <= 0 || corner_y >= ch ) 
00118                         return ;
00119                  
00120                 if( corner_y > 0 ) 
00121                         dst += corner_y * cw ;
00122                 else if( corner_y < 0 ) 
00123                 {
00124                         ah -= -corner_y ;
00125                         src += -corner_y * tw ;
00126                 }
00127 
00128                 if( corner_x  > 0 ) 
00129                         dst += corner_x ;  
00130                 else if( corner_x < 0 )
00131                 {       
00132                         src += -corner_x ; 
00133                         aw -= -corner_x ;
00134                 }
00135         
00136                 if( corner_x + tw > cw ) 
00137                         aw = cw - corner_x;
00138 
00139                 if( corner_y + th > ch ) 
00140                         ah = ch - corner_y;
00141 
00142                 if( ratio == 255 ) 
00143                 {
00144                         for( y = 0 ; y < ah ; ++y ) 
00145                         {       
00146                                 for( x = 0 ; x < aw ; ++x ) 
00147                                 {
00148                                         if( dst[x] < src[x] ) 
00149                                                 dst[x] = src[x] ;
00150                                         /*
00151                                         register CARD32 t = (CARD32)dst[x] + (CARD32)src[x] ;
00152                                         dst[x] = t > 255? 255 : t ;
00153                                         */
00154                                 }
00155                                 src += tw ; 
00156                                 dst += cw ; 
00157                         }
00158                 }else
00159                 {                
00160                 /* ratio, implementing anti-aliasing should be applyed to the outer layer of 
00161                    the tool only ! */           
00162                         CARD32 *tsrc = src-tw;
00163                         CARD32 *tdst = dst-cw;
00164 
00165                         for( y = 0 ; y < ah ; ++y ) 
00166                         {       
00167                                 CARD32 v1, v2;
00168                                 tsrc += tw ; 
00169                                 tdst += cw ; 
00170                                 v1 = (tsrc[0]*ratio)/255 ;
00171                                 v2 = (tsrc[aw-1]*ratio)/255 ;
00172                                 if( tdst[0] < v1 ) tdst[0] = v1 ;
00173                                 if( tdst[aw-1] < v2 ) tdst[aw-1] = v2 ;
00174                         }
00175                         
00176                         for (x = 1 ; x < aw-1 ; ++x) 
00177                         {       
00178                                 CARD32 v1 = (src[x]*ratio)/255 ;
00179                                 CARD32 v2 = (tsrc[x]*ratio)/255 ;
00180                                 if( dst[x] < v1 ) dst[x] = v1 ;
00181                                 if( tdst[x] < v2 ) tdst[x] = v2 ;
00182                         }
00183 
00184                         for( y = 1 ; y < ah-1 ; ++y ) 
00185                         {       
00186                                 src += tw ; 
00187                                 dst += cw ; 
00188                                 for( x = 1 ; x < aw-1 ; ++x ) 
00189                                         if( dst[x] < src[x] ) 
00190                                                 dst[x] = src[x] ;
00191                         }
00192                 }
00193         }
00194 }          
00195 
00196 static inline void alpha_blend_point_argb32( CARD32 *dst, CARD32 value, CARD32 ratio)
00197 {
00198         CARD32 ta = (ARGB32_ALPHA8(value)*ratio)/255;
00199 
00200         if (ta >= 255)
00201                 *dst = value|0xFF000000;
00202         else
00203         {
00204                 CARD32 aa = 255-ta; /* must be 256 or we ! */
00205                 CARD32 orig = *dst;
00206                 CARD32 res = orig&0xFF000000; //((orig&0xFF000000)>>8)*aa + (ta<<24);
00207                 if (res < (ta<<24))
00208                         res = (ta<<24);
00209                 /* red and blue */
00210                 res |= (((orig&0x00FF00FF)*aa + (value&0x00FF00FF)*ta)>>8)&0x00FF00FF;
00211                 /* green */
00212                 res |= (((orig&0x0000FF00)*aa + (value&0x0000FF00)*ta)>>8)&0x0000FF00;
00213                 *dst = res;
00214         }
00215 }
00216 
00217 static void
00218 apply_tool_2D_colored( ASDrawContext *ctx, int curr_x, int curr_y, CARD32 ratio )
00219 {
00220         if( ratio  !=  0 ) 
00221         {       
00222                 CARD32 *src = ctx->tool->matrix ;
00223                 int corner_x = curr_x - ctx->tool->center_x ; 
00224                 int corner_y = curr_y - ctx->tool->center_y ; 
00225                 int tw = ctx->tool->width ;
00226                 int th = ctx->tool->height ;
00227                 int cw = ctx->canvas_width ;
00228                 int ch = ctx->canvas_height ;
00229                 int aw = tw ; 
00230                 int ah = th ;
00231                 CARD32 *dst = CTX_SELECT_CANVAS(ctx) ; 
00232                 int x, y ;
00233 
00234                 if( corner_x+tw <= 0 || corner_x >= cw || corner_y+th <= 0 || corner_y >= ch ) 
00235                         return ;
00236                  
00237                 if( corner_y > 0 ) 
00238                         dst += corner_y * cw ;
00239                 else if( corner_y < 0 ) 
00240                 {
00241                         ah -= -corner_y ;
00242                         src += -corner_y * tw ;
00243                 }
00244 
00245                 if( corner_x  > 0 ) 
00246                         dst += corner_x ;  
00247                 else if( corner_x < 0 )
00248                 {       
00249                         src += -corner_x ; 
00250                         aw -= -corner_x ;
00251                 }
00252         
00253                 if( corner_x + tw > cw ) 
00254                         aw = cw - corner_x;
00255 
00256                 if( corner_y + th > ch ) 
00257                         ah = ch - corner_y;
00258 
00259                 /* ratio, implementing anti-aliasing should be applyed to the outer layer of 
00260                    the tool only ! */           
00261                 {
00262                         CARD32 *tsrc = src-tw;
00263                         CARD32 *tdst = dst-cw;
00264                 
00265                         if (get_flags(ctx->flags, ASDrawCTX_UsingScratch))
00266                         {
00267                                 for( y = 0 ; y < ah ; ++y ) 
00268                                 {       
00269                                         CARD32 v1, v2;
00270                                         tsrc += tw ; 
00271                                         tdst += cw ; 
00272                                         v1 = (ARGB32_ALPHA8(tsrc[0])*ratio)/255 ;
00273                                         v2 = (ARGB32_ALPHA8(tsrc[aw-1])*ratio)/255 ;
00274                                         if( tdst[0] < v1 ) tdst[0] = v1 ;
00275                                         if( tdst[aw-1] < v2 ) tdst[aw-1] = v2 ;
00276 
00277                                 }
00278 
00279                                 for (x = 1 ; x < aw-1 ; ++x) 
00280                                 {       
00281                                         CARD32 v1 = (ARGB32_ALPHA8(src[x])*ratio)/255 ;
00282                                         CARD32 v2 = (ARGB32_ALPHA8(tsrc[x])*ratio)/255 ;
00283                                         if( dst[x] < v1 ) dst[x] = v1 ;
00284                                         if( tdst[x] < v2 ) tdst[x] = v2 ;
00285                                 }
00286 
00287                                 for( y = 1 ; y < ah-1 ; ++y ) 
00288                                 {       
00289                                         src += tw ; 
00290                                         dst += cw ; 
00291                                         for( x = 1 ; x < aw-1 ; ++x ) 
00292                                         {
00293                                                 CARD32 value = ARGB32_ALPHA8(src[x]);
00294                                                 if( dst[x] < value ) 
00295                                                         dst[x] = value ;
00296                                         }
00297                                 }
00298                         }else
00299                         {
00300                                 for( y = 0 ; y < ah ; ++y ) 
00301                                 {       
00302                                         tsrc += tw ; 
00303                                         tdst += cw ; 
00304                                         alpha_blend_point_argb32( tdst, tsrc[0], ratio);
00305                                         alpha_blend_point_argb32( tdst+aw-1, tsrc[aw-1], ratio);
00306                                 }
00307                                 for (x = 1 ; x < aw-1 ; ++x) 
00308                                 {       
00309                                         alpha_blend_point_argb32( dst+x, src[x], ratio);
00310                                         alpha_blend_point_argb32( tdst+x, tsrc[x], ratio);
00311                                 }
00312 
00313                                 for( y = 1 ; y < ah-1 ; ++y ) 
00314                                 {       
00315                                         src += tw ; 
00316                                         dst += cw ; 
00317                                         for( x = 1 ; x < aw-1 ; ++x ) 
00318                                                 alpha_blend_point_argb32( dst+x, src[x], 255);
00319                                 }
00320                         }
00321                 }
00322         }
00323 }          
00324 
00325 
00326 static void
00327 apply_tool_point( ASDrawContext *ctx, int curr_x, int curr_y, CARD32 ratio )
00328 {
00329         int cw = ctx->canvas_width ;
00330         if( ratio != 0 && curr_x >= 0 && curr_x < cw && curr_y >= 0 && curr_y < ctx->canvas_height ) 
00331         {       
00332                 CARD32 value = (ctx->tool->matrix[0]*ratio)/255 ;
00333                 CARD32 *dst = CTX_SELECT_CANVAS(ctx) ;
00334                 dst += curr_y * cw ; 
00335 
00336                 if( dst[curr_x] < value ) 
00337                         dst[curr_x] = value ;
00338         }
00339 }          
00340 
00341 
00342 static void 
00343 apply_tool_point_colored(ASDrawContext *ctx, int curr_x, int curr_y, CARD32 ratio)
00344 {
00345         /* Apply tool point argb32. - stolen from ROOT by Valery Onuchin, with changes */
00346         int cw = ctx->canvas_width;
00347         if (curr_x >= 0 && curr_x < cw && curr_y >= 0 && curr_y < ctx->canvas_height && ratio != 0)             
00348         {
00349                 CARD32 *dst = CTX_SELECT_CANVAS(ctx);
00350                 dst += curr_y * cw + curr_x;
00351                 if (get_flags(ctx->flags, ASDrawCTX_UsingScratch))
00352                 {
00353                         CARD32 value = (ARGB32_ALPHA8(ctx->tool->matrix[0])*ratio)/255 ;
00354                         if( *dst < value ) 
00355                                 *dst = value ;
00356                 }               
00357                 else
00358                         alpha_blend_point_argb32( dst, ctx->tool->matrix[0], ratio);
00359                 
00360         }
00361 }
00362 
00363 static void
00364 fill_hline_notile( ASDrawContext *ctx, int x_from, int y, int x_to, CARD32 ratio )
00365 {
00366         int cw = ctx->canvas_width ;
00367         if( ratio != 0 && x_to >= 0 && x_from < cw && y >= 0 && y < ctx->canvas_height ) 
00368         {       
00369                 CARD32 value = ratio ;
00370                 CARD32 *dst = CTX_SELECT_CANVAS(ctx) + y * cw ; 
00371                 int x1 = x_from, x2 = x_to ; 
00372                 if( x1 < 0 ) 
00373                         x1 = 0 ; 
00374                 if( x2 >= cw ) 
00375                         x2 = cw - 1 ; 
00376 
00377                 while( x1 <= x2 ) 
00378                 {
00379                         if( dst[x1] < value ) 
00380                                 dst[x1] = value ;
00381                         ++x1 ;
00382                 }
00383         }
00384 }
00385 
00386 static void 
00387 fill_hline_notile_colored(ASDrawContext *ctx, int x_from, int y, int x_to, CARD32 ratio)
00388 {
00389         int cw = ctx->canvas_width ;
00390         if( ratio != 0 && x_to >= 0 && x_from < cw && y >= 0 && y < ctx->canvas_height ) 
00391         {       
00392                 CARD32 value = ctx->tool->matrix[0] ;
00393                 CARD32 *dst = CTX_SELECT_CANVAS(ctx) + y * cw ; 
00394                 int x1 = x_from, x2 = x_to ; 
00395                 if( x1 < 0 ) 
00396                         x1 = 0 ; 
00397                 if( x2 >= cw ) 
00398                         x2 = cw - 1 ; 
00399 
00400                 if (get_flags(ctx->flags, ASDrawCTX_UsingScratch))
00401                 {
00402                         while( x1 <= x2 ) 
00403                         {
00404                                 CARD32 value = (ARGB32_ALPHA8(ctx->tool->matrix[0])*ratio)/255 ;
00405                                 if( dst[x1] < value ) 
00406                                         dst[x1] = value ;
00407                                 ++x1 ;
00408                         }
00409                 }else
00410                         while( x1 <= x2 ) 
00411                         {
00412                                 alpha_blend_point_argb32( dst+x1, value, ratio);
00413                                 ++x1 ;
00414                         }
00415         }
00416 }
00417 
00418 /*********************************************************************************/
00419 /* drawing functions :                                                                                   */
00420 /*********************************************************************************/
00421 static void
00422 ctx_draw_line_solid( ASDrawContext *ctx, int from_x, int from_y, int to_x, int to_y )
00423 {
00424         int x, y, end, dir = 1;
00425         int dx = to_x - from_x ; 
00426         int dy = to_y - from_y ; 
00427         if( dx < 0 ) 
00428                 dx = -dx ;
00429         if( dy < 0 ) 
00430                 dy = -dy ;
00431         
00432         if( dx >= dy ) 
00433         {       
00434         int Dy = -dx + 2*dy;
00435         int inct = 2*dy;
00436                 int incf = 2*(dy - dx);
00437                 
00438                 if( to_y > from_y ) 
00439                 {       x = from_x ; y = from_y ; end = to_x ; }
00440                 else
00441                 {       x = to_x ; y = to_y ; end = from_x ;    }
00442                 
00443                 if( end < x ) 
00444                         dir = -1 ;                               
00445         
00446                 CTX_PUT_PIXEL( ctx, x, y, 255 );
00447         while(x != end)
00448                 {
00449                 x += dir;
00450                 if(Dy > 0)
00451                         {
00452                         Dy += incf;
00453                         ++y;
00454                 }else 
00455                                 Dy += inct;
00456                 CTX_PUT_PIXEL( ctx, x, y, 255 );
00457         }
00458         }else
00459         {
00460         int Dx = -dy + 2*dx;
00461         int inct = 2*dx;
00462                 int incf = 2*(dx - dy);
00463                 
00464                 if( to_x > from_x ) 
00465                 {       y = from_y ; x = from_x ; end = to_y ; }
00466                 else
00467                 {       y = to_y ; x = to_x ; end = from_y ;    }
00468                 
00469                 if( end < y ) 
00470                         dir = -1 ;                               
00471         
00472                 CTX_PUT_PIXEL( ctx, x, y, 255 );
00473         while(y != end)
00474                 {
00475                 y += dir;
00476                 if(Dx > 0)
00477                         {
00478                         Dx += incf;
00479                         ++x;
00480                 }else 
00481                                 Dx += inct;
00482                 CTX_PUT_PIXEL( ctx, x, y, 255 );
00483         }
00484         }                
00485 }        
00486 
00487 static void
00488 ctx_draw_line_solid_aa( ASDrawContext *ctx, int from_x, int from_y, int to_x, int to_y )
00489 {
00490 #define RATIO_t int
00491         int x, y, end, dir = 1;
00492         int dx = to_x - from_x ; 
00493         int dy = to_y - from_y ; 
00494         if( dx < 0 ) 
00495                 dx = -dx ;
00496         if( dy < 0 ) 
00497                 dy = -dy ;
00498 
00499         if( dx == 0 || dy == 0 ) 
00500         {       
00501                 ctx_draw_line_solid( ctx, from_x, from_y, to_x, to_y );
00502                 return ;
00503         }
00504         
00505         if( dx >= dy ) 
00506         {       
00507                 RATIO_t ratio2 = 0x007FFFFF/dx ; 
00508                 CARD32 value = 0x003FFFFF; 
00509                 CARD32 value_incr = ratio2*dy ; 
00510                 int value_decr = (dx - dy)*ratio2 ;
00511 
00512                 
00513                 if( to_y > from_y ) 
00514                 {       x = from_x ; y = from_y ; end = to_x ; }
00515                 else
00516                 {       x = to_x ; y = to_y ; end = from_x ;    }
00517                 
00518                 if( end < x )   dir = -1 ;                               
00519         
00520                 CTX_PUT_PIXEL( ctx, x, y, 255 );
00521 /*              LOCAL_DEBUG_OUT( "x = %d, y = %d, dir = %d, value = %d, incr = %d, decr = %d, ratio = %d, value_incr = %d", 
00522                                                  x, y, dir, value, incr, decr, ratio, value_incr );
00523   */                    
00524         while(x != end)
00525                 {
00526                 x += dir;
00527                 if( (int)value > value_decr)
00528                         {
00529                                 value = (int)value - value_decr ;
00530                         ++y;
00531                 }else 
00532                                 value += value_incr ; 
00533 
00534                         {
00535                                 RATIO_t above = (value&0x00FF0000)>>16;
00536                                 /* LOCAL_DEBUG_OUT( "x = %d, y = %d, value = %d, above = %d",  x, y, value, above ); */
00537                                 switch( (above>>5)&0x03 )
00538                                 {
00539                                         case 0 :  /* 0 - 32 */ 
00540                                                 above = 128 - above ;
00541                                                 CTX_PUT_PIXEL( ctx, x, y-1, above ) ;
00542                                                 CTX_PUT_PIXEL( ctx, x, y, (~(above>>1))&0x00FF ) ; 
00543                                                 break ;   
00544                                         case 1 :  /* 32 - 64 */ 
00545                                                 {
00546                                                         RATIO_t a1 = (above - 32) ;
00547                                                         CTX_PUT_PIXEL( ctx, x, y+1, a1 ) ;
00548                                                         above = (~above)&0x7f ;
00549                                                         CTX_PUT_PIXEL( ctx, x, y-1, above - a1 ) ;
00550                                                         CTX_PUT_PIXEL( ctx, x, y, 255 ) ; 
00551                                                 }
00552                                                 break ;
00553                                         case 2 :  /* 64 - 96 */  
00554                                                 {
00555                                                         RATIO_t a1 = (96 - above) ;       
00556                                                         CTX_PUT_PIXEL( ctx, x, y-1, a1 ) ;
00557                                                         CTX_PUT_PIXEL( ctx, x, y, 255 ) ; 
00558                                                         CTX_PUT_PIXEL( ctx, x, y+1, above - a1 ) ;
00559                                                 }
00560                                                 break ;
00561                                         case 3 :  /* 96 - 128 */ 
00562                                                 {
00563                                                         above -= ((~above)&0x7f)>>1 ;     
00564                                                         CTX_PUT_PIXEL( ctx, x, y, (~(above>>1))&0x00FF ) ; 
00565                                                         CTX_PUT_PIXEL( ctx, x, y+1, above ) ;
00566                                                 }
00567                                                 break ;
00568                                 }
00569                         }
00570         }
00571         }else
00572         {
00573                 RATIO_t ratio2 = 0x007FFFFF/dy ; 
00574                 CARD32 value = 0x003FFFFF; 
00575                 CARD32 value_incr = ratio2*dx ; 
00576                 int value_decr = (dy - dx)*ratio2 ;
00577 
00578                 
00579                 if( to_x > from_x ) 
00580                 {       y = from_y ; x = from_x ; end = to_y ; }
00581                 else
00582                 {       y = to_y ; x = to_x ; end = from_y ;    }
00583                 
00584                 if( end < y )   dir = -1 ;                               
00585         
00586                 CTX_PUT_PIXEL( ctx, x, y, 255 );
00587 /*              LOCAL_DEBUG_OUT( "x = %d, y = %d, dir = %d, value = %d, incr = %d, decr = %d, ratio = %d, value_incr = %d", 
00588                                                  x, y, dir, value, incr, decr, ratio, value_incr );
00589   */                    
00590         while(y != end)
00591                 {
00592                 y += dir;
00593                 if( (int)value > value_decr)
00594                         {
00595                                 value = (int)value - value_decr ;
00596                         ++x;
00597                 }else 
00598                                 value += value_incr ; 
00599 
00600                         {
00601                                 RATIO_t above = (value&0x00FF0000)>>16;
00602                                 /* LOCAL_DEBUG_OUT( "x = %d, y = %d, value = %d, above = %d",  x, y, value, above ); */
00603                                 switch( (above>>5)&0x03 )
00604                                 {
00605                                         case 0 :  /* 0 - 32 */ 
00606                                                 above = 128 - above ;
00607                                                 CTX_PUT_PIXEL( ctx, x-1, y, above ) ;
00608                                                 CTX_PUT_PIXEL( ctx, x, y, (~(above>>1))&0x00FF ) ; 
00609                                                 break ;   
00610                                         case 1 :  /* 32 - 64 */ 
00611                                                 {
00612                                                         RATIO_t a1 = (above - 32) ;
00613                                                         CTX_PUT_PIXEL( ctx, x+1, y, a1 ) ;
00614                                                         above = (~above)&0x7f ;
00615                                                         CTX_PUT_PIXEL( ctx, x-1, y, above - a1 ) ;
00616                                                         CTX_PUT_PIXEL( ctx, x, y, 255 ) ; 
00617                                                 }
00618                                                 break ;
00619                                         case 2 :  /* 64 - 96 */  
00620                                                 {
00621                                                         RATIO_t a1 = (96 - above) ;       
00622                                                         CTX_PUT_PIXEL( ctx, x-1, y, a1 ) ;
00623                                                         CTX_PUT_PIXEL( ctx, x, y, 255 ) ; 
00624                                                         CTX_PUT_PIXEL( ctx, x+1, y, above - a1 ) ;
00625                                                 }
00626                                                 break ;
00627                                         case 3 :  /* 96 - 128 */ 
00628                                                 {
00629                                                         above -= ((~above)&0x7f)>>1 ;     
00630                                                         CTX_PUT_PIXEL( ctx, x, y, (~(above>>1))&0x00FF ) ; 
00631                                                         CTX_PUT_PIXEL( ctx, x+1, y, above ) ;
00632                                                 }
00633                                                 break ;
00634                                 }
00635                         }
00636         }
00637         }                
00638 }        
00639 
00640 #define SUPERSAMPLING_BITS      8
00641 #define SUPERSAMPLING_MASK      0x000000FF
00642 
00643 static inline void 
00644 render_supersampled_pixel( ASDrawContext *ctx, int xs, int ys )
00645 {
00646         if( xs >= 0 && ys >= 0 )
00647         {       
00648                 unsigned int xe = xs&SUPERSAMPLING_MASK ; 
00649                 unsigned int nxe = (~xs)&SUPERSAMPLING_MASK ; 
00650                 unsigned int x = xs>>SUPERSAMPLING_BITS;
00651                 unsigned int ye = ys&SUPERSAMPLING_MASK ; 
00652                 unsigned int nye = (~ys)&SUPERSAMPLING_MASK ; 
00653                 unsigned int y = ys>>SUPERSAMPLING_BITS; 
00654                 unsigned int v = (nxe*nye)>>8 ;   
00655                         
00656                 CTX_PUT_PIXEL( ctx, x, y, v ) ; 
00657 /*              LOCAL_DEBUG_OUT( "x = %d, y = %d, xe = %d, ye = %d, v = 0x%x", x, y, xe, ye, v ); */
00658                 v = (xe*(nye))>>8 ;       
00659                 CTX_PUT_PIXEL( ctx, x+1, y, v ) ; 
00660                 v = ((nxe)*ye)>>8 ;
00661                 CTX_PUT_PIXEL( ctx, x, ++y, v ) ; 
00662                 v = (xe*ye)>>8 ;          
00663                 CTX_PUT_PIXEL( ctx, x+1, y, v ) ; 
00664         }
00665 }       
00666 
00667 typedef struct ASCubicBezier
00668 {
00669         int x0, y0;
00670         int x1, y1;
00671         int x2, y2;
00672         int x3, y3;
00673 }ASCubicBezier;
00674 
00675 static void
00676 ctx_draw_bezier( ASDrawContext *ctx, int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3 )
00677 {
00678         int ch = ctx->canvas_height<<8 ;
00679         int cw = ctx->canvas_width<<8 ;
00680         
00681         ASCubicBezier *bstack = NULL ;
00682         int bstack_size = 0, bstack_used = 0 ;
00683         
00684 #define ADD_CubicBezier(X0,Y0,X1,Y1,X2,Y2,X3,Y3)        \
00685         do{ \
00686                 if( ((X0)>=0 || (X1)>=0 || (X2)>=0 || (X3)>=0) && ((X0)<cw||(X1)<cw||(X2)<cw||(X3)<cw) && \
00687                         ((Y0)>=0 || (Y1)>=0 || (Y2)>=0 || (Y3)>=0) && ((Y0)<ch||(Y1)<ch||(Y2)<ch||(Y3)<ch) ){ \
00688                         while( bstack_used >= bstack_size ) { \
00689                                 bstack_size += 2048/sizeof(ASCubicBezier); \
00690                                 bstack = (ASCubicBezier *)realloc( bstack, bstack_size*sizeof(ASCubicBezier)); \
00691                         } \
00692                         LOCAL_DEBUG_OUT( "(%d,%d),(%d,%d),(%d,%d),(%d,%d)", X0, Y0, X1, Y1, X2, Y2, X3, Y3 ); \
00693                         bstack[bstack_used].x0=X0; \
00694                         bstack[bstack_used].y0=Y0; \
00695                         bstack[bstack_used].x1=X1; \
00696                         bstack[bstack_used].y1=Y1; \
00697                         bstack[bstack_used].x2=X2; \
00698                         bstack[bstack_used].y2=Y2; \
00699                         bstack[bstack_used].x3=X3; \
00700                         bstack[bstack_used].y3=Y3; \
00701                         ++bstack_used ; \
00702                 } \
00703         }while(0)
00704 
00705 
00706         ADD_CubicBezier(x0,y0,x1,y1,x2,y2,x3,y3);
00707 
00708         while( bstack_used > 0 )
00709         {
00710                 --bstack_used ;
00711                 x0 = bstack[bstack_used].x0 ;
00712                 y0 = bstack[bstack_used].y0 ;
00713                 x1 = bstack[bstack_used].x1 ;
00714                 y1 = bstack[bstack_used].y1 ;
00715                 x2 = bstack[bstack_used].x2 ;
00716                 y2 = bstack[bstack_used].y2 ;
00717                 x3 = bstack[bstack_used].x3 ;
00718                 y3 = bstack[bstack_used].y3 ;
00719                 {
00720                         int x01 = x0 + ((x1-x0)>>1) ;   
00721                         int y01 = y0 + ((y1-y0)>>1) ; 
00722                         int x11 = x1 + ((x2-x1)>>1) ;      
00723                         int y11 = y1 + ((y2-y1)>>1) ; 
00724                         int x31 = x3 + ((x2-x3)>>1) ;      
00725                         int y31 = y3 + ((y2-y3)>>1) ; 
00726 
00727                         int x011 = x01 + ((x11-x01)>>1) ;         
00728                         int y011 = y01 + ((y11-y01)>>1) ; 
00729                         int x111 = x11 + ((x31-x11)>>1) ;         
00730                         int y111 = y11 + ((y31-y11)>>1) ; 
00731 
00732                         int x0111 = x011 + ((x111-x011)>>1) ;     
00733                         int y0111 = y011 + ((y111-y011)>>1) ; 
00734 
00735                         if( (x0&0xFFFFFF00) == (x0111&0xFFFFFF00) && (y0&0xFFFFFF00) == (y0111&0xFFFFFF00) ) 
00736                         {
00737                                 render_supersampled_pixel( ctx, x0, y0 );
00738                         }else if( x01 != x1 || y01 != y1 || x011 != x2 || y011 != y2 || x0111 != x3 || y0111 != y3 )
00739                                 ADD_CubicBezier( x0, y0, x01, y01, x011, y011, x0111, y0111 );
00740 
00741                         if( (x3&0xFFFFFF00) == (x0111&0xFFFFFF00) && (y3&0xFFFFFF00) == (y0111&0xFFFFFF00) ) 
00742                         {       
00743                                 render_supersampled_pixel( ctx, x3, y3 );
00744                         }else if( x0111 != x0 || y0111 != y0 || x111 != x1 || y111 != y1 || x31 != x2 || y31 != y2 )    
00745                                 ADD_CubicBezier( x0111, y0111, x111, y111, x31, y31, x3, y3 );  
00746                 }
00747         }
00748         if( bstack ) 
00749                 free( bstack );
00750 }
00751 
00752 typedef struct ASScanlinePart
00753 {
00754         int y ;
00755         int x0, x1;
00756 }ASScanlinePart;
00757 
00758 
00759 static void 
00760 ctx_flood_fill( ASDrawContext *ctx, int x_from, int y, int x_to, CARD32 min_val, CARD32 max_val  )
00761 {
00762         int ch = ctx->canvas_height ;
00763         int cw = ctx->canvas_width ;
00764         
00765         ASScanlinePart *sstack = NULL ;
00766         int sstack_size = 0, sstack_used = 0 ;
00767         CARD32 *canvas = CTX_SELECT_CANVAS(ctx);
00768         
00769         LOCAL_DEBUG_OUT( "(%d,%d,%d)", x_from, y, x_to );
00770 #define ADD_ScanlinePart(X0,Y0,X1)      \
00771         do{ \
00772                 if( ((X0)>=0 || (X1)>=0 ) && ((X0)<cw||(X1)<cw) && \
00773                          (Y0)>=0 && (Y0)<ch ){ \
00774                         while( sstack_used >= sstack_size ) { \
00775                                 sstack_size += 2048/sizeof(ASScanlinePart); \
00776                                 sstack = realloc( sstack, sstack_size*sizeof(ASScanlinePart)); \
00777                         } \
00778                         LOCAL_DEBUG_OUT( "(%d,%d,%d)", X0, Y0, X1 ); \
00779                         sstack[sstack_used].x0=X0; \
00780                         sstack[sstack_used].y=Y0; \
00781                         sstack[sstack_used].x1=X1; \
00782                         ++sstack_used ; \
00783                 } \
00784         }while(0)
00785 
00786         ADD_ScanlinePart(x_from,y,x_to);
00787 
00788         while( sstack_used > 0 )
00789         {
00790                 --sstack_used ; 
00791                 x_from = sstack[sstack_used].x0 ; 
00792                 x_to = sstack[sstack_used].x1 ; 
00793                 y = sstack[sstack_used].y ; 
00794                 if( x_from <  0 )
00795                         x_from = 0 ; 
00796                 if( x_to >= cw ) 
00797                         x_to = cw - 1 ; 
00798                 if( x_from <= x_to ) 
00799                 {       
00800                         /* here we have to check for lines below and above */
00801                         if( y > 0 ) 
00802                         {
00803                                 CARD32 *data = canvas + (y-1)*cw ; 
00804                                 int xc = x_from ; 
00805 
00806                                 while( xc <= x_to ) 
00807                                 {       
00808                                         if( data[xc] <= max_val && data[xc] >= min_val ) 
00809                                         {       
00810                                                 int x0 = xc, x1 = xc ; 
00811                                                 while( x0 >= 0 && data[x0] <= max_val && data[x0]  >= min_val ) --x0;
00812                                                 ++x0 ;
00813                                                 while( x1 < cw && data[x1] <= max_val && data[x1]  >= min_val ) ++x1;
00814                                                 --x1 ; 
00815                                         
00816                                                 ADD_ScanlinePart(x0,y-1,x1);                                    
00817                                                 LOCAL_DEBUG_OUT( "x = %d, y = %d, data[x] = 0x%X, x0 = %d, x1 = %d", xc, y-1, data[xc], x0, x1 );
00818                                                 while( xc <= x_to && xc <= x1+1 ) ++xc ; 
00819                                         }else
00820                                                 ++xc ;
00821                                 }
00822                         }        
00823                         if( y < ch-1 ) 
00824                         {
00825                                 CARD32 *data = canvas + (y+1)*cw ; 
00826                                 int xc = x_from ; 
00827 
00828                                 while( xc <= x_to ) 
00829                                 {       
00830                                         if( data[xc] <= max_val && data[xc] >= min_val ) 
00831                                         {       
00832                                                 int x0 = xc, x1 = xc ; 
00833                                                 while( x0 >= 0 && data[x0] <= max_val && data[x0]  >= min_val ) --x0;
00834                                                 ++x0 ;
00835                                                 while( x1 < cw && data[x1] <= max_val && data[x1]  >= min_val ) ++x1;
00836                                                 --x1 ; 
00837                                                 LOCAL_DEBUG_OUT( "x = %d, y = %d, data[x] = 0x%X, x0 = %d, x1 = %d", xc, y+1, data[xc], x0, x1 );
00838                                                 ADD_ScanlinePart(x0,y+1,x1);                                    
00839                                                 while( xc <= x_to && xc <= x1+1 ) ++xc ; 
00840                                         }else
00841                                                 ++xc ;
00842                                 }
00843                         }        
00844                         CTX_FILL_HLINE(ctx,x_from,y,x_to,255);          
00845                 }
00846         }        
00847         if( sstack ) 
00848                 free( sstack );
00849         
00850         
00851 }
00852 
00853 /*************************************************************************
00854  * Clip functions 
00855  *************************************************************************/
00856 Bool 
00857 clip_line( int k, int x0, int y0, int cw, int ch, int *x, int*y )       
00858 {
00859         int new_x = *x ; 
00860         int new_y = *y ;
00861 
00862         if( new_x < 0 ) 
00863         {
00864                 new_x = 0 ;
00865                 new_y = (-x0 / k) + y0 ;
00866         }        
00867         if( new_y < 0 ) 
00868         {
00869                 new_y = 0 ;
00870                 new_x = -y0 * k + x0 ; 
00871         }        
00872         if( new_x < 0 ) 
00873                 return False;
00874 
00875         /* here both new_x and new_y are non-negative */
00876         if( new_x >= cw ) 
00877         {
00878                 new_x = cw - 1 ;
00879                 if( k != 0 )
00880                 {
00881                         new_y = (new_x - x0)/k  + y0 ; 
00882                         if( new_y < 0 ) 
00883                                 return False;      
00884                 }
00885         }                
00886         if( new_y >= ch ) 
00887         {
00888                 new_y = ch - 1 ;
00889                 new_x = (new_y - y0) * k  + x0 ; 
00890                 if( new_x < 0 || new_x >= cw ) 
00891                         return False;      
00892         }                
00893         *x = new_x ; 
00894         *y = new_y ;
00895         return True;
00896 }
00897 
00898 /*********************************************************************************/
00899 /* context functions :                                                                                                                   */
00900 /*********************************************************************************/
00901 Bool asim_set_brush( ASDrawContext *ctx, int brush );
00902 
00903 ASDrawContext *
00904 create_asdraw_context( unsigned int width, unsigned int height )
00905 {
00906         ASDrawContext *ctx = safecalloc( 1, sizeof(ASDrawContext));
00907         
00908         ctx->canvas_width = width == 0 ? 1 : width ; 
00909         ctx->canvas_height = height == 0 ? 1 : height ;
00910         ctx->canvas = safecalloc(  ctx->canvas_width*ctx->canvas_height, sizeof(CARD32));
00911 
00912         asim_set_brush( ctx, 0 ); 
00913         ctx->fill_hline_func = fill_hline_notile ;
00914                                    
00915         return ctx;
00916 }          
00917 
00918 void
00919 destroy_asdraw_context( ASDrawContext *ctx )
00920 {
00921         if( ctx )
00922         {
00923                 if( ctx->canvas ) 
00924                         free( ctx->canvas );     
00925                 if( ctx->scratch_canvas ) 
00926                         free( ctx->scratch_canvas );     
00927                 free( ctx );
00928         }        
00929 }          
00930 
00931 Bool
00932 asim_set_brush( ASDrawContext *ctx, int brush ) 
00933 {
00934         if( brush >= 0 && brush < AS_DRAW_BRUSHES && ctx != NULL ) 
00935         {
00936                 ctx->tool = &(StandardBrushes[brush]) ;  
00937                 if( ctx->tool->width == 1 && ctx->tool->height == 1 ) 
00938                         ctx->apply_tool_func = apply_tool_point ;
00939                 else 
00940                         ctx->apply_tool_func = apply_tool_2D ; 
00941 
00942                 ctx->fill_hline_func = fill_hline_notile ;
00943 
00944                 clear_flags (ctx->flags, ASDrawCTX_ToolIsARGB);
00945 
00946                 return True;
00947         }        
00948         return False;
00949 }
00950 
00951 Bool
00952 asim_set_custom_brush( ASDrawContext *ctx, ASDrawTool *brush) 
00953 {
00954         if( brush !=NULL && ctx != NULL ) 
00955         {
00956                 ctx->tool = brush ;  
00957                 if( ctx->tool->width == 1 && ctx->tool->height == 1 ) 
00958                         ctx->apply_tool_func = apply_tool_point ;
00959                 else 
00960                         ctx->apply_tool_func = apply_tool_2D ; 
00961         
00962                 ctx->fill_hline_func = fill_hline_notile ;
00963 
00964                 clear_flags (ctx->flags, ASDrawCTX_ToolIsARGB);
00965 
00966                 return True;
00967         }        
00968         return False;
00969 }
00970 
00971 Bool
00972 asim_set_custom_brush_colored( ASDrawContext *ctx, ASDrawTool *brush) 
00973 {
00974         if( brush !=NULL && ctx != NULL ) 
00975         {
00976                 ctx->tool = brush ;  
00977                 if( ctx->tool->width == 1 && ctx->tool->height == 1 ) 
00978                         ctx->apply_tool_func = apply_tool_point_colored ;
00979                 else 
00980                         ctx->apply_tool_func = apply_tool_2D_colored ; 
00981 
00982                 ctx->fill_hline_func = fill_hline_notile_colored ;
00983                 set_flags (ctx->flags, ASDrawCTX_ToolIsARGB);
00984 
00985                 return True;
00986         }        
00987         return False;
00988 }
00989 
00990 
00991 Bool
00992 asim_start_path( ASDrawContext *ctx ) 
00993 {
00994         if( ctx == NULL ) 
00995                 return False;
00996         LOCAL_DEBUG_OUT( "scratch_canvas = %p, flags = 0x%lx", ctx->scratch_canvas, ctx->flags );
00997         if( ctx->scratch_canvas ) 
00998         {
00999                 if( get_flags( ctx->flags, ASDrawCTX_UsingScratch ) )
01000                         return False;     
01001                 memset( ctx->scratch_canvas, 0x00, ctx->canvas_width*ctx->canvas_height*sizeof(CARD32) );
01002         }else
01003                 ctx->scratch_canvas      = safecalloc(  ctx->canvas_width*ctx->canvas_height, sizeof(CARD32));
01004         set_flags( ctx->flags, ASDrawCTX_UsingScratch );
01005         return True;
01006 }
01007 
01008 void asim_flood_fill( ASDrawContext *ctx, int x, int y, CARD32 min_val, CARD32 max_val );
01009 
01010 
01011 Bool
01012 asim_apply_path( ASDrawContext *ctx, int start_x, int start_y, Bool fill, int fill_start_x, int fill_start_y, CARD8 fill_threshold ) 
01013 {
01014     if( ctx == NULL || !get_flags( ctx->flags, ASDrawCTX_UsingScratch ))        
01015                 return False;
01016         
01017         LOCAL_DEBUG_CALLER_OUT( "start_x = %d, start_y = %d, fill = %d, fill_start_x = %d, fill_start_y = %d",
01018                                                         start_x, start_y, fill, fill_start_x, fill_start_y );
01019 
01020         /* TODO : contour tracing functionality : */
01021         if( fill ) 
01022                 asim_flood_fill( ctx, fill_start_x, fill_start_y, 0, fill_threshold==0?CTX_DEFAULT_FILL_THRESHOLD:fill_threshold );     
01023 
01024         clear_flags( ctx->flags, ASDrawCTX_UsingScratch );       
01025 
01026         /* actually applying scratch : */
01027         {
01028                 int i = ctx->canvas_width*ctx->canvas_height ;
01029                 if (get_flags (ctx->flags, ASDrawCTX_CanvasIsARGB))
01030                 {
01031                         CARD32 argb = ctx->tool->matrix[ctx->tool->center_y*ctx->tool->width + ctx->tool->center_x];
01032                         while (--i >= 0)
01033                                 if (ctx->scratch_canvas[i])
01034                                         alpha_blend_point_argb32( ctx->canvas + i, argb, ctx->scratch_canvas[i]);
01035                 }else
01036                 {
01037                         while( --i >= 0 ) 
01038                                 if( ctx->canvas[i] < ctx->scratch_canvas[i] )
01039                                         ctx->canvas[i] = ctx->scratch_canvas[i] ;
01040                 }
01041         }               
01042         return True;
01043 }
01044 
01045 Bool
01046 apply_asdraw_context( ASImage *im, ASDrawContext *ctx, ASFlagType filter ) 
01047 {
01048         int chan ;
01049         int width, height ;
01050         if( im == NULL || ctx == NULL || filter == 0 )
01051                 return False;
01052         
01053         width = im->width ;
01054         height = im->height ;
01055         if( width != ctx->canvas_width || height != ctx->canvas_height )
01056                 return False;
01057         
01058         for( chan = 0 ; chan < IC_NUM_CHANNELS;  chan++ )
01059                 if( get_flags( filter, 0x01<<chan) )
01060                 {
01061                         int y;
01062                         register ASStorageID *rows = im->channels[chan] ;
01063                         register CARD32 *canvas_row = ctx->canvas ; 
01064                         for( y = 0 ; y < height ; ++y )
01065                         {       
01066 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)
01067                                 {
01068                                         int i;
01069                                         fprintf( stderr, "row %d, canvas_row = %p:", y, canvas_row );
01070                                         for( i = 0 ; i < width ; ++i)
01071                                                 fprintf( stderr, "0x%8.8lX ", canvas_row[i] );
01072                                         fprintf( stderr, "\n" );        
01073                                 }
01074 #endif
01075                                 if( rows[y] ) 
01076                                         forget_data( NULL, rows[y] ); 
01077                                 rows[y] = store_data( NULL, (CARD8*)canvas_row, width*sizeof(CARD32), ASStorage_32Bit|ASStorage_RLEDiffCompress, 0);
01078                                 canvas_row += width ; 
01079                         }
01080                 }
01081         return True;
01082 }          
01083 
01084 /**************************************************************************/
01085 /* generic line drawing - uses calls supplied function to actually render 
01086  * pixels :
01087  **************************************************************************/
01088 /**************************************************************************/
01089 void asim_move_to( ASDrawContext *ctx, int dst_x, int dst_y );
01090 
01091 void
01092 asim_line_to_generic( ASDrawContext *ctx, int dst_x, int dst_y, void (*func)(ASDrawContext*,int,int,int,int))
01093 {
01094         if( ctx ) 
01095         {
01096                 int from_x = ctx->curr_x ;      
01097                 int from_y = ctx->curr_y ; 
01098                 int to_x = dst_x ;      
01099                 int to_y = dst_y ;
01100                 int cw = ctx->canvas_width ; 
01101                 int ch = ctx->canvas_height ; 
01102                 
01103                 asim_move_to( ctx, dst_x, dst_y );                                         
01104 
01105                 if( to_y == from_y ) 
01106                 {
01107                         if( to_y < 0 || to_y >= ch ) 
01108                                 return ; 
01109                         if( from_x < 0 ) 
01110                                 from_x = 0 ; 
01111                         else if( from_x >= cw ) 
01112                                 from_x = cw - 1 ;                 
01113                         if( to_x < 0 ) 
01114                                 to_x = 0 ; 
01115                         else if( to_x >= cw ) 
01116                                 to_x = cw - 1 ;                   
01117                 }else if( to_x == from_x ) 
01118                 {
01119                         if( to_x < 0 || to_x >= ch ) 
01120                                 return ; 
01121                         if( from_y < 0 ) 
01122                                 from_y = 0 ; 
01123                         else if( from_y >= ch ) 
01124                                 from_y = ch - 1 ;                 
01125                         if( to_y < 0 ) 
01126                                 to_y = 0 ; 
01127                         else if( to_y >= ch ) 
01128                                 to_y = ch - 1 ;                   
01129                 }else
01130                 {                        
01131                         int k = (to_x - from_x)/(to_y - from_y);
01132                         int x0 = from_x ; 
01133                         int y0 = from_y ;
01134 
01135                         if( (from_x < 0 && to_x < 0 ) || (from_y < 0 && to_y < 0 ) ||
01136                                 (from_x >= cw && to_x >= cw ) || (from_y >= ch && to_y >= ch ))
01137                                 return ;
01138                         
01139                         if( !clip_line( k, x0, y0, cw, ch, &from_x, &from_y ) ) 
01140                                 return ;         
01141                         if( !clip_line( k, x0, y0, cw, ch, &to_x, &to_y ) ) 
01142                                 return ;         
01143                 }                       
01144                 if( from_x != to_x || from_y != to_y ) 
01145                         func( ctx, from_x, from_y, to_x, to_y );
01146         }        
01147 } 
01148 
01149 /*************************************************************************/
01150 /* Path primitives : *****************************************************/
01151 /*************************************************************************/
01152 void
01153 asim_move_to( ASDrawContext *ctx, int dst_x, int dst_y )
01154 {
01155         if( ctx ) 
01156         {
01157                 ctx->curr_x = dst_x ;   
01158                 ctx->curr_y = dst_y ; 
01159         }                
01160 }
01161            
01162 void
01163 asim_line_to( ASDrawContext *ctx, int dst_x, int dst_y ) 
01164 {
01165         asim_line_to_generic( ctx, dst_x, dst_y, ctx_draw_line_solid);  
01166 }        
01167 
01168 
01169 void
01170 asim_line_to_aa( ASDrawContext *ctx, int dst_x, int dst_y ) 
01171 {
01172         asim_line_to_generic( ctx, dst_x, dst_y, ctx_draw_line_solid_aa);                       
01173 }        
01174 
01175 void
01176 asim_cube_bezier( ASDrawContext *ctx, int x1, int y1, int x2, int y2, int x3, int y3 ) 
01177 {
01178         if( ctx ) 
01179         {       
01180                 int x0 = ctx->curr_x;
01181                 int y0 = ctx->curr_y;
01182                 Bool path_started = False;
01183                         
01184                 if (get_flags (ctx->flags, ASDrawCTX_CanvasIsARGB))
01185                         path_started = asim_start_path (ctx);
01186         
01187                 asim_move_to( ctx, x3, y3 );
01188                 ctx_draw_bezier( ctx, x0<<8, y0<<8, x1<<8, y1<<8, x2<<8, y2<<8, x3<<8, y3<<8 );
01189         
01190                 if (path_started)
01191                         asim_apply_path( ctx, 0, 0, False, 0, 0, 0);
01192         }               
01193 }
01194 
01195 /*************************************************************************/
01196 /* misc auxilary stuff : *************************************************/
01197 /*************************************************************************/
01198 /* Sinus lookup table */
01199 const signed int ASIM_SIN[91]=
01200 {
01201         0x00000000,
01202         0x00000478,0x000008EF,0x00000D66,0x000011DC,0x00001650,0x00001AC2,0x00001F33,0x000023A1,0x0000280C,0x00002C74,
01203         0x000030D9,0x0000353A,0x00003996,0x00003DEF,0x00004242,0x00004690,0x00004AD9,0x00004F1C,0x00005358,0x0000578F,
01204         0x00005BBE,0x00005FE6,0x00006407,0x00006820,0x00006C31,0x00007039,0x00007439,0x0000782F,0x00007C1C,0x00008000,
01205         
01206         0x000083DA,0x000087A9,0x00008B6D,0x00008F27,0x000092D6,0x00009679,0x00009A11,0x00009D9C,0x0000A11B,0x0000A48E,
01207         0x0000A7F3,0x0000AB4C,0x0000AE97,0x0000B1D5,0x0000B505,0x0000B827,0x0000BB3A,0x0000BE3F,0x0000C135,0x0000C41B,
01208         0x0000C6F3,0x0000C9BB,0x0000CC73,0x0000CF1C,0x0000D1B4,0x0000D43C,0x0000D6B3,0x0000D91A,0x0000DB6F,0x0000DDB4,
01209         0x0000DFE7,0x0000E209,0x0000E419,0x0000E617,0x0000E804,0x0000E9DE,0x0000EBA6,0x0000ED5C,0x0000EEFF,0x0000F090,
01210         0x0000F20E,0x0000F378,0x0000F4D0,0x0000F615,0x0000F747,0x0000F865,0x0000F970,0x0000FA68,0x0000FB4C,0x0000FC1C,
01211         0x0000FCD9,0x0000FD82,0x0000FE18,0x0000FE99,0x0000FF07,0x0000FF60,0x0000FFA6,0x0000FFD8,0x0000FFF6,0x00010000
01212 };
01213 
01214 static inline int asim_sin( int angle )
01215 {
01216         while( angle >= 360 ) 
01217                 angle -= 360 ;
01218         while( angle < 0 ) 
01219                 angle += 360 ;
01220         if( angle <= 90 ) 
01221                 return ASIM_SIN[angle];
01222         if( angle <= 180 ) 
01223                 return ASIM_SIN[180-angle];
01224         if( angle <= 270 ) 
01225                 return -ASIM_SIN[angle-180];
01226         return -ASIM_SIN[360-angle];
01227 }        
01228 
01229 int 
01230 asim_sqrt( double sval ) 
01231 {
01232 #ifdef HAVE_LONG_LONG
01233         Long64_t uval = (sval >= 0) ? (Long64_t)sval:-(Long64_t)sval ;
01234         Long64_t res = uval ; 
01235         Long64_t t = res*res ;
01236 #else
01237    long uval = (sval >= 0) ? (long)sval:-(long)sval ;
01238    long res = uval ; 
01239    long t = res*res ;
01240 #endif
01241         
01242         while( t > uval ) 
01243         {
01244                 res = res >> 1 ; 
01245                 t = t >> 2 ;      
01246         }        
01247         if( t == uval ) 
01248                 return (int)res;
01249         res = (res << 1) + 1 ;
01250         t = res*res ;
01251         while( t > uval ) 
01252         {
01253                 t -= (res<<1)-1 ;
01254                 --res ;
01255         }                 
01256         return (int)res;
01257 }         
01258 
01259 /*************************************************************************/
01260 /* some standard closed paths :                                          */
01261 /*************************************************************************/
01262 void
01263 asim_straight_ellips( ASDrawContext *ctx, int x, int y, int rx, int ry, Bool fill ) 
01264 {
01265         if( ctx && rx > 0 && ry > 0 &&
01266                 x + rx >= 0 && y+ry >= 0 && 
01267                 x - rx  < ctx->canvas_width && y - ry < ctx->canvas_height ) 
01268         {        
01269                 int max_y = ry ; 
01270                 int orig_x = x, orig_y = y, orig_rx = rx ; 
01271 #ifdef HAVE_LONG_LONG                                              
01272                 Long64_t rx2 = rx*rx, ry2 = ry * ry, d ; 
01273 #else
01274                 long rx2 = rx*rx, ry2 = ry * ry, d ; 
01275 #endif          
01276 
01277 #if 1
01278                 if (y + ry  > ctx->canvas_height && y - ry  < 0) 
01279                         max_y = max (y, ctx->canvas_height - y); 
01280 #endif                  
01281 #if 0
01282                 if( fill ) 
01283                 {
01284                         long y1 = 0; 
01285                         long x1 = rx-1;
01286                         long ty = rx*rx ;
01287                         long tx = x1*x1 ;
01288                         
01289                         do
01290                         {
01291                                 while( tx > ty && x1 > 0 )
01292                                 {
01293                                         tx -= (x1<<1)+1 ;
01294                                         --x1 ;
01295                                 }
01296                                 CTX_FILL_HLINE(ctx,x-x1,y+y1,x+x1,255);
01297                                 CTX_FILL_HLINE(ctx,x-x1,y-y1,x+x1,255);
01298                                 
01299                                 d = (y1<<1)+1 ;
01300                                 /* this is likely to break for large radii when there are no 64 bit ints */
01301                                 if( rx != ry )
01302                                         d = (d*rx2)/ry2 ;
01303                                 ty -= (long)d;
01304                         
01305                         }while( ++y1 < max_y ); 
01306                 }
01307 #endif
01308 
01309                 asim_start_path( ctx );
01310                 asim_move_to( ctx, x+rx, y );
01311                 LOCAL_DEBUG_OUT( "x = %d, y = %d, rx = %d, ry = %d", x, y, rx, ry );
01312 /* if no 64 bit integers - then tough luck - have to resort to beziers */
01313 #ifndef HAVE_LONG_LONG                                             
01314                 if( (rx == ry && (rx > 16000 || ry > 16000 || x < -16000 || y < -16000 || x > 16000 || y > 16000)) ||
01315                         (rx != ry && (rx > 1000 || ry > 1000 || x > 1000 || y > 1000 || x < -1000 || y < -1000)) ) 
01316                 {  /* somewhat imprecise approximation using 4 bezier curves */
01317                         int drx = rx*142 ;       /* that gives us precision of about 0.05% which is 
01318                                                                         * pretty good for integer math */
01319                         int dry = ry*142 ;
01320                         LOCAL_DEBUG_OUT( "drx = %d, dry = %d", drx, dry );
01321                         rx  = rx << 8 ; 
01322                         ry  = ry << 8 ; 
01323                         x  = x << 8 ; 
01324                         y  = y << 8 ; 
01325                         ctx_draw_bezier( ctx, x+rx, y, x+rx, y+dry, x+drx, y+ry, x, y+ry );
01326                         ctx_draw_bezier( ctx, x, y+ry, x-drx, y+ry, x-rx, y+dry, x-rx, y );
01327                         ctx_draw_bezier( ctx, x-rx, y, x-rx, y-dry, x-drx, y-ry, x, y-ry );
01328                         ctx_draw_bezier( ctx, x, y-ry, x+drx, y-ry, x+rx, y-dry, x+rx, y );
01329 
01330                 }else
01331 #endif                  
01332                 {                 
01333                         x = x<<4 ; 
01334                         y = y<<4 ; 
01335                         rx = rx<<4 ;
01336                         ry = ry<<4 ;
01337                         max_y = (max_y << 4) + 4;
01338 
01339                         {
01340                                 long min_r = rx - 1, max_r = rx + 1 ; 
01341                                 long y1 = 0; 
01342                                 long x1 = max_r;
01343                                 long min_ty = min_r * min_r ;
01344                                 long max_ty = max_r * max_r ;
01345                                 long tx = max_ty ;
01346                         
01347                                 do
01348                                 {
01349                                         long start_tx, start_x1 ;
01350                                         while( tx > max_ty && x1 > 0 )
01351                                         {
01352                                                 --x1; 
01353                                                 tx -= (x1<<1)+1 ;
01354                                         }        
01355                                         start_tx = tx ; 
01356                                         start_x1 = x1 ;
01357 
01358                                         
01359                                         while( tx > min_ty && x1 >= 0) 
01360                                         {
01361                                                 render_supersampled_pixel( ctx, (x-x1)<<4, (y+y1)<<4 );
01362                                                 render_supersampled_pixel( ctx, (x-x1)<<4, (y-y1)<<4 );
01363                                                 render_supersampled_pixel( ctx, (x+x1)<<4, (y+y1)<<4 );
01364                                                 render_supersampled_pixel( ctx, (x+x1)<<4, (y-y1)<<4 );
01365                                                 --x1; 
01366                                                 tx -= (x1<<1)+1 ;
01367                                         }
01368                                         tx = start_tx ; 
01369                                         x1 = start_x1 ;
01370                                         d = ((y1<<1)+1);
01371                                         if( rx != ry )
01372                                                 d = (d*rx2)/ry2 ;
01373                                         min_ty -= (long)d;
01374                                         max_ty -= (long)d;
01375                                 }while( ++y1 <= max_y ); 
01376                         }
01377                 }               
01378                 asim_apply_path( ctx, orig_x+orig_rx, orig_y, fill, orig_x, orig_y, CTX_ELLIPS_FILL_THRESHOLD );
01379         }               
01380 }        
01381 
01382 
01383 void
01384 asim_circle( ASDrawContext *ctx, int x, int y, int r, Bool fill ) 
01385 {
01386         asim_straight_ellips( ctx, x, y, r, r, fill );
01387 }        
01388 
01389 
01390 void
01391 asim_ellips( ASDrawContext *ctx, int x, int y, int rx, int ry, int angle, Bool fill ) 
01392 {
01393         while( angle >= 360 ) 
01394                 angle -= 360 ;
01395         while( angle < 0 ) 
01396                 angle += 360 ;
01397         
01398         if( angle == 0 || angle ==180  || rx == ry ) 
01399         {       
01400                 asim_straight_ellips( ctx, x, y, rx, ry, False );
01401                 if( angle == 180 ) 
01402                         asim_move_to( ctx, x-rx, y );
01403                 return;
01404         }
01405         if( angle == 90 || angle == 270 ) 
01406         {       
01407                 asim_straight_ellips( ctx, x, y, ry, rx, False );
01408                 asim_move_to( ctx, x, y + (angle == 90?-rx:rx) );
01409                 return;
01410         }
01411 
01412         if( ctx && rx > 0 && ry > 0 ) 
01413         {       
01414                 int dx0 = rx, dy0 = ry, dx1 = 0, dy1 = rx*4/3 ;
01415                 int x0, y0, x1down, y1down, x2down, y2down, x3, y3, x2up, y2up, x1up, y1up ; 
01416                 int ry4 = (ry<<2)/3 ;
01417                 int sin_val = asim_sin(angle);
01418                 int cos_val = asim_sin(angle+90);
01419                 if(sin_val < 0) 
01420                         sin_val = -sin_val ;
01421                 if(cos_val < 0) 
01422                         cos_val = -cos_val ;
01423                 dx0 = (rx*cos_val)>>8; 
01424                 dy0 = (rx*sin_val)>>8; 
01425                 dx1 = (ry4*sin_val)>>8;
01426                 dy1 = (ry4*cos_val)>>8; 
01427                 if( angle < 180 )
01428                 {
01429                         dy0 = -dy0 ;
01430                         dx1 = -dx1 ; 
01431                 }        
01432                 if( angle > 90 && angle < 270 )
01433                 {       
01434                         dx0 = -dx0 ; 
01435                         dy1 = -dy1 ;
01436                 }
01437                 x = x << 8;
01438                 y = y << 8;
01439                 x0 = x + dx0 ;
01440                 y0 = y + dy0 ;
01441                 x3 = x - dx0 ;
01442                 y3 = y - dy0 ; 
01443                 x1down = x0 + dx1 ;
01444                 y1down = y0 - dy1 ;
01445                 x2down = x3 + dx1 ; 
01446                 y2down = y3 - dy1 ;  
01447                 x2up = x3 - dx1 ; 
01448                 y2up = y3 + dy1 ;  
01449                 x1up = x0 - dx1 ;  
01450                 y1up = y0 + dy1 ;  
01451                 
01452 
01453                 asim_start_path( ctx );
01454                 asim_move_to( ctx, x0>>8, y0>>8 );
01455                 ctx_draw_bezier( ctx, x0, y0, x1down, y1down, x2down, y2down, x3, y3 );
01456                 ctx_draw_bezier( ctx, x3, y3, x2up, y2up, x1up, y1up, x0, y0 );
01457                 asim_apply_path( ctx, x0>>8, y0>>8, fill, x, y, CTX_ELLIPS_FILL_THRESHOLD );
01458         }               
01459 }        
01460 
01461 void
01462 asim_ellips2( ASDrawContext *ctx, int x, int y, int rx, int ry, int angle, Bool fill ) 
01463 {
01464         Bool direction = 1 ;
01465 
01466         while( angle >= 360 ) 
01467                 angle -= 360 ;
01468         while( angle < 0 ) 
01469                 angle += 360 ;
01470         
01471         if( angle == 0 || angle ==180  || rx == ry ) 
01472         {       
01473                 asim_straight_ellips( ctx, x, y, rx, ry, fill );
01474                 if( angle == 180 ) 
01475                         asim_move_to( ctx, x-rx, y );
01476                 return;
01477         }
01478         if( angle == 90 || angle == 270 ) 
01479         {       
01480                 asim_straight_ellips( ctx, x, y, ry, rx, fill );
01481                 asim_move_to( ctx, x, y + (angle == 90?-rx:rx) );
01482                 return;
01483         }
01484 
01485         if( angle > 180 ) 
01486                 angle -= 180 ; 
01487         if( angle > 90 ) 
01488         {       
01489                 angle = 180-angle ; 
01490                 direction = -1 ;
01491         }
01492 
01493 
01494         if( ctx && rx > 0 && ry > 0 ) 
01495         {       
01496                 int sin90 = 0x00010000 ;
01497                 double sin_val = (double)asim_sin(angle)/(double)sin90;
01498                 double cos_val = (double)asim_sin(angle+90)/(double)sin90;
01499                 double rx2 = rx*rx ; 
01500                 double ry2 = ry*ry ;
01501                 double c2 = rx2 - ry2 ; 
01502                 double xc2 = (c2 * cos_val)*cos_val ;
01503                 double yc2 = (c2 * sin_val)*sin_val ;
01504                 double A = rx2 - xc2 ;
01505                 double B = rx2 - yc2 ;
01506                 double C = -c2*sin_val*cos_val ;
01507                 double F = -rx2*ry2 ;
01508                 int yt = asim_sqrt(A);
01509                 int xt = (int)-C/yt ;
01510                 int xr = asim_sqrt(B);
01511                 int yr = (int)-C/xr ;
01512                 int x1 ; 
01513                 int x2 ; 
01514                 int line = yt; 
01515                 int last_med_dd1 = 0 ; 
01516                 int last_med_dd2 = 0 ; 
01517                 int y1 ;
01518                 double A2 = 2.*A ;
01519                 double BB; 
01520                 double CC = C*(double)((line<<1)-1);
01521 
01522 
01523                 xt = (int)((A-CC)/A2)  ;
01524                 y1 = line*direction ;
01525                 BB = B*(double)line*(double)line + F - B*(double)line - (B/4.);
01526                 x1 = xt+1 ;
01527                 x2 = xt-1 ;
01528                 --yr ; 
01529 
01530                 while( line >= -1 ) 
01531                 {
01532                         double d ; 
01533                         int dx1 = 0, dx2 = 0 ;
01534                         d = A*(double)x1*(double)x1 + BB +CC*(double)x1;
01535 #ifdef DEBUG_ELLIPS                                                                                        
01536                         fprintf( stderr, "line = %d, d1 = %f", y-line, d ); 
01537 #endif
01538                         if( d < 0 ) 
01539                         {       
01540                                 int aa = (int)((A-A2*(double)x1-CC)*255/A2);
01541                                 int dd = (int)(-aa-(double)(d*255/A2)) ; 
01542                                 int med_dd = (dd>>1)+1; 
01543         
01544                                 if( last_med_dd1 > 0 ) 
01545                                 { /* this prevents suddent jags on the line and makes it as 
01546                                    * smooth as it gets  */
01547                                         med_dd = (2*med_dd+last_med_dd1)/3 ;
01548                                 }
01549                                 ++dx1 ;
01550 #ifdef DEBUG_ELLIPS                                                                                        
01551                                 fprintf( stderr, " -> d1 = %f, dx1 = %d, aa = %d, dd = %d, med_dd = %d\n", d, dx1, aa, dd, med_dd ); 
01552 #endif
01553                                 if( med_dd+aa > dd ) 
01554                                 {
01555                                         int v = (dd-med_dd)*255/(aa+255) ;      
01556                                         CTX_PUT_PIXEL( ctx, x+(x1-1), y-y1, 255-v ) ;
01557                                         CTX_PUT_PIXEL( ctx, x-(x1-1), y+y1, 255-v ) ;
01558                                         CTX_PUT_PIXEL( ctx, x+(x1-2), y-y1, v ) ;
01559                                         CTX_PUT_PIXEL( ctx, x-(x1-2), y+y1, v ) ;
01560                                         dx1 = 2 ;
01561 #ifdef DEBUG_ELLIPS                                                                                        
01562                                         fprintf( stderr, "\t\t dx1 = %d, v = %d\n", dx1, v ); 
01563 #endif
01564                                 }else    
01565                                         while( dd > -(aa>>1) ) 
01566                                         {       
01567                                                 int v ; 
01568                                                 v = ( dd >= med_dd )? dd-med_dd: med_dd-dd ;  
01569                                                 v = v*255/med_dd ; 
01570                                                 if( v < 0 || v > 255) 
01571                                                         v = 250 ;
01572 
01573                                                 CTX_PUT_PIXEL( ctx, x+(x1-dx1), y-y1, 255-v ) ;
01574                                                 CTX_PUT_PIXEL( ctx, x-(x1-dx1), y+y1, 255-v ) ;
01575                                                 if( x1 >= xt && dd > med_dd ) 
01576                                                 {       
01577                                                         CTX_PUT_PIXEL( ctx, x+(x1-dx1), y-(y1+direction), v ) ;
01578                                                         CTX_PUT_PIXEL( ctx, x-(x1-dx1), y+(y1+direction), v ) ;
01579                                                 }
01580                                                 ++dx1 ; 
01581 #ifdef DEBUG_ELLIPS                                                                                        
01582                                                 fprintf( stderr, "\t\t dx1 = %d, aa = %d, dd = %d, med_dd = %d, v = %d, x = %d\n", dx1, aa, dd, med_dd, v, x+(x1-dx1) ); 
01583 #endif
01584                                                 aa += 255 ;
01585                                                 dd -= aa ; 
01586                                         }
01587                                 x1 -= (dx1>>1)-1 ;
01588                                 last_med_dd1 = med_dd ; 
01589                         }
01590 
01591                         d = A*(double)(x2+1)*(double)(x2+1) + BB +CC*(double)(x2+1) ;
01592                         if( line > yr ) 
01593                         {
01594 #ifdef DEBUG_ELLIPS                                                                                        
01595                                 fprintf( stderr, "line = %d, d2 = %f\n", y-line, d ); 
01596 #endif
01597                                 if( d < 0 )     
01598                                 {
01599                                         int aa = (int)((A+A2*(double)x2+CC)*255/A2);
01600                                         int dd = (int)(aa+(double)(d*255/A2))  ; 
01601                                         int med_dd = dd/2 - 1; 
01602 
01603                                         if( last_med_dd2 > 0 ) 
01604                                         { /* this prevents suddent jags on the line and makes it as 
01605                                            * smooth as it gets  */
01606                                                 med_dd = (med_dd*2+last_med_dd2)/3 ;
01607                                         }
01608                                         dx2 = 1;
01609 #ifdef DEBUG_ELLIPS                                                                                        
01610                                         fprintf( stderr, " -> d2 = %f, x2 = %d, dx2 = %d, aa = %d, dd = %d, med_dd = %d\n", d, x2, dx2, aa, dd, med_dd ); 
01611 #endif
01612                                         if( med_dd-aa < dd ) 
01613                                         {
01614                                                 int v = (med_dd-dd)*255/(aa+255) ;      
01615                                                 CTX_PUT_PIXEL( ctx, x+(x2+2), y-y1, 255-v ) ;
01616                                                 CTX_PUT_PIXEL( ctx, x-(x2+2), y+y1, 255-v ) ;
01617                                                 CTX_PUT_PIXEL( ctx, x+(x2+3), y-y1, v ) ;
01618                                                 CTX_PUT_PIXEL( ctx, x-(x2+3), y+y1, v ) ;
01619                                                 dx2 = 2 ;
01620 #ifdef DEBUG_ELLIPS                                                                                        
01621                                                 fprintf( stderr, "\t\t dx2 = %d, v = %d\n", dx2, v ); 
01622 #endif
01623                                         }else while( dd < aa/2 ) 
01624                                         { 
01625                                                 int v ; 
01626                                                 v = ( dd >= med_dd )? dd-med_dd: med_dd-dd ;  
01627                                                 v = v*255/-med_dd ; 
01628                                                 if( v < 0 || v > 255) 
01629                                                         v = 250 ;
01630 #ifdef DEBUG_ELLIPS                                                                                        
01631                                                 fprintf( stderr, "\t\t dx2 = %d, aa = %d, dd = %d, med_dd = %d, v = %d, x = %d\n", dx2, aa, dd, med_dd, v, x+(x2+dx2) );                                                
01632 #endif
01633                                                 ++dx2; 
01634                                                 CTX_PUT_PIXEL( ctx, x+(x2+dx2), y-y1, 255-v ) ;
01635                                                 CTX_PUT_PIXEL( ctx, x-(x2+dx2), y+y1, 255-v ) ;
01636                                                 if( x2 <= xt && dd < med_dd ) 
01637                                                 {       
01638                                                         CTX_PUT_PIXEL( ctx, x+(x2+dx2), y-(y1+direction), v ) ;
01639                                                         CTX_PUT_PIXEL( ctx, x-(x2+dx2), y+(y1+direction), v ) ;
01640                                                 }
01641                                                 aa += 255 ;
01642                                                 dd += aa ; 
01643                                         }
01644                                         x2 += (dx2>>1)-1 ;
01645                                         last_med_dd2 = med_dd ; 
01646                                 }        
01647                         }else if( line < yr ) 
01648                         {
01649 #ifdef DEBUG_ELLIPS                                                                                        
01650                                 fprintf( stderr, "line = %d, BELOW: d2 = %f\n", y-line, d ); 
01651 #endif
01652                                 if( d > 0. )
01653                                 {       
01654                                         int aa = (int)((A-A2*(double)(x2)-CC)*255./A2);
01655                                         int dd = (int)(aa+(double)(d*255./A2))  ; 
01656                                         int med_dd = dd/2+1; 
01657                                         
01658                                         if( last_med_dd2 > 0 ) 
01659                                                 med_dd = (med_dd*2+last_med_dd2)/3 ;
01660 
01661                                         dx2 = -1 ;
01662 #ifdef DEBUG_ELLIPS                                                                                        
01663                                         fprintf( stderr, " ->BELOW: d2 = %f, dx2 = %d, aa = %d, dd = %d, med_dd = %d\n", d, dx2, aa, dd, med_dd );                                      
01664 #endif
01665                                         if( med_dd-aa > dd ) 
01666                                         {
01667                                                 int v = (dd-med_dd)*255/(-aa+255) ;     
01668 #ifdef DEBUG_ELLIPS                                                                                        
01669                                                 fprintf( stderr, "\t\t BELOW: dx2 = %d, v = %d\n", dx2, v ); 
01670 #endif
01671                                                 CTX_PUT_PIXEL( ctx, x+(x2-1), y-y1, 255-v ) ;
01672                                                 CTX_PUT_PIXEL( ctx, x-(x2-1), y+y1, 255-v ) ;
01673                                                 CTX_PUT_PIXEL( ctx, x+(x2-2), y-y1, v ) ;
01674                                                 CTX_PUT_PIXEL( ctx, x-(x2-2), y+y1, v ) ;
01675                                                 dx2 = -2 ;
01676                                         }else while( dd > aa/2 )        
01677                                         {       
01678                                                 int v ; 
01679                                                 v = ( dd >= med_dd )? dd-med_dd: med_dd-dd ;  
01680                                                 v = v*255/med_dd ; 
01681                                                 if( v < 0 || v > 255) 
01682                                                         v = 250 ;
01683 #ifdef DEBUG_ELLIPS                                                                                     
01684                                                 fprintf( stderr, "\t\tBELOW:  dx2 = %d, aa = %d, dd = %d, med_dd = %d, v = %d, x = %d\n", dx2, aa, dd, med_dd, v, x+(x2+dx2) );                                                    
01685 #endif
01686                                                 CTX_PUT_PIXEL( ctx, x+(x2+dx2), y-y1, 255-v ) ;
01687                                                 CTX_PUT_PIXEL( ctx, x-(x2+dx2), y+y1, 255-v ) ;
01688                                                 --dx2; 
01689                                                 aa += 255 ;
01690                                                 dd += aa ; 
01691                                         }
01692                                         x2 += (dx2/2)+1 ;
01693                                         last_med_dd2 = med_dd ; 
01694                                 }                       
01695                         }else
01696                         {       
01697                         x2 = xr+2 ;     
01698 #ifdef DEBUG_ELLIPS                                      
01699                                 fprintf( stderr, "\t\t BELOW: x2 = %d, xr = %d\n", x2,xr); 
01700 #endif
01701                                 CTX_PUT_PIXEL( ctx, x+xr, y-y1, 255 ) ;
01702                                 CTX_PUT_PIXEL( ctx, x-xr, y+y1, 255 ) ;
01703                                 last_med_dd2 = 0 ;
01704                         }
01705 #ifdef DEBUG_ELLIPS                                      
01706                         fprintf( stderr, "dx1 = %d, x1 = %d, dx2 = %d, x2 = %d\n", dx1, x1, dx2, x2 ); 
01707 #endif
01708                         if( fill ) 
01709                         {       
01710                                 CTX_FILL_HLINE(ctx,x+(x1-2),y-y1,x+x2-1,255);
01711                                 CTX_FILL_HLINE(ctx,x-x2-1,y+y1,x-(x1-2),255);
01712                         }
01713                         
01714                         CC -= 2.*C ;
01715                         BB -= B*(double)((line-1)<<1) ;
01716                         y1 -= direction ;
01717                         --line ; 
01718                 }        
01719         }               
01720 }        
01721 
01722 /*************************************************************************/
01723 /* Flood fill functionality **********************************************/
01724 /*************************************************************************/
01725 
01726 void 
01727 asim_flood_fill( ASDrawContext *ctx, int x, int y, CARD32 min_val, CARD32 max_val  ) 
01728 {
01729         if( ctx && x >= 0 && x < ctx->canvas_width && y >= 0 && y < ctx->canvas_height )
01730         {
01731                 int x0 = x, x1 = x ; 
01732                 int cw = ctx->canvas_width ;
01733                 CARD32 *data = CTX_SELECT_CANVAS(ctx) + y*cw ; 
01734                 while( x0 >= 0 && data[x0] <= max_val && data[x0]  >= min_val ) --x0;
01735                 ++x0 ;
01736                 while( x1 < cw && data[x1] <= max_val && data[x1]  >= min_val ) ++x1;
01737                 --x1 ; 
01738                 LOCAL_DEBUG_OUT( "x = %d, y = %d, data[x] = 0x%X, x0 = %d, x1 = %d", x, y, data[x], x0, x1 );
01739                 
01740                 if( x0 <= x1 ) 
01741                         ctx_flood_fill( ctx, x0, y, x1, min_val, max_val );                     
01742         }                  
01743 }        
01744 
01745 void
01746 asim_rectangle( ASDrawContext *ctx, int x, int y, int width, int height ) 
01747 {
01748         asim_move_to( ctx, x, y );
01749         asim_line_to_generic( ctx, x+width, y, ctx_draw_line_solid);                    
01750         asim_line_to_generic( ctx, x+width, y+height, ctx_draw_line_solid);                        
01751         asim_line_to_generic( ctx, x, y+height, ctx_draw_line_solid);                      
01752         asim_line_to_generic( ctx, x, y, ctx_draw_line_solid);                     
01753 }        
01754 
01755 
01756 
01757 
01758 /*********************************************************************************/
01759 /* The end !!!!                                                                                                                                  */
01760 /*********************************************************************************/
01761 /*********************************************************************************/
01762 /* Test container :                                                                                                                              */
01763 /*********************************************************************************/
01764 
01765 #ifdef TEST_ASDRAW
01766 #include "afterimage.h"
01767 
01768 /*************************************/
01769 /* testing code for ROOT from CERN : */
01770 typedef int Int_t;
01771 typedef unsigned int UInt_t;
01772 typedef int Bool_t;
01773 
01774 static ASDrawContext *create_draw_context_argb32(ASImage *im, ASDrawTool *brush)
01775 {
01776    // Create draw context
01777 
01778    ASDrawContext *ctx = safecalloc (1, sizeof(ASDrawContext));
01779 
01780    ctx->canvas_width = im->width;
01781    ctx->canvas_height = im->height;
01782    ctx->canvas = im->alt.argb32;
01783    ctx->scratch_canvas = 0;
01784 
01785    ctx->flags = ASDrawCTX_CanvasIsARGB;
01786    asim_set_custom_brush_colored( ctx, brush);
01787    return ctx;
01788 }
01789 
01790 
01791 ASImage *TASImage_DrawCircle(ASVisual *asv, ASImage *fImage, Int_t x, Int_t y, Int_t r, const char *col, Int_t thick)
01792 {
01793    // Draw circle. If thick < 0 - draw filled circle
01794 
01795    thick = !thick ? 1 : thick;
01796    Int_t sz = thick*thick;
01797    CARD32 *matrix;
01798    int i;
01799    ASImage *img = 0;
01800    ASDrawContext *ctx;
01801 
01802    ARGB32 color;
01803    parse_argb_color(col, &color);
01804    ASDrawTool brush;
01805 
01806    matrix = malloc (sizeof(CARD32)*sz);
01807 
01808    for (i = 0; i < sz; i++) {
01809       matrix[i] = (CARD32)color;
01810    }
01811 
01812    brush.matrix = matrix;
01813    brush.height = brush.width = thick > 0 ? thick : 1;
01814    brush.center_y = brush.center_x = thick > 0 ? thick/2 : 0;
01815 
01816    img = tile_asimage(asv, fImage, 0, 0, fImage->width, fImage->height,
01817                             0, ASA_ARGB32, 0, ASIMAGE_QUALITY_DEFAULT);
01818    
01819    ctx = create_draw_context_argb32(img, &brush);
01820 
01821    asim_circle(ctx, x,  y, r, thick < 0);
01822    asim_cube_bezier(ctx, x+50, y+50, x+100, y+100, x+50, y+100);
01823    asim_move_to(ctx, x, y+200);
01824    asim_line_to_aa(ctx, x+200, y+100);
01825    asim_line_to_aa(ctx, x+200, y+200);
01826    asim_line_to_aa(ctx, x, y+200);
01827 
01828    free (matrix);
01829 //   destroy_asdraw_context32(ctx);
01830 
01831         return img;
01832 }
01833 
01834 // ROOT testing end
01835 /* testing code for ROOT from CERN   */
01836 /*************************************/
01837 
01838 int main(int argc, char **argv )
01839 {
01840         ASVisual *asv ;
01841         ASImage *back = NULL ;
01842         ASImage *drawing1 = NULL ;
01843         ASImage *merged_im = NULL ;
01844         ASImageLayer *layers ;
01845         int layers_num = 0, i;
01846         int screen = 0, depth = 0;
01847 
01848         ASDrawContext *ctx ;
01849 
01850 #define DRAW_TEST_SIZE 800      
01851         
01852         set_output_threshold( 10 );
01853 
01854 #ifndef X_DISPLAY_MISSING
01855         dpy = XOpenDisplay(NULL);
01856         screen = DefaultScreen(dpy);
01857         depth = DefaultDepth( dpy, screen );
01858 #endif
01859 
01860         asv = create_asvisual( dpy, screen, depth, NULL );
01861 
01862 
01863         back = create_asimage( DRAW_TEST_SIZE, DRAW_TEST_SIZE, 100 );
01864         back->back_color = ARGB32_White ;
01865         drawing1 = create_asimage( DRAW_TEST_SIZE, DRAW_TEST_SIZE, 100 );
01866         drawing1->back_color = ARGB32_Black ;
01867 
01868 
01869         ctx = create_asdraw_context(DRAW_TEST_SIZE, DRAW_TEST_SIZE);
01870         /* actuall drawing starts here */
01871 #if 1
01872 /*      for( i = 0 ; i < 50000 ; ++i ) */
01873 #if 1
01874         asim_move_to( ctx, 0, 0 ); 
01875         asim_line_to_aa( ctx, 200, 200 ); 
01876         asim_line_to_aa( ctx, 100, 10 );
01877         asim_line_to_aa( ctx, 10, 300 );
01878         asim_line_to_aa( ctx, 15, 400 );
01879         asim_move_to(ctx, 15, 420);  
01880         asim_line_to_aa( ctx, 200, 410 );
01881         asim_line_to_aa( ctx, 400, 440 );
01882                 
01883         asim_move_to(ctx, 10, 0);         
01884         asim_set_brush( ctx, 1 ); 
01885         asim_line_to_aa( ctx, 210, 200 ); 
01886         asim_line_to_aa( ctx, 110, 10 );
01887         asim_line_to_aa( ctx, 20, 300 );
01888         asim_line_to_aa( ctx, 25, 400 );
01889         asim_move_to(ctx, 15, 430);  
01890         asim_line_to_aa( ctx, 200, 420 );
01891         asim_line_to_aa( ctx, 400, 450 );
01892 
01893         asim_move_to(ctx, 20, 0);         
01894         asim_set_brush( ctx, 2 ); 
01895         asim_line_to_aa( ctx, 220, 200 ); 
01896         asim_line_to_aa( ctx, 120, 10 );
01897 
01898 #endif
01899         asim_move_to(ctx, 120, 10);       
01900         asim_set_brush( ctx, 2 ); 
01901 
01902         asim_line_to_aa( ctx, 30, 300 );
01903 #if 1
01904         asim_line_to_aa( ctx, 35, 400 );
01905         asim_move_to(ctx, 15, 440);    
01906         asim_line_to_aa( ctx, 200, 430 );
01907         asim_line_to_aa( ctx, 400, 460 );
01908 
01909     /****************************************/
01910         /* non-antialiased : */
01911 
01912         asim_move_to(ctx,  200, 0 ); 
01913 
01914         asim_set_brush( ctx, 0 ); 
01915         asim_line_to( ctx, 400, 200 ); 
01916         asim_line_to( ctx, 300, 10 );
01917         asim_line_to( ctx, 210, 300 );
01918         asim_line_to( ctx, 215, 400 );
01919         asim_move_to(ctx, 15, 450);  
01920         asim_line_to( ctx, 200, 440 );
01921         asim_line_to( ctx, 400, 470 );
01922                 
01923         asim_move_to(ctx, 210, 0);        
01924         asim_set_brush( ctx, 1 ); 
01925         asim_line_to( ctx, 410, 200 ); 
01926         asim_line_to( ctx, 310, 10 );
01927         asim_line_to( ctx, 220, 300 );
01928         asim_line_to( ctx, 225, 400 );
01929         asim_move_to(ctx, 15, 460);  
01930         asim_line_to( ctx, 200, 450 );
01931         asim_line_to( ctx, 400, 480 );
01932 
01933         asim_move_to(ctx, 220, 0);        
01934         asim_set_brush( ctx, 2 ); 
01935         asim_line_to( ctx, 420, 200 ); 
01936         asim_line_to( ctx, 320, 10 );
01937         asim_line_to( ctx, 230, 300 );
01938         asim_line_to( ctx, 235, 400 );
01939         asim_move_to(ctx, 15, 470);    
01940         asim_line_to( ctx, 200, 460 );
01941         asim_line_to( ctx, 400, 490 );
01942 
01943         asim_set_brush( ctx, 0 ); 
01944         asim_circle( ctx, 600, 110, 80, False );
01945         asim_circle( ctx, 600, 110, 50, False );
01946         asim_circle( ctx, 600, 110, 20, False );
01947         asim_circle( ctx, 600, 110, 1, False );
01948 
01949         asim_set_brush( ctx, 1 ); 
01950         asim_circle( ctx, 600, 110, 90, False );
01951         asim_circle( ctx, 600, 110, 60, False );
01952         asim_circle( ctx, 600, 110, 30, False );
01953         asim_circle( ctx, 600, 110, 5, False );
01954         
01955         asim_set_brush( ctx, 2 ); 
01956         asim_circle( ctx, 600, 110, 100, False );
01957         asim_circle( ctx, 600, 110, 70, False );
01958         asim_circle( ctx, 600, 110, 40, False );
01959         asim_circle( ctx, 600, 110, 10, False );
01960 
01961         asim_set_brush( ctx, 0 ); 
01962 /*      asim_circle( ctx, -1000, -1000, 2000, False );
01963         asim_ellips( ctx, -1000, -1000, 2000, 500, -45, False );
01964  */
01965         asim_circle( ctx, 595, 550, 200, False );
01966         i = 30 ;
01967 
01968         {
01969 /*              int k;
01970                 for( k = 0 ; k < 100 ; ++k )  */
01971                 for( i = 3 ; i < 180 ; i+=5 ) 
01972                 {       
01973 /*                      asim_ellips2( ctx, 595, 550, 198, 40, i, False );
01974                         asim_ellips( ctx, 595, 540, 198, 40, i, False );
01975                         asim_ellips2( ctx, 595, 550, 198, 40, i+30, False );
01976                         asim_ellips( ctx, 595, 540, 198, 40, i+30, False );
01977  */
01978                         asim_ellips2( ctx, 595, 550, 198, 60, i, False );
01979 /*                      asim_ellips( ctx, 585, 550, 198, 40, i+50, False );
01980                         asim_ellips( ctx, 595, 550, 198, 40, i, False ); 
01981  */
01982                 }
01983         }
01984         asim_circle( ctx, 705, 275, 90, True );
01985 //      asim_circle( ctx, 100, 100, 90, True );
01986 
01987         asim_circle( ctx, -40000, 500, 40500, False );
01988         asim_circle( ctx, -10000, 500, 10499, False );
01989 
01990         asim_ellips2( ctx, -1000, 500, 1500, 100, 2, False );
01991 
01992         asim_flood_fill( ctx, 664, 166, 0, 126 ); 
01993         asim_flood_fill( ctx, 670, 77, 0, 126 ); 
01994         asim_flood_fill( ctx, 120, 80, 0, 126 ); 
01995         asim_flood_fill( ctx, 300, 460, 0, 126 ); 
01996 
01997 #endif
01998 #endif
01999 #if 1
02000         /* commit drawing : */
02001         apply_asdraw_context( drawing1, ctx, SCL_DO_ALPHA ); 
02002         
02003         layers_num = 2 ;
02004         layers = create_image_layers( layers_num );
02005         
02006         layers[0].im = back ;
02007         layers[1].im = drawing1 ;
02008         layers[0].clip_width = DRAW_TEST_SIZE ;
02009         layers[0].clip_height = DRAW_TEST_SIZE ;
02010         layers[1].clip_width = DRAW_TEST_SIZE ;
02011         layers[1].clip_height = DRAW_TEST_SIZE ;
02012                 
02013         merged_im = merge_layers( asv, layers, layers_num,
02014                                       DRAW_TEST_SIZE, DRAW_TEST_SIZE,
02015                                                           ASA_ASImage,
02016                                                           0, ASIMAGE_QUALITY_DEFAULT );
02017 
02018 #if 1
02019         {
02020                 ASImage *overlayed_im = TASImage_DrawCircle(asv, merged_im, 84, 299, 80, "blue", -1);
02021                 ASImage2file( overlayed_im, NULL, "test_asdraw.overlayed.png", ASIT_Png, NULL );
02022                 destroy_asimage( &overlayed_im );
02023         }
02024 #endif  
02025         ASImage2file( merged_im, NULL, "test_asdraw.merged.png", ASIT_Png, NULL );
02026         destroy_asimage( &merged_im );
02027 #endif
02028 
02029         return 0;
02030 }
02031         
02032 
02033 #endif
02034 

Generated on Tue Jul 5 14:13:27 2011 for ROOT_528-00b_version by  doxygen 1.5.1