14 #include <SDL_video.h>
15 #include <SDL_endian.h>
18 #define COMPILE_TIME_ASSERT(condition) typedef char _compile_time_assert__[(condition) ? 1 : -1];
20 #define MAX_INTVAL(int_type) ((((unsigned int_type)(-1))-1)/2)
22 int get_pmask_pixel(struct PMASK
*mask
, int x
, int y
) {
23 return 1 & (mask
->mask
[(mask
->h
* (x
>> MASK_WORD_BITBITS
)) + y
] >> (x
& (MASK_WORD_BITS
-1)));
25 void set_pmask_pixel(struct PMASK
*mask
, int x
, int y
, int value
) {
27 mask
->mask
[(mask
->h
* (x
>> MASK_WORD_BITBITS
)) + y
] |= 1 << (x
& (MASK_WORD_BITS
-1));
29 mask
->mask
[(mask
->h
* (x
>> MASK_WORD_BITBITS
)) + y
] &=~(1 << (x
& (MASK_WORD_BITS
-1)));
33 void install_pmask() {
34 COMPILE_TIME_ASSERT((1 << MASK_WORD_BITBITS
) == MASK_WORD_BITS
);
38 void init_pmask (struct PMASK
*mask
, int w
, int h
)
40 int words
, total_words
, x
;
42 if ((w
> MAX_INTVAL(short int)) || (h
> MAX_INTVAL(short int)) || (w
< 0) || (h
< 0))
44 mask
->w
= mask
->h
= 0;
45 #ifndef MASK_SINGLE_MEMORY_BLOCK
51 words
= 1 + ((w
-1) >> MASK_WORD_BITBITS
);
53 total_words
= words
* h
;
55 #ifdef MASK_SINGLE_MEMORY_BLOCK
58 mask
->mask
= (MASK_WORD_TYPE
*) malloc(
59 MASK_WORD_SIZE
* total_words
);
61 mask
->w
= mask
->h
= 0;
66 //Now we initialize some of the fields of the structure...
71 //Now we have a proper mask structure allocated and mostly initialized, but the mask data has garbage! We have to initialize it to 0's:
72 for(x
=0; x
< total_words
; x
+=1) {
76 //only clear right hand edge if CLEAR_MASK is not defined
77 for(x
=total_words
-h
; x
< total_words
; x
+=1) {
84 void deinit_pmask(struct PMASK
*mask
) {
87 #ifndef MASK_SINGLE_MEMORY_BLOCK
88 if (mask
->mask
) free(mask
->mask
);
94 void destroy_pmask(struct PMASK
*mask
) {
100 PMASK
*create_pmask (int w
, int h
) {
101 struct PMASK
*maskout
;
103 #ifdef MASK_SINGLE_MEMORY_BLOCK
104 int words
, total_words
;
105 words
= 1 + ((w
-1) >> MASK_WORD_BITBITS
);
106 total_words
= words
* h
;
107 maskout
= (PMASK
*) malloc(
109 MASK_WORD_SIZE
* total_words
);
110 if(!maskout
) return NULL
;
112 maskout
= (PMASK
*) malloc(sizeof(PMASK
));
113 if(!maskout
) return NULL
;
116 init_pmask(maskout
, w
, h
);
118 #ifndef MASK_SINGLE_MEMORY_BLOCK
119 if (!maskout
->mask
) {
120 destroy_pmask(maskout
);
128 void pmask_load_func (struct PMASK
*mask
, int _x
, int _y
, void *surface
, int trans_color
, int (*func
)(void*,int,int))
130 int words
, x
, y
, x2
, w
, h
;
136 words
= 1 + ((w
-1) >> MASK_WORD_BITBITS
);
138 //Now we have to create the bit mask array for the sprite:
139 for(x
=0; x
< words
; x
+=1) {
140 for(y
=0; y
< h
; y
+=1) {
141 MASK_WORD_TYPE m
= 0;
142 for (x2
=MASK_WORD_BITS
-1; x2
>= 0; x2
-=1) {
143 int x3
= (x
<< MASK_WORD_BITBITS
) + x2
+ _x
;
146 if ( func(surface
, x3
, y
+_y
) != trans_color
) {
151 mask
->mask
[y
+x
*h
] = m
;
157 void pmask_load_pixels (struct PMASK
*mask
, void *pixels
, int pitch
, int bytes_per_pixel
, int trans_color
)
159 int words
, x
, y
, x2
, w
, h
;
165 words
= 1 + ((w
-1) >> MASK_WORD_BITBITS
);
167 //Now we have to create the bit mask array for the sprite:
168 for(x
=0; x
< words
; x
+=1) {
169 for(y
=0; y
< h
; y
+=1) {
170 MASK_WORD_TYPE m
= 0;
171 for (x2
=MASK_WORD_BITS
-1; x2
>= 0; x2
-=1) {
172 int x3
= (x
<< MASK_WORD_BITBITS
) + x2
;
175 //beware of endianness!!!!!!!!!!
176 if ( memcmp(((char*)pixels
) + x3
* bytes_per_pixel
+ y
* pitch
, &trans_color
, bytes_per_pixel
) == 0 ) {
181 mask
->mask
[y
+x
*h
] = m
;
188 void init_allegro_pmask(struct PMASK
*mask
, struct BITMAP
*sprite
) {
189 pmask_load_func (mask
, 0, 0, sprite
, bitmap_mask_color(sprite
), (int (*)(void*,int,int))getpixel
);
191 PMASK
*create_allegro_pmask(struct BITMAP
*sprite
) {
193 ret
= create_pmask(sprite
->w
, sprite
->h
);
194 init_allegro_pmask(ret
, sprite
);
200 static int SDL_getpixel(void *_surface
, int x
, int y
)
202 int bpp
= ((SDL_Surface
*)_surface
)->format
->BytesPerPixel
;
203 /* Here p is the address to the pixel we want to retrieve */
204 Uint8
*p
= (Uint8
*)((SDL_Surface
*)_surface
)->pixels
+ y
* ((SDL_Surface
*)_surface
)->pitch
+ x
* bpp
;
214 if(SDL_BYTEORDER
== SDL_BIG_ENDIAN
)
215 return p
[0] << 16 | p
[1] << 8 | p
[2];
217 return p
[0] | p
[1] << 8 | p
[2] << 16;
223 return 0; /* shouldn't happen, but avoids warnings */
226 void init_sdl_pmask(struct PMASK
*mask
, struct SDL_Surface
*sprite
, int trans_color
) {
227 pmask_load_func (mask
, 0, 0, sprite
, trans_color
, SDL_getpixel
);
229 PMASK
*create_sdl_pmask(struct SDL_Surface
*sprite
, int trans_color
) {
231 ret
= create_pmask(sprite
->w
, sprite
->h
);
232 init_sdl_pmask(ret
, sprite
, trans_color
);
238 int check_pmask_collision(struct PMASK
*mask1
, struct PMASK
*mask2
, int x1
, int y1
, int x2
, int y2
)
240 int h1
, h2
, words1
, words2
, max1
, max2
;
241 int dx1
, dx2
, dy1
, dy2
; //We will use this deltas...
242 int py
; //This will store the Y position...
243 int maxh
; //This will store the maximum height...
246 //First we do normal bounding box collision detection...
247 if( !check_bb_collision(mask1
, mask2
, x1
,y1
, x2
,y2
) ) //If there is not bounding box collision...
248 return 0; //return that there is not collision...
250 if (0) { //swap 1 & 2
253 tmp
= x1
; x1
= x2
; x2
= tmp
;//swap x
254 tmp
= y1
; y1
= y2
; y2
= tmp
;//swap y
255 mtmp
= mask1
; mask1
= mask2
; mask2
= mtmp
;//swap masks
258 //First we need to see how much we have to shift the coordinates of the masks...
260 dx1
=0; //don't need to shift mask 1.
261 dx2
=x1
-x2
; //shift mask 2 left. Why left? Because we have the mask 1 being on the right of the mask 2, so we have to move mask 2 to the left to do the proper pixel perfect collision...
263 dx1
=x2
-x1
; //shift mask 1 left.
264 dx2
=0; //don't need to shift mask 2.
268 dy2
=y1
-y2
; //we need to move this many rows up mask 2. Why up? Because we have mask 1 being down of mask 2, so we have to move mask 2 up to do the proper pixel perfect collision detection...
270 dy1
=y2
-y1
; //we need to move this many rows up mask 1.
274 block1
= dx1
>>MASK_WORD_BITBITS
;
275 block2
= dx2
>>MASK_WORD_BITBITS
;
276 dx1
&= MASK_WORD_BITS
-1;
277 dx2
&= MASK_WORD_BITS
-1;
279 //This will calculate the maximum height that we will reach...
280 if(mask1
->h
-dy1
> mask2
->h
-dy2
) {
289 words1
= 1 + ((mask1
->w
-1) >> MASK_WORD_BITBITS
);
290 words2
= 1 + ((mask2
->w
-1) >> MASK_WORD_BITBITS
);
293 block1
= block1
* h1
+ dy1
;
294 block2
= block2
* h2
+ dy2
;
296 while((block1
<max1
) && (block2
<max2
) ) { //search horizantolly in the outer loop
297 for(py
=maxh
;py
>=0;py
--) { //Search vertically
299 (mask1
->mask
[py
+ block1
] >> dx1
) &
300 (mask2
->mask
[py
+ block2
] >> dx2
)
304 //Now we have to move to the next block...
305 //we do blocks twice because of the shift
306 if( (!dx1
) && (!dx2
) ) { //In case both masks are lined up on the x axis...
312 dx1
= MASK_WORD_BITS
- dx2
;
317 dx2
= MASK_WORD_BITS
- dx1
;