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 * A bitmask is a simple array of bits, which can be used for 00008 * 2d collision detection. Set 'unoccupied' area to zero and 00009 * occupies areas to one and use the bitmask_overlap*() functions 00010 * to check for collisions. 00011 * The current implementation uses 32 bit wide stripes to hold 00012 * the masks, but should work just as well with 64 bit sizes. 00013 * (Note that the current bitcount function is 32 bit only!) 00014 * 00015 * The overlap tests uses the following offsets (which may be negative): 00016 * 00017 * +----+----------.. 00018 * |A | yoffset 00019 * | +-+----------.. 00020 * +--|B 00021 * |xoffset 00022 * | | 00023 * : : 00024 * 00025 * For optimal collision detection performance combine these functions 00026 * with some kind of pre-sorting to avoid comparing objects far from 00027 * each other. 00028 * 00029 * BUGS: No known bugs, even though they may certainly be in here somewhere. 00030 * Possible performance improvements could be to remove the div in 00031 * bitmask_overlap_pos() and to implement wider stripes if the masks used 00032 * are wider than 64 bits on the average. 00033 * 00034 * Performance of the various functions goes something like: 00035 * (relative timings, smaller is better) 00036 * 00037 * bitmask_overlap() 1.0 00038 * bitmask_overlap_pos() 1.3 00039 * bitmask_overlap_area() 1.6 00040 * 00041 * For maximum performance on my machine I use gcc with 00042 * -O2 -fomit-frame-pointer -funroll-loops 00043 * 00044 * 00045 * If you can make these functions faster or have found any bugs please 00046 * email Ulf Ekstrom, ulfek@ifm.liu.se 00047 * 00048 * 00049 * 00050 * This program is free software; you can redistribute it and/or 00051 * modify it under the terms of the GNU General Public License 00052 * as published by the Free Software Foundation; either version 2 00053 * of the License, or (at your option) any later version. 00054 * 00055 * This program is distributed in the hope that it will be useful, 00056 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00057 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00058 * GNU General Public License for more details. 00059 * 00060 * You should have received a copy of the GNU General Public License 00061 * along with this program; if not, write to the Free Software 00062 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00063 */ 00064 #ifndef BITMASK_H 00065 #define BITMASK_H 00066 00067 #include <SDL/begin_code.h> 00068 00069 /* Define INLINE for different compilers. */ 00070 #ifndef INLINE 00071 # ifdef __GNUC__ 00072 # define INLINE __inline__ 00073 # else 00074 # ifdef _MSC_VER 00075 # define INLINE __inline 00076 # else 00077 # define INLINE 00078 # endif 00079 # endif 00080 #endif 00081 00082 #define BITW unsigned long int 00083 #define BITW_LEN 32 00084 #define BITW_MASK 31 00085 #define BITN(n) ((BITW)1 << (n)) 00086 00087 #ifdef __cplusplus 00088 extern "C" { 00089 #endif 00090 00091 typedef struct bitmask 00092 { 00093 int w,h; 00094 BITW *bits; 00095 } bitmask; 00096 00097 /* Creates a bitmask of width w and height h. 00098 * The mask is automatically cleared when created. 00099 */ 00100 bitmask *bitmask_create(int w, int h); 00101 void bitmask_free(bitmask *m); 00102 00103 /* Returns nonzero if the bit at (x,y) is set. 00104 * Coordinates start at (0,0) 00105 */ 00106 static INLINE int bitmask_getbit(const bitmask *m,int x,int y) 00107 { 00108 return m->bits[x/BITW_LEN*m->h + y] & BITN(x & BITW_MASK); 00109 } 00110 00111 00112 /* Sets the bit at (x,y) */ 00113 static INLINE void bitmask_setbit(bitmask *m,int x,int y) 00114 { 00115 m->bits[x/BITW_LEN*m->h + y] |= BITN(x & BITW_MASK); 00116 } 00117 00118 00119 /* Clears the bit at (x,y) */ 00120 static INLINE void bitmask_clearbit(bitmask *m,int x,int y) 00121 { 00122 m->bits[x/BITW_LEN*m->h + y] &= ~BITN(x & BITW_MASK); 00123 } 00124 00125 00126 /* Returns nonzero if the masks overlap with the given offset. */ 00127 DECLSPEC int SDLCALL bitmask_overlap(const bitmask *a,const bitmask *b,int xoffset, int yoffset); 00128 00129 /* Like bitmask_overlap(), but will also give a point of intersection. 00130 * x and y are given in the coordinates of mask a, and are untouched if the is 00131 * no overlap. 00132 */ 00133 DECLSPEC int SDLCALL bitmask_overlap_pos(const bitmask *a,const bitmask *b,int xoffset, int yoffset, int *x, int *y); 00134 00135 /* Returns the number of overlapping 'pixels' */ 00136 DECLSPEC int SDLCALL bitmask_overlap_area(const bitmask *a,const bitmask *b,int xoffset, int yoffset); 00137 00138 /* Draws mask b onto mask a (bitwise OR) 00139 * Can be used to compose large (game background?) mask from 00140 * several submasks, which may speed up the testing. 00141 */ 00142 DECLSPEC void SDLCALL bitmask_draw(bitmask *a,bitmask *b,int xoffset, int yoffset); 00143 00144 #include <SDL/close_code.h> 00145 00146 #ifdef __cplusplus 00147 } 00148 #endif 00149 00150 00151 #endif