cliprect.c

Go to the documentation of this file.
00001 
00007 #include <stdlib.h>
00008 #include <string.h>
00009 #include "../ctl/ctldef.h"
00010 #include "cliprect.h"
00011 
00019 void ClipRect_init( ClipRect* self, Rect* dirty, size_t cDirty, const Rect* bounds )
00020 {
00021     self->cDirty = 0;
00022     self->dirty = dirty;
00023     self->maxDirty = cDirty;
00024     self->bounds = *bounds;
00025 }
00026 
00034 void ClipRect_add( ClipRect* self, const Rect* rect )
00035 {
00036     Rect newRect = *rect;
00037     RectIntRect( newRect, self->bounds );
00038     if( !RectEmpty(newRect) )
00039     {
00040         Rect* curr = self->dirty;
00041         Rect* end = self->dirty + self->cDirty;
00042         while( curr < end )
00043         {
00044             /* Look for rectangles already containing newRect */
00045             if( RectContainsRect( *curr, newRect ) )
00046                 return;
00047             /* Look for rectangles to combine with newRect */
00048             if( RectInRect(*curr, newRect) )
00049             {
00050                 if( self->cDirty > 1 )
00051                 {
00052                     RectUnionRect( newRect, *curr );
00053                     self->cDirty--;
00054                     if( --end > curr )
00055                         *curr = *end;
00056                     curr = self->dirty;
00057                 }
00058                 else
00059                 {
00060                     RectUnionRect( *self->dirty, newRect );
00061                     return;
00062                 }
00063                 continue;
00064             }
00065             curr++;
00066         }
00067         if( self->cDirty < self->maxDirty )
00068         {
00069             /* Add new rectangle */
00070             self->dirty[self->cDirty++] = newRect;
00071         }
00072         else
00073         {
00074             /* If we run out of clipping rectangles, eat the last and try again */
00075             --self->cDirty;
00076             RectUnionRect( newRect, self->dirty[self->cDirty] );
00077             ClipRect_add( self, &newRect );
00078         }
00079     }
00080 }
00081 
00090 void ClipRect_remove( ClipRect* self, const Rect* rect )
00091 {
00092     /* Local function: Add a rectangle to 'self' */\
00093 #define ClipRect_remove_AddRect( l,t,r,b )\
00094     if( self->cDirty < self->maxDirty ) \
00095     {\
00096         Rect* nr = self->dirty + self->cDirty++;\
00097         nr->left = (l); \
00098         nr->top = (t); \
00099         nr->right = (r); \
00100         nr->bottom = (b); \
00101     }\
00102     else\
00103     {\
00104         /* Running out of our fixed pool of rectangles is definitely an error */\
00105         throwassert( "Ran out of dirty rectangles." );\
00106         break;\
00107     }
00108     Rect* curr = self->dirty;
00109     Rect* end = self->dirty + self->cDirty;
00110     while( curr < end )
00111     {
00112         /* If rects don't touch, don't touch them */
00113         if( RectOutside( *rect, *curr ) )
00114         {
00115             curr++;
00116             continue;
00117         }
00118         /* If rect contains curr, eat curr */
00119         else if( RectContainsRect( *rect, *curr ) )
00120         {
00121             *curr = *--end;
00122             continue;
00123         }
00124         /* If curr contains rect, pop a hole in the middle */
00125         else if( RectContainsRect( *curr, *rect ) )
00126         {
00127             ClipRect_remove_AddRect( curr->left,curr->top,curr->right,rect->top );  /* Top box */
00128             ClipRect_remove_AddRect( curr->left,rect->top,rect->left,rect->bottom );    /* Left box */
00129             ClipRect_remove_AddRect( rect->right,rect->top,curr->right,rect->bottom );  /* Right box */
00130             curr->top = rect->bottom; /* Bottom box */
00131         }
00132         /* Check for simple clip off the left or right */
00133         else if( (curr->top >= rect->top) && (curr->bottom <= rect->bottom) ) 
00134         {
00135             if( curr->left >= rect->left )
00136             {
00137                 curr->left = rect->right;
00138             }
00139             else 
00140             {
00141                 /* Check bisecting, make rects left & right, as applicable */
00142                 if( curr->right <= rect->right )
00143                 {
00144                     curr->right = rect->left;
00145                 }
00146                 else 
00147                 {
00148                     ClipRect_remove_AddRect( curr->left,curr->top,rect->left,curr->bottom );
00149                     curr->left = rect->right;
00150                 }
00151             }
00152         }
00153         /* Check for simple clip off the top or bottom */
00154         else if( (curr->left >= rect->left) && (curr->right <= rect->right) ) 
00155         {
00156             if(curr->top >= rect->top)
00157             {
00158                 curr->top = rect->bottom;
00159             }
00160             else 
00161             {
00162                 /* Check bisecting, make rects above & below, as applicable */
00163                 if(curr->bottom <= rect->bottom)
00164                 {
00165                     curr->bottom = rect->top;
00166                 }
00167                 else 
00168                 {
00169                     ClipRect_remove_AddRect( curr->left,curr->top,curr->right,rect->top);
00170                     curr->top = rect->bottom;
00171                 }
00172             }
00173         }
00174         /* See if we need to make an 'L', left and above */
00175         else if( RectPtInRect(*rect, curr->right-1, curr->bottom-1 ) )
00176         {
00177             ClipRect_remove_AddRect( curr->left, rect->top, rect->left, curr->bottom );
00178             curr->bottom = rect->top;
00179         }
00180         /* See if we need to make an 'L', right and above */
00181         else if( RectPtInRect(*rect, curr->left, curr->bottom-1 ) )
00182         {
00183             ClipRect_remove_AddRect( rect->right, rect->top, curr->right, curr->bottom );
00184             curr->bottom = rect->top;
00185         }
00186         /* See if we need to make an 'L', left and below */
00187         else if( RectPtInRect(*rect, curr->right-1, curr->top ) )
00188         {
00189             ClipRect_remove_AddRect( curr->left, curr->top, rect->left, rect->bottom );
00190             curr->top = rect->bottom;
00191         }
00192         /* See if we need to make an 'L', right and below */
00193         else if( RectPtInRect(*rect, curr->left, curr->top ) )
00194         {
00195             ClipRect_remove_AddRect( rect->right, curr->top, curr->right, rect->bottom );
00196             curr->top = rect->bottom;
00197         }
00198         /* 
00199          * We now know the clipping rectangle is making a 'U' shape
00200          * Just work out which edge to lop clipping box out of
00201          */
00202         /* Make a 'C' out of three rectangles */
00203         else if( curr->right >= rect->left && curr->right <= rect->right) 
00204         {
00205             ClipRect_remove_AddRect(curr->left, curr->top, curr->right, rect->top);     /* Top of C */
00206             ClipRect_remove_AddRect(curr->left, rect->top, rect->left, rect->bottom);       /* Left edge of C */
00207             curr->top = rect->bottom;                                   /* Bottom of C */
00208         }
00209         /* Make a 'U' out of three rectangles */
00210         else if( curr->top >= rect->top && curr->top <= rect->bottom) 
00211         {
00212             ClipRect_remove_AddRect(curr->left, curr->top, rect->left, rect->bottom);       /* Left edge of U */
00213             ClipRect_remove_AddRect(rect->right, curr->top, curr->right, rect->bottom); /* Right edge of U */
00214             curr->top = rect->bottom;                                   /* Bottom edge of U */
00215         }
00216         /* Make an upside-down 'U' out of three rectangles */
00217         else if( curr->bottom >= rect->top && curr->bottom <= rect->bottom )
00218         {
00219             ClipRect_remove_AddRect(curr->left, rect->top, rect->left, curr->bottom);       /* Left edge of U */
00220             ClipRect_remove_AddRect(rect->right, rect->top, curr->right, curr->bottom); /* Right edge of U */
00221             curr->bottom = rect->top;                                   /* Top edge of U */
00222         }
00223         /* Make a backwards 'C' out of three rectangles */
00224         else if( curr->left >= rect->left && curr->left <= rect->right ) 
00225         {
00226             ClipRect_remove_AddRect(curr->left, curr->top, curr->right, rect->top );        /* Top of C */
00227             ClipRect_remove_AddRect(rect->right, rect->top, curr->right, rect->bottom); /* Right edge of C */
00228             curr->top = rect->bottom;                                   /* Bottom edge of C */
00229         }
00230         curr++;
00231     }
00232 #undef ClipRect_remove_AddRect
00233 }
00234 
00240 Rect ClipRect_union( const ClipRect* self )
00241 {
00242     Rect ret;
00243     RectClear(ret);
00244     {
00245         pointer_foreach_const( Rect, self->dirty, self->cDirty, curr )
00246             RectUnionRect( ret, *curr );
00247     }
00248     return ret;
00249 }
00250 
00256 void ClipRect_merge( ClipRect* self, const ClipRect* other )
00257 {
00258     pointer_foreach_const( Rect, other->dirty, other->cDirty, curr )
00259         ClipRect_add( self, curr );
00260 }
00261 
00267 void ClipRect_copy( ClipRect* self, const ClipRect* other )
00268 {
00269     if( other->cDirty <= self->maxDirty )
00270     {
00271         memcpy( self->dirty, other->dirty, sizeof(Rect)*other->cDirty );
00272         self->cDirty = other->cDirty;
00273     }
00274     else
00275     {
00276         self->cDirty = 0;
00277         ClipRect_merge( self, other );
00278     }
00279 }

Generated on Fri Jan 2 15:28:34 2009 for Squat by  doxygen 1.5.6