JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
ditched the separate shape struct.
[vor.git] / sprite.c
1 #include <stdlib.h>
2 #include "common.h"
3 #include "sprite.h"
4
5 void
6 load_sprite(Sprite *s, char *filename)
7 {
8         s->image = load_image(filename);
9         if(s->image) get_shape(s);
10 }
11
12 void
13 get_shape(Sprite *s)
14 {
15         int x, y;
16         uint16_t *px, transp;
17         uint32_t bits = 0, bit, *p;
18
19         if(s->image->format->BytesPerPixel != 2) {
20                 fprintf(stderr, "get_shape(): not a 16-bit image!\n");
21                 exit(1);
22         }
23
24         s->w = s->image->w; s->h = s->image->h;
25         s->mask_w = ((s->image->w+31)>>5);
26         s->mask = malloc(4*s->mask_w*s->h);
27         if(!s->mask) {
28                 fprintf(stderr, "get_shape(): can't allocate bitmask.\n");
29                 exit(1);
30         }
31
32         SDL_LockSurface(s->image);
33         px = s->image->pixels;
34         transp = s->image->format->colorkey;
35         p = s->mask;
36         for(y=0; y<s->image->h; y++) {
37                 bit = 0;
38                 for(x=0; x<s->image->w; x++) {
39                         if(!bit) { bits = 0; bit = 0x80000000; }
40                         if(*px++ != transp) { bits |= bit; }
41                         bit >>= 1;
42                         if(!bit || x == s->image->w - 1) { *(p++) = bits; }
43                 }
44                 px = (uint16_t *) ((uint8_t *) px + s->image->pitch - 2*s->image->w);
45         }
46         SDL_UnlockSurface(s->image);
47 }
48
49 static int
50 line_collide(int xov, unsigned bit, uint32_t *amask, uint32_t *bmask)
51 {
52         int i, words = (xov-1) >> 5;
53         uint32_t abits;
54
55         for(i=0; i<words; i++) {
56                 abits = *amask++ << bit;
57                 abits |= *amask >> (32-bit);
58                 if(abits & *bmask++) return true;
59         }
60         abits = *amask << bit;
61         if(abits & *bmask) return true;
62
63         return false;
64 }
65
66 static int
67 mask_collide(int xov, int yov, Sprite *a, Sprite *b)
68 {
69         int y;
70         int xoffset = a->w - xov;
71         int word = xoffset >> 5, bit = xoffset & 31;
72         uint32_t *amask = a->mask, *bmask = b->mask;
73
74         if(yov > 0) {
75                 amask = a->mask + ((a->h - yov) * a->mask_w) + word;
76                 bmask = b->mask;
77         } else {
78                 yov = -yov;
79                 amask = a->mask;
80                 bmask = b->mask + ((b->h - yov) * b->mask_w) + word;
81         }
82
83         for(y=0; y<yov; y++) {
84                 if(line_collide(xov, bit, amask, bmask)) return 1;
85                 amask += a->mask_w; bmask += b->mask_w;
86         }
87
88         return 0;
89 }
90
91 int
92 collide(Sprite *a, Sprite *b)
93 {
94         int dx, dy, xov, yov;
95
96         if(b->x < a->x) { Sprite *tmp = a; a = b; b = tmp; }
97
98         dx = b->x - a->x;
99         dy = b->y - a->y;
100
101         xov = max(min(a->w - dx, b->w), 0);
102
103         if(dy >= 0) yov = max(min(a->h - dy, b->h), 0);
104         else yov = -max(min(a->h - -dy, b->h), 0);
105
106         if(xov == 0 || yov == 0) return false;
107         else return mask_collide(xov, yov, a, b);
108 }
109
110 int
111 pixel_collide(Sprite *s, int x, int y)
112 {
113         uint32_t pmask;
114         
115         if(x < s->x || y < s->y || x >= s->x + s->w || y >= s->y + s->h) return 0;
116
117         x -= s->x; y -= s->y;
118         pmask = 0x80000000 >> (x&0x1f);
119         return s->mask[(y*s->mask_w) + (x>>5)] & pmask;
120 }