Main Page | Modules | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members

bitmask.c

00001 /*
00002  *                          bitmask.c 1.0
00003  *                          -------------
00004  *    Simple and efficient bitmask collision detection routines
00005  *  Copyright (C) 2002 Ulf Ekstrom except for the bitcount function.
00006  *
00007  *           >  See the header file for more info. < 
00008  *  
00009  *  Please email bugs and comments to Ulf Ekstrom, ulfek@ifm.liu.se
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00024  */
00025 
00026 #include <malloc.h>
00027 #include "bitmask.h"
00028 
00029 #define MIN(a,b) ((a) < (b) ? (a) : (b))
00030 
00031 bitmask *bitmask_create(int w, int h)
00032 {
00033   bitmask *temp = malloc(sizeof(bitmask));
00034   if (! temp) return 0;
00035   temp->w = w;
00036   temp->h = h;
00037   temp->bits = calloc(h*((w - 1)/BITW_LEN + 1),sizeof(BITW));
00038   if (! temp->bits) 
00039     {
00040       free(temp);
00041       return 0;
00042     }
00043   else
00044     return temp;
00045 }
00046 
00047 void bitmask_free(bitmask *m)
00048 {
00049   free(m->bits);
00050   free(m);
00051 }
00052 
00053 int bitmask_overlap(const bitmask *a,const bitmask *b,int xoffset, int yoffset)
00054 {
00055   BITW *a_entry,*a_end;
00056   BITW *b_entry;
00057   BITW *ap,*bp;
00058   int shift,rshift,i,astripes,bstripes;
00059   
00060   if ((xoffset >= a->w) || (yoffset >= a->h) || (yoffset <= - b->h)) 
00061       return 0;
00062   
00063   if (xoffset >= 0) 
00064     {
00065       if (yoffset >= 0)
00066         {
00067           a_entry = a->bits + a->h*(xoffset/BITW_LEN) + yoffset;
00068           a_end = a_entry + MIN(b->h,a->h - yoffset);
00069           b_entry = b->bits;
00070         }
00071       else
00072         {
00073           a_entry = a->bits + a->h*(xoffset/BITW_LEN);
00074           a_end = a_entry + MIN(b->h + yoffset,a->h);
00075           b_entry = b->bits - yoffset;
00076         }
00077       shift = xoffset & BITW_MASK;
00078       if (shift)
00079         {
00080           rshift = BITW_LEN - shift;
00081           astripes = (a->w - 1)/BITW_LEN - xoffset/BITW_LEN;
00082           bstripes = (b->w - 1)/BITW_LEN + 1;
00083           if (bstripes > astripes) /* zig-zag .. zig*/
00084             {
00085               for (i=0;i<astripes;i++)
00086                 {
00087                   for (ap = a_entry,bp = b_entry;ap < a_end;) /* Join these two to one loop */
00088                       if ((*ap++ >> shift) & *bp++) return 1;
00089                   a_entry += a->h;
00090                   a_end += a->h;
00091                   for (ap = a_entry,bp = b_entry;ap < a_end;)
00092                       if ((*ap++ << rshift) & *bp++) return 1;
00093                   b_entry += b->h;
00094                 }
00095               for (ap = a_entry,bp = b_entry;ap < a_end;)
00096                   if ((*ap++ >> shift) & *bp++) return 1;
00097               return 0;
00098             }
00099           else /* zig-zag */
00100             {
00101               for (i=0;i<bstripes;i++)
00102                 {
00103                   for (ap = a_entry,bp = b_entry;ap < a_end;)
00104                     if ((*ap++ >> shift) & *bp++) return 1;
00105                   a_entry += a->h;
00106                   a_end += a->h;
00107                   for (ap = a_entry,bp = b_entry;ap < a_end;)
00108                       if ((*ap++  << rshift) & *bp++) return 1;
00109                   b_entry += b->h;
00110                 }
00111               return 0;
00112             }
00113         }
00114       else /* xoffset is a multiple of the stripe width, and the above routines wont work */
00115         {
00116           astripes = (MIN(b->w,a->w - xoffset) - 1)/BITW_LEN + 1;
00117           for (i=0;i<astripes;i++)
00118             {
00119               for (ap = a_entry,bp = b_entry;ap < a_end;)
00120                 if (*ap++ & *bp++) return 1;
00121               a_entry += a->h;
00122               a_end += a->h;
00123               b_entry += b->h;
00124             }
00125           return 0;
00126         }
00127     }
00128   else  
00129       return bitmask_overlap(b,a,-xoffset,-yoffset);
00130 }
00131 
00132 /* Will hang if there are no bits set in w! */
00133 static INLINE int firstsetbit(BITW w)
00134 {
00135   int i = 0;
00136   while ((w & 1) == 0) 
00137     {
00138       i++;
00139       w/=2;
00140     }
00141   return i;
00142 }
00143 
00144 /* x and y are given in the coordinates of mask a, and are untouched if the is no overlap */
00145 int bitmask_overlap_pos(const bitmask *a,const bitmask *b,int xoffset, int yoffset, int *x, int *y)
00146 {
00147   BITW *a_entry,*a_end;
00148   BITW *b_entry;
00149   BITW *ap,*bp;
00150   int shift,rshift,i,astripes,bstripes;
00151   
00152   if ((xoffset >= a->w) || (yoffset >= a->h) || (yoffset <= - b->h)) 
00153       return 0;
00154   
00155   if (xoffset >= 0) 
00156     {
00157       if (yoffset >= 0)
00158         {
00159           a_entry = a->bits + a->h*(xoffset/BITW_LEN) + yoffset;
00160           a_end = a_entry + MIN(b->h,a->h - yoffset);
00161           b_entry = b->bits;
00162         }
00163       else
00164         {
00165           a_entry = a->bits + a->h*(xoffset/BITW_LEN);
00166           a_end = a_entry + MIN(b->h + yoffset,a->h);
00167           b_entry = b->bits - yoffset;
00168         }
00169       shift = xoffset & BITW_MASK;
00170       if (shift)
00171         {
00172           rshift = BITW_LEN - shift;
00173           astripes = (a->w - 1)/BITW_LEN - xoffset/BITW_LEN;
00174           bstripes = (b->w - 1)/BITW_LEN + 1;
00175           if (bstripes > astripes) /* zig-zag .. zig*/
00176             {
00177               for (i=0;i<astripes;i++)
00178                 {
00179                   for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++)
00180                       if (*ap & (*bp << shift)) 
00181                         {
00182                           *y = (ap - a->bits) % a->h;
00183                           *x = ((ap - a->bits) / a->h)*BITW_LEN + firstsetbit(*ap & (*bp << shift));
00184                           return 1;
00185                         }
00186                   a_entry += a->h;
00187                   a_end += a->h;
00188                   for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++)
00189                       if (*ap & (*bp >> rshift)) 
00190                         {
00191                           *y = (ap - a->bits) % a->h;
00192                           *x = ((ap - a->bits) / a->h)*BITW_LEN + firstsetbit(*ap & (*bp >> rshift));
00193                           return 1;
00194                         }
00195                   b_entry += b->h;
00196                 }
00197               for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++)
00198                 if (*ap & (*bp << shift)) 
00199                   {
00200                     *y = (ap - a->bits) % a->h;
00201                     *x = ((ap - a->bits) / a->h)*BITW_LEN + firstsetbit(*ap & (*bp << shift));
00202                     return 1;
00203                   }
00204               return 0;
00205             }
00206           else /* zig-zag */
00207             {
00208               for (i=0;i<bstripes;i++)
00209                 {
00210                   for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++)
00211                       if (*ap & (*bp << shift)) 
00212                         {
00213                           *y = (ap - a->bits) % a->h;
00214                           *x = ((ap - a->bits) / a->h)*BITW_LEN + firstsetbit(*ap & (*bp << shift));
00215                           return 1;
00216                         }
00217                   a_entry += a->h;
00218                   a_end += a->h;
00219                   for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++)
00220                       if (*ap & (*bp >> rshift)) 
00221                         {
00222                           *y = (ap - a->bits) % a->h;
00223                           *x = ((ap - a->bits) / a->h)*BITW_LEN + firstsetbit(*ap & (*bp >> rshift));
00224                           return 1;
00225                         }
00226                   b_entry += b->h;
00227                 }
00228               return 0;
00229             }
00230         }
00231       else /* xoffset is a multiple of the stripe width, and the above routines won't work. */
00232         {
00233           astripes = (MIN(b->w,a->w - xoffset) - 1)/BITW_LEN + 1;
00234           for (i=0;i<astripes;i++)
00235             {
00236               for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++)
00237                 {
00238                   if (*ap & *bp) 
00239                     {
00240                       *y = (ap - a->bits) % a->h;
00241                       *x = ((ap - a->bits) / a->h)*BITW_LEN + firstsetbit(*ap & *bp); 
00242                       return 1;
00243                     }
00244                 }
00245               a_entry += a->h;
00246               a_end += a->h;
00247               b_entry += b->h;
00248             }
00249           return 0;
00250         }
00251     }
00252   else  
00253     {
00254       if (bitmask_overlap_pos(b,a,-xoffset,-yoffset,x,y))
00255         {
00256           *x += xoffset;
00257           *y += yoffset; 
00258           return 1;
00259         }
00260       else
00261         return 0;
00262     }
00263 }
00264 
00265 
00266 
00267 /* (C) Donald W. Gillies, 1992.  All rights reserved.  You may reuse
00268    this bitcount() function anywhere you please as long as you retain
00269    this Copyright Notice. */
00270 static INLINE int bitcount(unsigned long n)
00271 {
00272   register unsigned long tmp;
00273   return (tmp = (n) - (((n) >> 1) & 033333333333) - (((n) >> 2) & 011111111111),\
00274           tmp = ((tmp + (tmp >> 3)) & 030707070707),                    \
00275           tmp =  (tmp + (tmp >> 6)),                                    \
00276           tmp = (tmp + (tmp >> 12) + (tmp >> 24)) & 077);
00277 }
00278 /* End of Donald W. Gillies bitcount code */
00279 
00280 
00281 int bitmask_overlap_area(const bitmask *a,const bitmask *b,int xoffset, int yoffset)
00282 {
00283   BITW *a_entry,*a_end;
00284   BITW *b_entry;
00285   BITW *ap,*bp;
00286   int shift,rshift,i,astripes,bstripes;
00287   int count = 0;
00288 
00289   if ((xoffset >= a->w) || (yoffset >= a->h) || (yoffset <= - b->h)) 
00290       return 0;
00291   
00292   if (xoffset >= 0) 
00293     {
00294       if (yoffset >= 0)
00295         {
00296           a_entry = a->bits + a->h*(xoffset/BITW_LEN) + yoffset;
00297           a_end = a_entry + MIN(b->h,a->h - yoffset);
00298           b_entry = b->bits;
00299         }
00300       else
00301         {
00302           a_entry = a->bits + a->h*(xoffset/BITW_LEN);
00303           a_end = a_entry + MIN(b->h + yoffset,a->h);
00304           b_entry = b->bits - yoffset;
00305         }
00306       shift = xoffset & BITW_MASK;
00307       if (shift)
00308         {
00309           rshift = BITW_LEN - shift;
00310           astripes = (a->w - 1)/BITW_LEN - xoffset/BITW_LEN;
00311           bstripes = (b->w - 1)/BITW_LEN + 1;
00312           if (bstripes > astripes) /* zig-zag .. zig*/
00313             {
00314               for (i=0;i<astripes;i++)
00315                 {
00316                   for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++)
00317                     count += bitcount(((*ap >> shift) | (*(ap + a->h) << rshift)) & *bp);
00318                   a_entry += a->h;
00319                   a_end += a->h;
00320                   b_entry += b->h;
00321                 }
00322               for (ap = a_entry,bp = b_entry;ap < a_end;)
00323                 count += bitcount((*ap++ >> shift) & *bp++);
00324               return count;
00325             }
00326           else /* zig-zag */
00327             {
00328               for (i=0;i<bstripes;i++)
00329                 {
00330                   for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++)
00331                     count += bitcount(((*ap >> shift) | (*(ap + a->h) << rshift)) & *bp);
00332                   a_entry += a->h;
00333                   a_end += a->h;
00334                   b_entry += b->h;
00335                 }
00336               return count;
00337             }
00338         }
00339       else /* xoffset is a multiple of the stripe width, and the above routines wont work */
00340         {
00341           astripes = (MIN(b->w,a->w - xoffset) - 1)/BITW_LEN + 1;
00342           for (i=0;i<astripes;i++)
00343             {
00344               for (ap = a_entry,bp = b_entry;ap < a_end;)
00345                 count += bitcount(*ap++ & *bp++);
00346 
00347               a_entry += a->h;
00348               a_end += a->h;
00349               b_entry += b->h;
00350             }
00351           return count;
00352         }
00353     }
00354   else  
00355       return bitmask_overlap_area(b,a,-xoffset,-yoffset);
00356 }
00357 
00358 
00359 /* Draws mask b onto mask a (bitwise OR) */
00360 void bitmask_draw(bitmask *a,bitmask *b,int xoffset, int yoffset)
00361 {
00362   BITW *a_entry,*a_end;
00363   BITW *b_entry;
00364   BITW *ap,*bp;
00365   bitmask *swap;
00366   int shift,rshift,i,astripes,bstripes;
00367   
00368   if ((xoffset >= a->w) || (yoffset >= a->h) || (yoffset <= - b->h)) 
00369       return;
00370   
00371   if (xoffset >= 0) 
00372     {
00373       if (yoffset >= 0)
00374         {
00375           a_entry = a->bits + a->h*(xoffset/BITW_LEN) + yoffset;
00376           a_end = a_entry + MIN(b->h,a->h - yoffset);
00377           b_entry = b->bits;
00378         }
00379       else
00380         {
00381           a_entry = a->bits + a->h*(xoffset/BITW_LEN);
00382           a_end = a_entry + MIN(b->h + yoffset,a->h);
00383           b_entry = b->bits - yoffset;
00384         }
00385       shift = xoffset & BITW_MASK;
00386       if (shift)
00387         {
00388           rshift = BITW_LEN - shift;
00389           astripes = (a->w - 1)/BITW_LEN - xoffset/BITW_LEN;
00390           bstripes = (b->w - 1)/BITW_LEN + 1;
00391           if (bstripes > astripes) /* zig-zag .. zig*/
00392             {
00393               for (i=0;i<astripes;i++)
00394                 {
00395                   for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++)
00396                     *ap |= (*bp << shift);
00397                   a_entry += a->h;
00398                   a_end += a->h;
00399                   for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++)
00400                     *ap |= (*bp >> rshift);
00401                   b_entry += b->h;
00402                 }
00403               for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++)
00404                 *ap |= (*bp << shift);
00405               return;
00406             }
00407           else /* zig-zag */
00408             {
00409               for (i=0;i<bstripes;i++)
00410                 {
00411                   for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++)
00412                     *ap |= (*bp << shift);
00413                   a_entry += a->h;
00414                   a_end += a->h;
00415                   for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++)
00416                     *ap |= (*bp >> rshift);
00417                   b_entry += b->h;
00418                 }
00419               return;
00420             }
00421         }
00422       else /* xoffset is a multiple of the stripe width, and the above routines won't work. */
00423         {
00424           astripes = (MIN(b->w,a->w - xoffset) - 1)/BITW_LEN + 1;
00425           for (i=0;i<astripes;i++)
00426             {
00427               for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++)
00428                 {
00429                   *ap |= *bp;
00430                 }
00431               a_entry += a->h;
00432               a_end += a->h;
00433               b_entry += b->h;
00434             }
00435           return;
00436         }
00437     }
00438   else  
00439     {
00440       /* 'Swapping' arguments to be able to almost reuse the code above */
00441       swap = a;
00442       a = b;
00443       b = swap;
00444       xoffset *= -1;
00445       yoffset *= -1;
00446 
00447       if (yoffset >= 0)
00448         {
00449           a_entry = a->bits + a->h*(xoffset/BITW_LEN) + yoffset;
00450           a_end = a_entry + MIN(b->h,a->h - yoffset);
00451           b_entry = b->bits;
00452         }
00453       else
00454         {
00455           a_entry = a->bits + a->h*(xoffset/BITW_LEN);
00456           a_end = a_entry + MIN(b->h + yoffset,a->h);
00457           b_entry = b->bits - yoffset;
00458         }
00459       shift = xoffset & BITW_MASK;
00460       if (shift)
00461         {
00462           rshift = BITW_LEN - shift;
00463           astripes = (a->w - 1)/BITW_LEN - xoffset/BITW_LEN;
00464           bstripes = (b->w - 1)/BITW_LEN + 1;
00465           if (bstripes > astripes) /* zig-zag .. zig*/
00466             {
00467               for (i=0;i<astripes;i++)
00468                 {
00469                   for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++)
00470                     *bp |= (*ap >> shift);
00471                   a_entry += a->h;
00472                   a_end += a->h;
00473                   for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++)
00474                     *bp |= (*ap <<rshift); 
00475                   b_entry += b->h;
00476                 }
00477               for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++)
00478                 *bp |= (*ap >> shift);
00479               return;
00480             }
00481           else /* zig-zag */
00482             {
00483               for (i=0;i<bstripes;i++)
00484                 {
00485                   for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++)
00486                     *bp |= (*ap >> shift);
00487                   a_entry += a->h;
00488                   a_end += a->h;
00489                   for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++)
00490                     *bp |= (*ap << rshift);
00491                   b_entry += b->h;
00492                 }
00493               return;
00494             }
00495         }
00496       else /* xoffset is a multiple of the stripe width, and the above routines won't work. */
00497         {
00498           astripes = (MIN(b->w,a->w - xoffset) - 1)/BITW_LEN + 1;
00499           for (i=0;i<astripes;i++)
00500             {
00501               for (ap = a_entry,bp = b_entry;ap < a_end;ap++,bp++)
00502                 {
00503                   *bp |= *ap;
00504                 }
00505               a_entry += a->h;
00506               a_end += a->h;
00507               b_entry += b->h;
00508             }
00509           return;
00510         }
00511     }   
00512 }

Generated on Sat Oct 11 13:19:25 2003 for Spritelib by doxygen 1.3.4