~ubuntu-branches/ubuntu/maverick/pygame/maverick

« back to all changes in this revision

Viewing changes to src/mask.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2010-01-14 17:02:11 UTC
  • mfrom: (1.3.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20100114170211-21eop2ja7mr9vdcr
Tags: 1.9.1release-0ubuntu1
* New upstream version (lp: #433304)
* debian/control:
  - build-depends on libportmidi-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
 
21
21
*/
22
22
 
 
23
/* a couple of print debugging helpers */
 
24
/*
 
25
#define CALLLOG2(x,y) fprintf(stderr, (x), (y));
 
26
#define CALLLOG(x) fprintf(stderr, (x));
 
27
*/
 
28
 
 
29
#define PYGAMEAPI_MASK_INTERNAL 1
 
30
#include "mask.h"
23
31
#include "pygame.h"
 
32
#include "pgcompat.h"
24
33
#include "pygamedocs.h"
25
34
#include "structmember.h"
26
35
#include "bitmask.h"
27
 
 
28
 
 
29
 
typedef struct {
30
 
  PyObject_HEAD
31
 
  bitmask_t *mask;
32
 
} PyMaskObject;
33
 
 
34
 
staticforward PyTypeObject PyMask_Type;
35
 
#define PyMask_Check(x) ((x)->ob_type == &PyMask_Type)
36
 
#define PyMask_AsBitmap(x) (((PyMaskObject*)x)->mask)
37
 
 
 
36
#include <math.h>
 
37
 
 
38
#ifndef M_PI
 
39
#define M_PI 3.14159265358979323846
 
40
#endif
 
41
 
 
42
static PyTypeObject PyMask_Type;
38
43
 
39
44
/* mask object methods */
40
45
 
124
129
    return PyInt_FromLong(val);
125
130
}
126
131
 
127
 
/*
128
 
def maskFromSurface(surface, threshold = 127):
129
 
    mask = pygame.Mask(surface.get_size())
130
 
    key = surface.get_colorkey()
131
 
    if key:
132
 
        for y in range(surface.get_height()):
133
 
            for x in range(surface.get_width()):
134
 
                if surface.get_at((x+0.1,y+0.1)) != key:
135
 
                    mask.set_at((x,y),1)
136
 
    else:
137
 
        for y in range(surface.get_height()):
138
 
            for x in range (surface.get_width()):
139
 
                if surface.get_at((x,y))[3] > threshold:
140
 
                    mask.set_at((x,y),1)
141
 
    return mask
142
 
*/
143
 
 
144
 
 
145
 
 
 
132
static PyObject* mask_overlap_mask(PyObject* self, PyObject* args)
 
133
{
 
134
    int x, y;
 
135
    bitmask_t *mask = PyMask_AsBitmap(self);
 
136
    bitmask_t *output = bitmask_create(mask->w, mask->h);
 
137
    bitmask_t *othermask;
 
138
    PyObject *maskobj;
 
139
    PyMaskObject *maskobj2 = PyObject_New(PyMaskObject, &PyMask_Type);
 
140
 
 
141
    if(!PyArg_ParseTuple(args, "O!(ii)", &PyMask_Type, &maskobj, &x, &y)) {
 
142
        return NULL;
 
143
    }
 
144
    othermask = PyMask_AsBitmap(maskobj);
 
145
    
 
146
    bitmask_overlap_mask(mask, othermask, output, x, y);
 
147
    
 
148
    if(maskobj2)
 
149
        maskobj2->mask = output;
 
150
 
 
151
    return (PyObject*)maskobj2;
 
152
}
 
153
 
 
154
static PyObject* mask_fill(PyObject* self, PyObject* args)
 
155
{
 
156
    bitmask_t *mask = PyMask_AsBitmap(self);
 
157
    
 
158
    bitmask_fill(mask);
 
159
        
 
160
    Py_RETURN_NONE;
 
161
}
 
162
 
 
163
static PyObject* mask_clear(PyObject* self, PyObject* args)
 
164
{
 
165
    bitmask_t *mask = PyMask_AsBitmap(self);
 
166
    
 
167
    bitmask_clear(mask);
 
168
        
 
169
    Py_RETURN_NONE;
 
170
}
 
171
 
 
172
static PyObject* mask_invert(PyObject* self, PyObject* args)
 
173
{
 
174
    bitmask_t *mask = PyMask_AsBitmap(self);
 
175
    
 
176
    bitmask_invert(mask);
 
177
        
 
178
    Py_RETURN_NONE;
 
179
}
 
180
 
 
181
static PyObject* mask_scale(PyObject* self, PyObject* args)
 
182
{
 
183
    int x, y;
 
184
    bitmask_t *input = PyMask_AsBitmap(self);
 
185
    bitmask_t *output;
 
186
    PyMaskObject *maskobj = PyObject_New(PyMaskObject, &PyMask_Type);
 
187
    
 
188
    if(!PyArg_ParseTuple(args, "(ii)", &x, &y)) {
 
189
        return NULL;
 
190
    }
 
191
 
 
192
    output = bitmask_scale(input, x, y);
 
193
    
 
194
    if(maskobj)
 
195
        maskobj->mask = output;
 
196
 
 
197
    return (PyObject*)maskobj;
 
198
}
 
199
 
 
200
static PyObject* mask_draw(PyObject* self, PyObject* args)
 
201
{
 
202
    bitmask_t *mask = PyMask_AsBitmap(self);
 
203
    bitmask_t *othermask;
 
204
    PyObject *maskobj;
 
205
    int x, y;
 
206
 
 
207
    if(!PyArg_ParseTuple(args, "O!(ii)", &PyMask_Type, &maskobj, &x, &y)) {
 
208
        return NULL;
 
209
    }
 
210
    othermask = PyMask_AsBitmap(maskobj);
 
211
 
 
212
    bitmask_draw(mask, othermask, x, y);
 
213
    
 
214
    Py_RETURN_NONE;
 
215
}
 
216
 
 
217
static PyObject* mask_erase(PyObject* self, PyObject* args)
 
218
{
 
219
    bitmask_t *mask = PyMask_AsBitmap(self);
 
220
    bitmask_t *othermask;
 
221
    PyObject *maskobj;
 
222
    int x, y;
 
223
 
 
224
    if(!PyArg_ParseTuple(args, "O!(ii)", &PyMask_Type, &maskobj, &x, &y)) {
 
225
        return NULL;
 
226
    }
 
227
    othermask = PyMask_AsBitmap(maskobj);
 
228
 
 
229
    bitmask_erase(mask, othermask, x, y);
 
230
    
 
231
    Py_RETURN_NONE;
 
232
}
 
233
 
 
234
static PyObject* mask_count(PyObject* self, PyObject* args)
 
235
{
 
236
    bitmask_t *m = PyMask_AsBitmap(self);
 
237
    
 
238
    return PyInt_FromLong(bitmask_count(m));
 
239
}
 
240
 
 
241
static PyObject* mask_centroid(PyObject* self, PyObject* args)
 
242
{
 
243
    bitmask_t *mask = PyMask_AsBitmap(self);
 
244
    int x, y;
 
245
    long int m10, m01, m00;
 
246
    PyObject *xobj, *yobj;
 
247
 
 
248
    m10 = m01 = m00 = 0;
 
249
    
 
250
    for (x = 0; x < mask->w; x++) {
 
251
        for (y = 0; y < mask->h; y++) {
 
252
            if (bitmask_getbit(mask, x, y)) {
 
253
               m10 += x;
 
254
               m01 += y;
 
255
               m00++;
 
256
            }
 
257
        }
 
258
    }
 
259
    
 
260
    if (m00) {
 
261
        xobj = PyInt_FromLong(m10/m00);
 
262
        yobj = PyInt_FromLong(m01/m00);
 
263
    } else {
 
264
        xobj = PyInt_FromLong(0);
 
265
        yobj = PyInt_FromLong(0);
 
266
    }
 
267
    
 
268
    return Py_BuildValue("(NN)", xobj, yobj);
 
269
}
 
270
 
 
271
static PyObject* mask_angle(PyObject* self, PyObject* args)
 
272
{
 
273
    bitmask_t *mask = PyMask_AsBitmap(self);
 
274
    int x, y, xc, yc;
 
275
    long int m10, m01, m00, m20, m02, m11;
 
276
    double theta;
 
277
 
 
278
    m10 = m01 = m00 = m20 = m02 = m11 = 0;
 
279
    
 
280
    for (x = 0; x < mask->w; x++) {
 
281
        for (y = 0; y < mask->h; y++) {
 
282
            if (bitmask_getbit(mask, x, y)) {
 
283
               m10 += x;
 
284
               m20 += x*x;
 
285
               m11 += x*y;
 
286
               m02 += y*y;
 
287
               m01 += y;
 
288
               m00++;
 
289
            }
 
290
        }
 
291
    }
 
292
    
 
293
    if (m00) {
 
294
        xc = m10/m00;
 
295
        yc = m01/m00;
 
296
        theta = -90.0*atan2(2*(m11/m00 - xc*yc),(m20/m00 - xc*xc)-(m02/m00 - yc*yc))/M_PI;
 
297
        return PyFloat_FromDouble(theta);
 
298
    } else {
 
299
        return PyFloat_FromDouble(0);
 
300
    }
 
301
}
 
302
 
 
303
static PyObject* mask_outline(PyObject* self, PyObject* args)
 
304
{
 
305
    bitmask_t* c = PyMask_AsBitmap(self);
 
306
    bitmask_t* m = bitmask_create(c->w + 2, c->h + 2); 
 
307
    PyObject *plist, *value;
 
308
    int x, y, every, e, firstx, firsty, secx, secy, currx, curry, nextx, nexty, n;
 
309
    int a[14], b[14];
 
310
    a[0] = a[1] = a[7] = a[8] = a[9] = b[1] = b[2] = b[3] = b[9] = b[10] = b[11]= 1;
 
311
    a[2] = a[6] = a[10] = b[4] = b[0] = b[12] = b[8] = 0;
 
312
    a[3] = a[4] = a[5] = a[11] = a[12] = a[13] = b[5] = b[6] = b[7] = b[13] = -1;
 
313
    
 
314
    plist = NULL;
 
315
    plist = PyList_New (0);
 
316
    if (!plist)
 
317
        return NULL;
 
318
        
 
319
    every = 1;
 
320
    n = firstx = firsty = secx = x = 0;
 
321
 
 
322
    if(!PyArg_ParseTuple(args, "|i", &every)) {
 
323
        return NULL;
 
324
    }
 
325
    
 
326
    /* by copying to a new, larger mask, we avoid having to check if we are at
 
327
       a border pixel every time.  */
 
328
    bitmask_draw(m, c, 1, 1);
 
329
    
 
330
    e = every;
 
331
    
 
332
    /* find the first set pixel in the mask */
 
333
    for (y = 1; y < m->h-1; y++) {
 
334
        for (x = 1; x < m->w-1; x++) {
 
335
            if (bitmask_getbit(m, x, y)) {
 
336
                 firstx = x;
 
337
                 firsty = y;
 
338
                 value = Py_BuildValue("(ii)", x-1, y-1);
 
339
                 PyList_Append(plist, value);
 
340
                 Py_DECREF(value);
 
341
                 break;
 
342
            }
 
343
        }
 
344
        if (bitmask_getbit(m, x, y))
 
345
            break;
 
346
    }
 
347
    
 
348
    
 
349
    
 
350
    /* covers the mask having zero pixels or only the final pixel */
 
351
    if ((x == m->w-1) && (y == m->h-1)) {
 
352
        bitmask_free(m);
 
353
        return plist;
 
354
    }        
 
355
    
 
356
    /* check just the first pixel for neighbors */
 
357
    for (n = 0;n < 8;n++) {
 
358
        if (bitmask_getbit(m, x+a[n], y+b[n])) {
 
359
            currx = secx = x+a[n];
 
360
            curry = secy = y+b[n];
 
361
            e--;
 
362
            if (!e) {
 
363
                e = every;
 
364
                value = Py_BuildValue("(ii)", secx-1, secy-1);
 
365
                PyList_Append(plist, value);
 
366
                Py_DECREF(value);
 
367
            }
 
368
            break;
 
369
        }
 
370
    }       
 
371
    
 
372
    /* if there are no neighbors, return */
 
373
    if (!secx) {
 
374
        bitmask_free(m);
 
375
        return plist;
 
376
    }
 
377
 
 
378
    /* the outline tracing loop */
 
379
    for (;;) {
 
380
        /* look around the pixel, it has to have a neighbor */
 
381
        for (n = (n + 6) & 7;;n++) {
 
382
            if (bitmask_getbit(m, currx+a[n], curry+b[n])) {
 
383
                nextx = currx+a[n];
 
384
                nexty = curry+b[n];
 
385
                e--;
 
386
                if (!e) {
 
387
                    e = every;
 
388
                    if ((curry == firsty && currx == firstx) && (secx == nextx && secy == nexty)) {
 
389
                        break;
 
390
                    }
 
391
                    value = Py_BuildValue("(ii)", nextx-1, nexty-1);
 
392
                    PyList_Append(plist, value);
 
393
                    Py_DECREF(value);
 
394
                }
 
395
                break;
 
396
            }
 
397
        }
 
398
        /* if we are back at the first pixel, and the next one will be the
 
399
           second one we visited, we are done */
 
400
        if ((curry == firsty && currx == firstx) && (secx == nextx && secy == nexty)) {
 
401
            break;
 
402
        }
 
403
 
 
404
        curry = nexty;
 
405
        currx = nextx;
 
406
    }
 
407
 
 
408
    bitmask_free(m);
 
409
 
 
410
    return plist;
 
411
}
 
412
 
 
413
static PyObject* mask_convolve(PyObject* aobj, PyObject* args)
 
414
{
 
415
    PyObject *bobj, *oobj = Py_None;
 
416
    bitmask_t    *a,    *b,    *o;
 
417
    int xoffset = 0, yoffset = 0;
 
418
 
 
419
    if (!PyArg_ParseTuple (args, "O!|O(ii)", &PyMask_Type, &bobj, &oobj, &xoffset, &yoffset))
 
420
        return NULL;
 
421
 
 
422
    a = PyMask_AsBitmap(aobj);
 
423
    b = PyMask_AsBitmap(bobj);
 
424
 
 
425
    if (oobj == Py_None) {
 
426
        PyMaskObject *result = PyObject_New(PyMaskObject, &PyMask_Type);
 
427
 
 
428
        result->mask = bitmask_create(a->w + b->w - 1, a->h + b->h - 1);
 
429
        oobj = (PyObject*) result;
 
430
    }
 
431
    else
 
432
        Py_INCREF(oobj);
 
433
 
 
434
    o = PyMask_AsBitmap(oobj);
 
435
 
 
436
    bitmask_convolve(a, b, o, xoffset, yoffset);
 
437
    return oobj;
 
438
}
146
439
 
147
440
static PyObject* mask_from_surface(PyObject* self, PyObject* args)
148
441
{
152
445
    PyObject* surfobj;
153
446
    PyMaskObject *maskobj;
154
447
 
155
 
    int x, y, threshold;
 
448
    int x, y, threshold, ashift, aloss, usethresh;
156
449
    Uint8 *pixels;
157
450
 
158
451
    SDL_PixelFormat *format;
159
 
    Uint32 color;
 
452
    Uint32 color, amask;
160
453
    Uint8 *pix;
161
 
    Uint8 r, g, b, a;
 
454
    Uint8 a;
162
455
 
163
456
    /* set threshold as 127 default argument. */
164
457
    threshold = 127;
176
469
    /* lock the surface, release the GIL. */
177
470
    PySurface_Lock (surfobj);
178
471
 
179
 
 
180
 
 
181
472
    Py_BEGIN_ALLOW_THREADS;
182
473
 
183
 
 
184
 
 
185
474
    /* get the size from the surface, and create the mask. */
186
475
    mask = bitmask_create(surf->w, surf->h);
187
476
 
191
480
         */
192
481
        return NULL; /*RAISE(PyExc_Error, "cannot create bitmask");*/
193
482
    }
194
 
    
195
 
 
196
 
 
197
 
    /* TODO: this is the slow, but easy to code way.  Could make the loop 
198
 
     *         just increment a pointer depending on the format & duff unroll.
199
 
     *         It's faster than in python anyhow.
200
 
     */
 
483
 
201
484
    pixels = (Uint8 *) surf->pixels;
202
485
    format = surf->format;
 
486
    amask = format->Amask;
 
487
    ashift = format->Ashift;
 
488
    aloss = format->Aloss;
 
489
    usethresh = !(surf->flags & SDL_SRCCOLORKEY);
203
490
 
204
491
    for(y=0; y < surf->h; y++) {
 
492
        pixels = (Uint8 *) surf->pixels + y*surf->pitch;
205
493
        for(x=0; x < surf->w; x++) {
206
494
            /* Get the color.  TODO: should use an inline helper 
207
495
             *   function for this common function. */
208
496
            switch (format->BytesPerPixel)
209
497
            {
210
498
                case 1:
211
 
                    color = (Uint32)*((Uint8 *) pixels + y * surf->pitch + x);
 
499
                    color = (Uint32)*((Uint8 *) pixels);
 
500
                    pixels++;
212
501
                    break;
213
502
                case 2:
214
 
                    color = (Uint32)*((Uint16 *) (pixels + y * surf->pitch) + x);
 
503
                    color = (Uint32)*((Uint16 *) pixels);
 
504
                    pixels += 2;
215
505
                    break;
216
506
                case 3:
217
 
                    pix = ((Uint8 *) (pixels + y * surf->pitch) + x * 3);
 
507
                    pix = ((Uint8 *) pixels);
 
508
                    pixels += 3;
218
509
                #if SDL_BYTEORDER == SDL_LIL_ENDIAN
219
510
                    color = (pix[0]) + (pix[1] << 8) + (pix[2] << 16);
220
511
                #else
222
513
                #endif
223
514
                    break;
224
515
                default:                  /* case 4: */
225
 
                    color = *((Uint32 *) (pixels + y * surf->pitch) + x);
 
516
                    color = *((Uint32 *) pixels);
 
517
                    pixels += 4;
226
518
                    break;
227
519
            }
228
520
 
229
521
 
230
 
            if (!(surf->flags & SDL_SRCCOLORKEY)) {
231
 
 
232
 
                SDL_GetRGBA (color, format, &r, &g, &b, &a);
233
 
 
 
522
            if (usethresh) {
 
523
                a = ((color & amask) >> ashift) << aloss;
234
524
                /* no colorkey, so we check the threshold of the alpha */
235
525
                if (a > threshold) {
236
526
                    bitmask_setbit(mask, x, y);
244
534
        }
245
535
    }
246
536
 
247
 
 
248
537
    Py_END_ALLOW_THREADS;
249
538
 
250
539
    /* unlock the surface, release the GIL.
251
540
     */
252
541
    PySurface_Unlock (surfobj);
253
542
 
254
 
    /*create the new python object from mask*/        
 
543
    /*create the new python object from mask*/
255
544
    maskobj = PyObject_New(PyMaskObject, &PyMask_Type);
256
545
    if(maskobj)
257
546
        maskobj->mask = mask;
261
550
}
262
551
 
263
552
 
264
 
 
265
553
/*
266
554
 
267
 
def get_bounding_boxes(surf):
268
 
    """
269
 
    """
270
 
    width, height = surf.get_width(), surf.get_height()
271
 
 
272
 
    regions = []
273
 
 
274
 
    # used pixels is Rects[y][x]
275
 
    used_pixels = []
276
 
    for y in xrange(height):
277
 
        widthones = []
278
 
        for x in xrange(width):
279
 
            widthones.append(None)
280
 
        used_pixels.append(widthones)
281
 
 
282
 
 
283
 
    for y in xrange(height):
284
 
        for x in xrange(width):
285
 
            c = surf.get_at((x, y))
286
 
            # if the pixel has been set.
287
 
            if c[0]:
288
 
                if not used_pixels[y][x]:
289
 
                    used_pixels[y][x] = pygame.Rect(x,y,1,1)
290
 
                    regions.append( used_pixels[y][x] )
291
 
 
292
 
                aregion = used_pixels[y][x] 
293
 
 
294
 
                # check other directions, clockwise.  mark a pixel as used if it is.
295
 
                for dx, dy in [(0,-1), (1,-1), (1,0), (1,1), (0,1), (-1,1), (-1,0), (-1,-1)]:
296
 
                    try:
297
 
                        ax, ay = x+dx, y+dy
298
 
                        if surf.get_at((ax,ay))[0]:
299
 
                            if not used_pixels[ay][ax]:
300
 
                                aregion.union_ip( pygame.Rect(ax,ay, 1, 1) )
301
 
                            used_pixels[ay][ax] = aregion
302
 
                    except:
303
 
                        pass
304
 
 
305
 
 
306
 
    return regions
 
555
palette_colors - this only affects surfaces with a palette 
 
556
    if true we look at the colors from the palette, 
 
557
    otherwise we threshold the pixel values.  This is useful if 
 
558
    the surface is actually greyscale colors, and not palette colors.
 
559
 
307
560
*/
308
561
 
309
 
 
310
 
/* returns an array of regions in regions. */
311
 
 
312
 
static GAME_Rect* get_bounding_rects(bitmask_t *mask, int *num_bounding_boxes) {
313
 
 
314
 
    int x, y, p, i, width, height;
315
 
    GAME_Rect **used_pixels;
316
 
    GAME_Rect *a_used_pixels;
317
 
    GAME_Rect *direction_used_pixels;
318
 
    GAME_Rect *regions;
319
 
 
320
 
    GAME_Rect *aregion, *the_regions;
321
 
    int num_regions;
322
 
    int nx, ny, nh, nw, ay, ax;
323
 
    int directions[8][2];
324
 
 
325
 
 
326
 
    /* for dx, dy in [(0,-1), (1,-1), (1,0), (1,1), (0,1), (-1,1), (-1,0), (-1,-1)]:
327
 
     */
328
 
 
329
 
    directions[0][0] = 0; directions[0][1] = -1;
330
 
    directions[1][0] = 1; directions[1][1] = -1;
331
 
    directions[2][0] = 1; directions[2][1] = 0;
332
 
    directions[3][0] = 1; directions[3][1] = 1;
333
 
    directions[4][0] = 0; directions[4][1] = 1;
334
 
    directions[5][0] = -1; directions[5][1] = 1;
335
 
    directions[6][0] = -1; directions[6][1] = 0;
336
 
    directions[7][0] = -1; directions[7][1] = -1;
337
 
 
338
 
 
339
 
 
340
 
    num_regions = 0;
341
 
 
342
 
    height = mask->h;
343
 
    width = mask->w;
344
 
 
345
 
 
346
 
    /* used_pixels are pointers to rects held in the regions array.  */
347
 
    used_pixels = (GAME_Rect**) malloc(sizeof(GAME_Rect*) * height * width);
348
 
 
349
 
 
350
 
    for(y=0; y < height; y++) {
351
 
        for(x=0; x < width; x++) {
352
 
            /* used_pixels[y][x] = (GAME_Rect*)NULL; */
353
 
            *((GAME_Rect **) (used_pixels + y * width) + x) = NULL;
 
562
void bitmask_threshold (bitmask_t *m, 
 
563
                        SDL_Surface *surf, 
 
564
                        SDL_Surface *surf2,
 
565
                        Uint32 color,  
 
566
                        Uint32 threshold,
 
567
                        int palette_colors)
 
568
{
 
569
    int x, y, rshift, gshift, bshift, rshift2, gshift2, bshift2;
 
570
    int rloss, gloss, bloss, rloss2, gloss2, bloss2;
 
571
    Uint8 *pixels, *pixels2;
 
572
    SDL_PixelFormat *format, *format2;
 
573
    Uint32 the_color, the_color2, rmask, gmask, bmask, rmask2, gmask2, bmask2;
 
574
    Uint8 *pix;
 
575
    Uint8 r, g, b, a;
 
576
    Uint8 tr, tg, tb, ta;
 
577
    int bpp1, bpp2;
 
578
 
 
579
 
 
580
    pixels = (Uint8 *) surf->pixels;
 
581
    format = surf->format;
 
582
    rmask = format->Rmask;
 
583
    gmask = format->Gmask;
 
584
    bmask = format->Bmask;
 
585
    rshift = format->Rshift;
 
586
    gshift = format->Gshift;
 
587
    bshift = format->Bshift;
 
588
    rloss = format->Rloss;
 
589
    gloss = format->Gloss;
 
590
    bloss = format->Bloss;
 
591
    bpp1 = surf->format->BytesPerPixel;
 
592
 
 
593
    if(surf2) {
 
594
        format2 = surf2->format;
 
595
        rmask2 = format2->Rmask;
 
596
        gmask2 = format2->Gmask;
 
597
        bmask2 = format2->Bmask;
 
598
        rshift2 = format2->Rshift;
 
599
        gshift2 = format2->Gshift;
 
600
        bshift2 = format2->Bshift;
 
601
        rloss2 = format2->Rloss;
 
602
        gloss2 = format2->Gloss;
 
603
        bloss2 = format2->Bloss;
 
604
        pixels2 = (Uint8 *) surf2->pixels;
 
605
        bpp2 = surf->format->BytesPerPixel;
 
606
    } else { /* make gcc stop complaining */
 
607
        rmask2 = gmask2 = bmask2 = 0;
 
608
        rshift2 = gshift2 = bshift2 = 0;
 
609
        rloss2 = gloss2 = bloss2 = 0;
 
610
        format2 = NULL;
 
611
        pixels2 = NULL;
 
612
        bpp2 = 0;
 
613
    }
 
614
 
 
615
 
 
616
    SDL_GetRGBA (color, format, &r, &g, &b, &a);
 
617
    SDL_GetRGBA (threshold, format, &tr, &tg, &tb, &ta);
 
618
 
 
619
    for(y=0; y < surf->h; y++) {
 
620
        pixels = (Uint8 *) surf->pixels + y*surf->pitch;
 
621
        if (surf2) {
 
622
            pixels2 = (Uint8 *) surf2->pixels + y*surf2->pitch;
354
623
        }
355
 
    }
356
 
 
357
 
    regions = (GAME_Rect*) malloc(sizeof(GAME_Rect) * height * width);
358
 
 
359
 
    the_regions = regions;
360
 
 
361
 
    for(y=0; y < height; y++) {
362
 
        for(x=0; x < width; x++) {
363
 
            p = bitmask_getbit(mask, x, y);
364
 
 
365
 
            if(p) {
366
 
                /* a_used_pixels is the pointer used_pixels[y][x].  */
367
 
                a_used_pixels = *((GAME_Rect **) (used_pixels + y * width) + x);
368
 
 
369
 
                /*
370
 
                if not used_pixels[y][x]:
371
 
                    used_pixels[y][x] = pygame.Rect(x,y,1,1)
372
 
                    regions.append( used_pixels[y][x] )
373
 
 
374
 
                aregion = used_pixels[y][x] 
375
 
 
 
624
        for(x=0; x < surf->w; x++) {
 
625
            /* the_color = surf->get_at(x,y) */
 
626
            switch (bpp1)
 
627
            {
 
628
            case 1:
 
629
                the_color = (Uint32)*((Uint8 *) pixels);
 
630
                pixels++;
 
631
                break;
 
632
            case 2:
 
633
                the_color = (Uint32)*((Uint16 *) pixels);
 
634
                pixels += 2;
 
635
                break;
 
636
            case 3:
 
637
                pix = ((Uint8 *) pixels);
 
638
                pixels += 3;
 
639
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
 
640
                the_color = (pix[0]) + (pix[1] << 8) + (pix[2] << 16);
 
641
#else
 
642
                the_color = (pix[2]) + (pix[1] << 8) + (pix[0] << 16);
 
643
#endif
 
644
                break;
 
645
            default:                  /* case 4: */
 
646
                the_color = *((Uint32 *) pixels);
 
647
                pixels += 4;
 
648
                break;
 
649
            }
 
650
 
 
651
            if (surf2) {
 
652
                switch (bpp2) {
 
653
                    case 1:
 
654
                        the_color2 = (Uint32)*((Uint8 *) pixels2);
 
655
                        pixels2++;
 
656
                        break;
 
657
                    case 2:
 
658
                        the_color2 = (Uint32)*((Uint16 *) pixels2);
 
659
                        pixels2 += 2;
 
660
                        break;
 
661
                    case 3:
 
662
                        pix = ((Uint8 *) pixels2);
 
663
                        pixels2 += 3;
 
664
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
 
665
                        the_color2 = (pix[0]) + (pix[1] << 8) + (pix[2] << 16);
 
666
#else
 
667
                        the_color2 = (pix[2]) + (pix[1] << 8) + (pix[0] << 16);
 
668
#endif
 
669
                        break;
 
670
                    default:                  /* case 4: */
 
671
                        the_color2 = *((Uint32 *) pixels2);
 
672
                        pixels2 += 4;
 
673
                        break;
 
674
                }
 
675
                /* TODO: will need to handle surfaces with palette colors.
376
676
                */
377
 
                
378
 
 
379
 
                if( !a_used_pixels ) {
380
 
                    /* Add the pixels as a rect on the_regions */
381
 
                    the_regions[num_regions].x = x;
382
 
                    the_regions[num_regions].y = y;
383
 
                    the_regions[num_regions].w = 1;
384
 
                    the_regions[num_regions].h = 1;
385
 
                    a_used_pixels = the_regions + num_regions;
386
 
                    num_regions++;
387
 
 
388
 
                }
389
 
                aregion = a_used_pixels;
390
 
 
391
 
                /* check other directions, clockwise.  mark a pixel as used if it is.  */
392
 
 
393
 
                for(i=0; i < 8; i++) {
394
 
 
395
 
                    ax = directions[i][0] + x;
396
 
                    ay = directions[i][1] + y;
397
 
                    
398
 
                    /* if we are within the bounds of the mask, check it. */
399
 
                    
400
 
                    if(ax >=0 && ax < width && ay < height && ay >= 0) {
401
 
                        
402
 
                        
403
 
                        /* printf("ax, ay: %d,%d\n", ax, ay);
404
 
                        */
405
 
 
406
 
                        if(bitmask_getbit(mask, ax, ay)) {
407
 
                            /*
408
 
                            if not used_pixels[ay][ax]:
409
 
                                aregion.union_ip( pygame.Rect(ax,ay, 1, 1) )
410
 
                            */
411
 
                            direction_used_pixels = *((GAME_Rect **) (used_pixels + ay * width) + ax);
412
 
                            if (!direction_used_pixels) {
413
 
                                nx = MIN (aregion->x, ax);
414
 
                                ny = MIN (aregion->y, ay);
415
 
                                nw = MAX (aregion->x + aregion->w, ax + 1) - nx;
416
 
                                nh = MAX (aregion->y + aregion->h, ay + 1) - ny;
417
 
                                
418
 
                                aregion->x = nx;
419
 
                                aregion->y = ny;
420
 
                                aregion->w = nw;
421
 
                                aregion->h = nh;
422
 
                            }
423
 
                            /* used_pixels[ay][ax] = aregion */
424
 
                            *((GAME_Rect **) (used_pixels + ay * width) + ax) = aregion;
425
 
                        }
426
 
                    }
427
 
 
428
 
                }
429
 
 
430
 
 
431
 
 
432
 
            }
433
 
        }
434
 
    }
435
 
 
436
 
 
437
 
    *num_bounding_boxes = num_regions;
438
 
 
439
 
 
440
 
    free(used_pixels);
441
 
 
442
 
 
443
 
    return regions;
444
 
}
445
 
 
 
677
                if((bpp2 == 1) && (bpp1 == 1) && (!palette_colors)) {
 
678
                    /* Don't look at the color of the surface, just use the
 
679
                       value. This is useful for 8bit images that aren't
 
680
                       actually using the palette.
 
681
                    */
 
682
                    if (  (abs( (the_color2) - (the_color)) < tr )  ) {
 
683
                        
 
684
                        /* this pixel is within the threshold of othersurface. */
 
685
                        bitmask_setbit(m, x, y);
 
686
                    }
 
687
                    
 
688
                } else if ((abs((((the_color2 & rmask2) >> rshift2) << rloss2) - (((the_color & rmask) >> rshift) << rloss)) < tr) &
 
689
                    (abs((((the_color2 & gmask2) >> gshift2) << gloss2) - (((the_color & gmask) >> gshift) << gloss)) < tg) &
 
690
                    (abs((((the_color2 & bmask2) >> bshift2) << bloss2) - (((the_color & bmask) >> bshift) << bloss)) < tb)) {
 
691
                    /* this pixel is within the threshold of othersurface. */
 
692
                    bitmask_setbit(m, x, y);
 
693
                }
 
694
 
 
695
            /* TODO: will need to handle surfaces with palette colors.
 
696
               TODO: will need to handle the case where palette_colors == 0
 
697
            */
 
698
 
 
699
            } else if ((abs((((the_color & rmask) >> rshift) << rloss) - r) < tr) &
 
700
                       (abs((((the_color & gmask) >> gshift) << gloss) - g) < tg) &
 
701
                       (abs((((the_color & bmask) >> bshift) << bloss) - b) < tb)) {
 
702
                /* this pixel is within the threshold of the color. */
 
703
                bitmask_setbit(m, x, y);
 
704
            }
 
705
        }
 
706
    }
 
707
}
 
708
 
 
709
static PyObject* mask_from_threshold(PyObject* self, PyObject* args)
 
710
{
 
711
    PyObject *surfobj, *surfobj2 = NULL;
 
712
    PyMaskObject *maskobj;
 
713
    bitmask_t* m;
 
714
    SDL_Surface* surf = NULL, *surf2 = NULL;
 
715
    int bpp;
 
716
    PyObject *rgba_obj_color, *rgba_obj_threshold = NULL;
 
717
    Uint8 rgba_color[4];
 
718
    Uint8 rgba_threshold[4] = {0, 0, 0, 255};
 
719
    Uint32 color;
 
720
    Uint32 color_threshold;
 
721
    int palette_colors = 1;
 
722
 
 
723
 
 
724
    if (!PyArg_ParseTuple (args, "O!O|OO!i", &PySurface_Type, &surfobj,
 
725
                           &rgba_obj_color,  &rgba_obj_threshold,
 
726
                           &PySurface_Type, &surfobj2, &palette_colors))
 
727
        return NULL;
 
728
 
 
729
    surf = PySurface_AsSurface (surfobj);
 
730
    if(surfobj2) {
 
731
        surf2 = PySurface_AsSurface (surfobj2);
 
732
    }
 
733
 
 
734
    if (PyInt_Check (rgba_obj_color)) {
 
735
        color = (Uint32) PyInt_AsLong (rgba_obj_color);
 
736
    } else if (PyLong_Check (rgba_obj_color)) {
 
737
        color = (Uint32) PyLong_AsUnsignedLong (rgba_obj_color);
 
738
    } else if (RGBAFromColorObj (rgba_obj_color, rgba_color)) {
 
739
        color = SDL_MapRGBA (surf->format, rgba_color[0], rgba_color[1],
 
740
            rgba_color[2], rgba_color[3]);
 
741
    } else {
 
742
        return RAISE (PyExc_TypeError, "invalid color argument");
 
743
    }
 
744
 
 
745
    if(rgba_obj_threshold) {
 
746
        if (PyInt_Check (rgba_obj_threshold))
 
747
            color_threshold = (Uint32) PyInt_AsLong (rgba_obj_threshold);
 
748
        else if (PyLong_Check (rgba_obj_threshold))
 
749
            color_threshold = (Uint32) PyLong_AsUnsignedLong
 
750
                (rgba_obj_threshold);
 
751
        else if (RGBAFromColorObj (rgba_obj_threshold, rgba_threshold))
 
752
            color_threshold = SDL_MapRGBA (surf->format, rgba_threshold[0], rgba_threshold[1], rgba_threshold[2], rgba_threshold[3]);
 
753
        else
 
754
            return RAISE (PyExc_TypeError, "invalid threshold argument");
 
755
    } else {
 
756
        color_threshold = SDL_MapRGBA (surf->format, rgba_threshold[0], rgba_threshold[1], rgba_threshold[2], rgba_threshold[3]);
 
757
    }
 
758
 
 
759
    bpp = surf->format->BytesPerPixel;
 
760
    m = bitmask_create(surf->w, surf->h);
 
761
 
 
762
    PySurface_Lock(surfobj);
 
763
    if(surfobj2) {
 
764
        PySurface_Lock(surfobj2);
 
765
    }
 
766
 
 
767
    Py_BEGIN_ALLOW_THREADS;
 
768
    bitmask_threshold (m, surf, surf2, color, color_threshold, palette_colors);
 
769
    Py_END_ALLOW_THREADS;
 
770
 
 
771
    PySurface_Unlock(surfobj);
 
772
    if(surfobj2) {
 
773
        PySurface_Unlock(surfobj2);
 
774
    }
 
775
 
 
776
    maskobj = PyObject_New(PyMaskObject, &PyMask_Type);
 
777
    if(maskobj)
 
778
        maskobj->mask = m;
 
779
 
 
780
    return (PyObject*)maskobj;
 
781
}
 
782
 
 
783
 
 
784
 
 
785
 
 
786
/* the initial labelling phase of the connected components algorithm
 
787
 
 
788
Returns: The highest label in the labelled image
 
789
 
 
790
input - The input Mask
 
791
image - An array to store labelled pixels
 
792
ufind - The union-find label equivalence array
 
793
largest - An array to store the number of pixels for each label
 
794
 
 
795
*/
 
796
unsigned int cc_label(bitmask_t *input, unsigned int* image, unsigned int* ufind, unsigned int* largest) {
 
797
    unsigned int *buf;
 
798
    unsigned int x, y, w, h, root, aroot, croot, temp, label;
 
799
 
 
800
    label = 0;
 
801
    w = input->w;
 
802
    h = input->h;
 
803
 
 
804
    ufind[0] = 0;
 
805
    buf = image;
 
806
 
 
807
    /* special case for first pixel */
 
808
    if(bitmask_getbit(input, 0, 0)) { /* process for a new connected comp: */
 
809
        label++;              /* create a new label */
 
810
        *buf = label;         /* give the pixel the label */
 
811
        ufind[label] = label; /* put the label in the equivalence array */
 
812
        largest[label] = 1;   /* the label has 1 pixel associated with it */
 
813
    } else {
 
814
        *buf = 0;
 
815
    }
 
816
    buf++;
 
817
 
 
818
 
 
819
 
 
820
    /* special case for first row.
 
821
           Go over the first row except the first pixel.
 
822
    */
 
823
    for(x = 1; x < w; x++) {
 
824
        if (bitmask_getbit(input, x, 0)) {
 
825
            if (*(buf-1)) {                    /* d label */
 
826
                *buf = *(buf-1);
 
827
            } else {                           /* create label */
 
828
                label++;
 
829
                *buf = label;
 
830
                ufind[label] = label;
 
831
                largest[label] = 0;
 
832
            }
 
833
            largest[*buf]++;
 
834
        } else {
 
835
            *buf = 0;
 
836
        }
 
837
        buf++;
 
838
    }
 
839
 
 
840
 
 
841
 
 
842
    /* the rest of the image */
 
843
    for(y = 1; y < h; y++) {
 
844
        /* first pixel of the row */
 
845
        if (bitmask_getbit(input, 0, y)) {
 
846
            if (*(buf-w)) {                    /* b label */
 
847
                *buf = *(buf-w);
 
848
            } else if (*(buf-w+1)) {           /* c label */
 
849
                *buf = *(buf-w+1);
 
850
            } else {                           /* create label */
 
851
                label++;
 
852
                *buf = label;
 
853
                ufind[label] = label;
 
854
                largest[label] = 0;
 
855
            }
 
856
            largest[*buf]++;
 
857
        } else {
 
858
            *buf = 0;
 
859
        }
 
860
        buf++;
 
861
        /* middle pixels of the row */
 
862
        for(x = 1; x < (w-1); x++) {
 
863
            if (bitmask_getbit(input, x, y)) {
 
864
                if (*(buf-w)) {                /* b label */
 
865
                    *buf = *(buf-w);
 
866
                } else if (*(buf-w+1)) {       /* c branch of tree */
 
867
                    if (*(buf-w-1)) {                      /* union(c, a) */
 
868
                        croot = root = *(buf-w+1);
 
869
                        while (ufind[root] < root) {       /* find root */
 
870
                            root = ufind[root];
 
871
                        }
 
872
                        if (croot != *(buf-w-1)) {
 
873
                            temp = aroot = *(buf-w-1);
 
874
                            while (ufind[aroot] < aroot) { /* find root */
 
875
                                aroot = ufind[aroot];
 
876
                            }
 
877
                            if (root > aroot) {
 
878
                                root = aroot;
 
879
                            }
 
880
                            while (ufind[temp] > root) {   /* set root */
 
881
                                aroot = ufind[temp];
 
882
                                ufind[temp] = root;
 
883
                                temp = aroot;
 
884
                            }
 
885
                        }
 
886
                        while (ufind[croot] > root) {      /* set root */
 
887
                            temp = ufind[croot];
 
888
                            ufind[croot] = root;
 
889
                            croot = temp;
 
890
                        }
 
891
                        *buf = root;
 
892
                    } else if (*(buf-1)) {                 /* union(c, d) */
 
893
                        croot = root = *(buf-w+1);
 
894
                        while (ufind[root] < root) {       /* find root */
 
895
                            root = ufind[root];
 
896
                        }
 
897
                        if (croot != *(buf-1)) {
 
898
                            temp = aroot = *(buf-1);
 
899
                            while (ufind[aroot] < aroot) { /* find root */
 
900
                                aroot = ufind[aroot];
 
901
                            }
 
902
                            if (root > aroot) {
 
903
                                root = aroot;
 
904
                            }
 
905
                            while (ufind[temp] > root) {   /* set root */
 
906
                                aroot = ufind[temp];
 
907
                                ufind[temp] = root;
 
908
                                temp = aroot;
 
909
                            }
 
910
                        }
 
911
                        while (ufind[croot] > root) {      /* set root */
 
912
                            temp = ufind[croot];
 
913
                            ufind[croot] = root;
 
914
                            croot = temp;
 
915
                        }
 
916
                        *buf = root;
 
917
                    } else {                   /* c label */
 
918
                        *buf = *(buf-w+1);
 
919
                    }
 
920
                } else if (*(buf-w-1)) {       /* a label */
 
921
                    *buf = *(buf-w-1);
 
922
                } else if (*(buf-1)) {         /* d label */
 
923
                    *buf = *(buf-1);
 
924
                } else {                       /* create label */
 
925
                    label++;
 
926
                    *buf = label;
 
927
                    ufind[label] = label;
 
928
                    largest[label] = 0;
 
929
                }
 
930
                largest[*buf]++;
 
931
            } else {
 
932
                *buf = 0;
 
933
            }
 
934
            buf++;
 
935
        }
 
936
        /* last pixel of the row, if its not also the first pixel of the row */
 
937
        if (w > 1) {
 
938
            if (bitmask_getbit(input, x, y)) {
 
939
                if (*(buf-w)) {                /* b label */
 
940
                    *buf = *(buf-w);
 
941
                } else if (*(buf-w-1)) {       /* a label */
 
942
                    *buf = *(buf-w-1);
 
943
                } else if (*(buf-1)) {         /* d label */
 
944
                    *buf = *(buf-1);
 
945
                } else {                       /* create label */
 
946
                    label++;
 
947
                    *buf = label;
 
948
                    ufind[label] = label;
 
949
                    largest[label] = 0;
 
950
                }
 
951
                largest[*buf]++;
 
952
            } else {
 
953
                *buf = 0;
 
954
            }
 
955
            buf++;
 
956
        }
 
957
    }
 
958
 
 
959
    return label;
 
960
}
 
961
 
 
962
 
 
963
 
 
964
/* Connected component labeling based on the SAUF algorithm by Kesheng Wu,
 
965
   Ekow Otoo, and Kenji Suzuki.  The algorithm is best explained by their paper,
 
966
   "Two Strategies to Speed up Connected Component Labeling Algorithms", but in
 
967
   summary, it is a very efficient two pass method for 8-connected components.
 
968
   It uses a decision tree to minimize the number of neighbors that need to be
 
969
   checked.  It stores equivalence information in an array based union-find.
 
970
   This implementation also has a final step of finding bounding boxes. */
 
971
 
 
972
/*
 
973
returns -2 on memory allocation error, otherwise 0 on success.
 
974
 
 
975
input - the input mask.
 
976
num_bounding_boxes - returns the number of bounding rects found.
 
977
rects - returns the rects that are found.  Allocates the memory for the rects.
 
978
 
 
979
*/
 
980
static int get_bounding_rects(bitmask_t *input, int *num_bounding_boxes, GAME_Rect** ret_rects)
 
981
{
 
982
    unsigned int *image, *ufind, *largest, *buf;
 
983
    int x, y, w, h, temp, label, relabel;
 
984
    GAME_Rect* rects;
 
985
 
 
986
    rects = NULL;
 
987
    label = 0;
 
988
 
 
989
    w = input->w;
 
990
    h = input->h;
 
991
 
 
992
    /* a temporary image to assign labels to each bit of the mask */
 
993
    image = (unsigned int *) malloc(sizeof(int)*w*h);
 
994
    if(!image) { return -2; }
 
995
 
 
996
    /* allocate enough space for the maximum possible connected components */
 
997
    /* the union-find array. see wikipedia for info on union find */
 
998
    ufind = (unsigned int *) malloc(sizeof(int)*(w/2 + 1)*(h/2 + 1));
 
999
    if(!ufind) { return -2; }
 
1000
 
 
1001
    largest = (unsigned int *) malloc(sizeof(int)*(w/2 + 1)*(h/2 + 1));
 
1002
    if(!largest) { return -2; }
 
1003
 
 
1004
 
 
1005
    /* do the initial labelling */
 
1006
    label = cc_label(input, image, ufind, largest);
 
1007
 
 
1008
    relabel = 0;
 
1009
    /* flatten and relabel the union-find equivalence array.  Start at label 1
 
1010
       because label 0 indicates an unset pixel.  For this reason, we also use
 
1011
       <= label rather than < label. */
 
1012
    for (x = 1; x <= label; x++) {
 
1013
         if (ufind[x] < x) {             /* is it a union find root? */
 
1014
             ufind[x] = ufind[ufind[x]]; /* relabel it to its root */
 
1015
         } else {                 /* its a root */
 
1016
             relabel++;
 
1017
             ufind[x] = relabel;  /* assign the lowest label available */
 
1018
         }
 
1019
    }
 
1020
 
 
1021
    *num_bounding_boxes = relabel;
 
1022
 
 
1023
    if (relabel == 0) {
 
1024
    /* early out, as we didn't find anything. */
 
1025
        free(image);
 
1026
        free(ufind);
 
1027
        free(largest);
 
1028
        *ret_rects = rects;
 
1029
        return 0;
 
1030
    }
 
1031
 
 
1032
    /* the bounding rects, need enough space for the number of labels */
 
1033
    rects = (GAME_Rect *) malloc(sizeof(GAME_Rect) * (relabel +1));
 
1034
    if(!rects) { return -2; }
 
1035
 
 
1036
    for (temp = 0; temp <= relabel; temp++) {
 
1037
        rects[temp].h = 0;        /* so we know if its a new rect or not */
 
1038
    }
 
1039
 
 
1040
    /* find the bounding rect of each connected component */
 
1041
    buf = image;
 
1042
    for (y = 0; y < h; y++) {
 
1043
        for (x = 0; x < w; x++) {
 
1044
            if (ufind[*buf]) {         /* if the pixel is part of a component */
 
1045
                if (rects[ufind[*buf]].h) {   /* the component has a rect */
 
1046
                    temp = rects[ufind[*buf]].x;
 
1047
                    rects[ufind[*buf]].x = MIN(x, temp);
 
1048
                    rects[ufind[*buf]].y = MIN(y, rects[ufind[*buf]].y);
 
1049
                    rects[ufind[*buf]].w = MAX(rects[ufind[*buf]].w + temp, x + 1) - rects[ufind[*buf]].x;
 
1050
                    rects[ufind[*buf]].h = MAX(rects[ufind[*buf]].h, y - rects[ufind[*buf]].y + 1);
 
1051
                } else {                      /* otherwise, start the rect */
 
1052
                    rects[ufind[*buf]].x = x;
 
1053
                    rects[ufind[*buf]].y = y;
 
1054
                    rects[ufind[*buf]].w = 1;
 
1055
                    rects[ufind[*buf]].h = 1;
 
1056
                }
 
1057
            }
 
1058
            buf++;
 
1059
        }
 
1060
    }
 
1061
 
 
1062
    free(image);
 
1063
    free(ufind);
 
1064
    free(largest);
 
1065
    *ret_rects = rects;
 
1066
 
 
1067
    return 0;
 
1068
}
446
1069
 
447
1070
static PyObject* mask_get_bounding_rects(PyObject* self, PyObject* args)
448
1071
{
449
1072
    GAME_Rect *regions;
450
1073
    GAME_Rect *aregion;
451
 
    int num_bounding_boxes, i;
 
1074
    int num_bounding_boxes, i, r;
452
1075
    PyObject* ret;
453
 
 
454
1076
    PyObject* rect;
455
1077
 
456
1078
 
457
 
 
458
1079
    bitmask_t *mask = PyMask_AsBitmap(self);
459
1080
 
460
 
 
461
1081
    ret = NULL;
 
1082
    regions = NULL;
 
1083
    aregion = NULL;
 
1084
 
462
1085
    num_bounding_boxes = 0;
463
1086
 
464
 
 
465
 
    if(!PyArg_ParseTuple(args, ""))
466
 
        return NULL;
 
1087
    Py_BEGIN_ALLOW_THREADS;
 
1088
 
 
1089
    r = get_bounding_rects(mask, &num_bounding_boxes, &regions);
 
1090
 
 
1091
    Py_END_ALLOW_THREADS;
 
1092
 
 
1093
 
 
1094
    if(r == -2) {
 
1095
        /* memory out failure */
 
1096
        return RAISE (PyExc_MemoryError, "Not enough memory to get bounding rects. \n");
 
1097
    }
467
1098
 
468
1099
    ret = PyList_New (0);
469
1100
    if (!ret)
470
1101
        return NULL;
471
1102
 
472
 
 
473
 
    Py_BEGIN_ALLOW_THREADS;
474
 
 
475
 
    regions = get_bounding_rects(mask, &num_bounding_boxes);
476
 
 
477
 
    Py_END_ALLOW_THREADS;
478
 
 
479
 
 
480
 
    /* printf("num_bounding_boxes:%d\n", num_bounding_boxes); */
481
 
 
482
 
 
483
 
    /* build a list of rects to return.  */
484
 
    for(i=0; i < num_bounding_boxes; i++) {
 
1103
    /* build a list of rects to return.  Starts at 1 because we never use 0. */
 
1104
    for(i=1; i <= num_bounding_boxes; i++) {
485
1105
        aregion = regions + i;
486
 
        /* printf("aregion x,y,w,h:%d,%d,%d,%d\n", aregion->x, aregion->y, aregion->w, aregion->h);
487
 
        */
488
 
 
489
1106
        rect = PyRect_New4 ( aregion->x, aregion->y, aregion->w, aregion->h );
490
1107
        PyList_Append (ret, rect);
491
1108
        Py_DECREF (rect);
493
1110
 
494
1111
    free(regions);
495
1112
 
496
 
 
497
 
    return ret;
498
 
}
499
 
 
500
 
 
501
 
 
502
 
 
503
 
static PyMethodDef maskobj_builtins[] =
 
1113
    return ret;
 
1114
}
 
1115
 
 
1116
 
 
1117
/*
 
1118
returns the number of connected components.
 
1119
returns -2 on memory allocation error.
 
1120
Allocates memory for components.
 
1121
 
 
1122
*/
 
1123
static int get_connected_components(bitmask_t *mask, bitmask_t ***components, int min)
 
1124
{
 
1125
    unsigned int *image, *ufind, *largest, *buf;
 
1126
    int x, y, w, h, label, relabel;
 
1127
    bitmask_t** comps;
 
1128
 
 
1129
    label = 0;
 
1130
 
 
1131
    w = mask->w;
 
1132
    h = mask->h;
 
1133
 
 
1134
    /* a temporary image to assign labels to each bit of the mask */
 
1135
    image = (unsigned int *) malloc(sizeof(int)*w*h);
 
1136
    if(!image) { return -2; }
 
1137
 
 
1138
    /* allocate enough space for the maximum possible connected components */
 
1139
    /* the union-find array. see wikipedia for info on union find */
 
1140
    ufind = (unsigned int *) malloc(sizeof(int)*(w/2 + 1)*(h/2 + 1));
 
1141
    if(!ufind) { 
 
1142
        free(image);
 
1143
        return -2; 
 
1144
    }
 
1145
 
 
1146
    largest = (unsigned int *) malloc(sizeof(int)*(w/2 + 1)*(h/2 + 1));
 
1147
    if(!largest) { 
 
1148
        free(image);
 
1149
        free(ufind);
 
1150
        return -2; 
 
1151
    }
 
1152
 
 
1153
    /* do the initial labelling */
 
1154
    label = cc_label(mask, image, ufind, largest);
 
1155
 
 
1156
    for (x = 1; x <= label; x++) {
 
1157
        if (ufind[x] < x) {
 
1158
            largest[ufind[x]] += largest[x];
 
1159
        }
 
1160
    }
 
1161
 
 
1162
    relabel = 0;
 
1163
    /* flatten and relabel the union-find equivalence array.  Start at label 1
 
1164
       because label 0 indicates an unset pixel.  For this reason, we also use
 
1165
       <= label rather than < label. */
 
1166
    for (x = 1; x <= label; x++) {
 
1167
        if (ufind[x] < x) {             /* is it a union find root? */
 
1168
            ufind[x] = ufind[ufind[x]]; /* relabel it to its root */
 
1169
        } else {                 /* its a root */
 
1170
            if (largest[x] >= min) {
 
1171
                relabel++;
 
1172
                ufind[x] = relabel;  /* assign the lowest label available */
 
1173
            } else {
 
1174
                ufind[x] = 0;
 
1175
            }
 
1176
        }
 
1177
    }
 
1178
 
 
1179
    if (relabel == 0) {
 
1180
    /* early out, as we didn't find anything. */
 
1181
        free(image);
 
1182
        free(ufind);
 
1183
        free(largest);
 
1184
        return 0;
 
1185
    }
 
1186
 
 
1187
    /* allocate space for the mask array */
 
1188
    comps = (bitmask_t **) malloc(sizeof(bitmask_t *) * (relabel +1));
 
1189
    if(!comps) { 
 
1190
        free(image);
 
1191
        free(ufind);
 
1192
        free(largest);
 
1193
        return -2; 
 
1194
    }
 
1195
 
 
1196
    /* create the empty masks */
 
1197
    for (x = 1; x <= relabel; x++) {
 
1198
        comps[x] = bitmask_create(w, h);
 
1199
    }
 
1200
 
 
1201
    /* set the bits in each mask */
 
1202
    buf = image;
 
1203
    for (y = 0; y < h; y++) {
 
1204
        for (x = 0; x < w; x++) {
 
1205
            if (ufind[*buf]) {         /* if the pixel is part of a component */
 
1206
                bitmask_setbit(comps[ufind[*buf]], x, y);
 
1207
            }
 
1208
            buf++;
 
1209
        }
 
1210
    }
 
1211
 
 
1212
    free(image);
 
1213
    free(ufind);
 
1214
    free(largest);
 
1215
 
 
1216
    *components = comps;
 
1217
 
 
1218
    return relabel;
 
1219
}
 
1220
 
 
1221
static PyObject* mask_connected_components(PyObject* self, PyObject* args)
 
1222
{
 
1223
    PyObject* ret;
 
1224
    PyMaskObject *maskobj;
 
1225
    bitmask_t **components;
 
1226
    bitmask_t *mask = PyMask_AsBitmap(self);
 
1227
    int i, num_components, min;
 
1228
 
 
1229
    min = 0;
 
1230
    components = NULL;
 
1231
 
 
1232
    if(!PyArg_ParseTuple(args, "|i", &min)) {
 
1233
        return NULL;
 
1234
    }
 
1235
 
 
1236
    Py_BEGIN_ALLOW_THREADS;
 
1237
    num_components = get_connected_components(mask, &components, min);
 
1238
    Py_END_ALLOW_THREADS;
 
1239
 
 
1240
    if (num_components == -2)
 
1241
        return RAISE (PyExc_MemoryError, "Not enough memory to get components. \n");
 
1242
 
 
1243
    ret = PyList_New(0);
 
1244
    if (!ret)
 
1245
        return NULL;
 
1246
 
 
1247
    for (i=1; i <= num_components; i++) {
 
1248
        maskobj = PyObject_New(PyMaskObject, &PyMask_Type);
 
1249
        if(maskobj) {
 
1250
            maskobj->mask = components[i];
 
1251
            PyList_Append (ret, (PyObject *) maskobj);
 
1252
            Py_DECREF((PyObject *) maskobj);
 
1253
        }
 
1254
    }
 
1255
 
 
1256
    free(components);
 
1257
    return ret;
 
1258
}
 
1259
 
 
1260
/* Connected component labeling based on the SAUF algorithm by Kesheng Wu,
 
1261
   Ekow Otoo, and Kenji Suzuki.  The algorithm is best explained by their paper,
 
1262
   "Two Strategies to Speed up Connected Component Labeling Algorithms", but in
 
1263
   summary, it is a very efficient two pass method for 8-connected components.
 
1264
   It uses a decision tree to minimize the number of neighbors that need to be
 
1265
   checked.  It stores equivalence information in an array based union-find.
 
1266
   This implementation also tracks the number of pixels in each label, finding
 
1267
   the biggest one while flattening the union-find equivalence array.  It then
 
1268
   writes an output mask containing only the largest connected component. */
 
1269
 
 
1270
 
 
1271
/*
 
1272
returns -2 on memory allocation error.
 
1273
*/
 
1274
static int largest_connected_comp(bitmask_t* input, bitmask_t* output, int ccx, int ccy)
 
1275
{
 
1276
    unsigned int *image, *ufind, *largest, *buf;
 
1277
    unsigned int max, x, y, w, h, label;
 
1278
 
 
1279
    w = input->w;
 
1280
    h = input->h;
 
1281
 
 
1282
    /* a temporary image to assign labels to each bit of the mask */
 
1283
    image = (unsigned int *) malloc(sizeof(int)*w*h);
 
1284
    if(!image) { return -2; }
 
1285
    /* allocate enough space for the maximum possible connected components */
 
1286
    /* the union-find array. see wikipedia for info on union find */
 
1287
    ufind = (unsigned int *) malloc(sizeof(int)*(w/2 + 1)*(h/2 + 1));
 
1288
    if(!ufind) {
 
1289
        free(image);
 
1290
        return -2;
 
1291
    }
 
1292
    /* an array to track the number of pixels associated with each label */
 
1293
    largest = (unsigned int *) malloc(sizeof(int)*(w/2 + 1)*(h/2 + 1));
 
1294
    if(!largest) {
 
1295
        free(image);
 
1296
        free(ufind);
 
1297
        return -2;
 
1298
    }
 
1299
 
 
1300
    /* do the initial labelling */
 
1301
    label = cc_label(input, image, ufind, largest);
 
1302
 
 
1303
    max = 1;
 
1304
    /* flatten the union-find equivalence array */
 
1305
    for (x = 2; x <= label; x++) {
 
1306
         if (ufind[x] != x) {                 /* is it a union find root? */
 
1307
             largest[ufind[x]] += largest[x]; /* add its pixels to its root */
 
1308
             ufind[x] = ufind[ufind[x]];      /* relabel it to its root */
 
1309
         }
 
1310
         if (largest[ufind[x]] > largest[max]) { /* is it the new biggest? */
 
1311
             max = ufind[x];
 
1312
         }
 
1313
    }
 
1314
 
 
1315
    /* write out the final image */
 
1316
    buf = image;
 
1317
    if (ccx >= 0)
 
1318
        max = ufind[*(buf+ccy*w+ccx)];
 
1319
    for (y = 0; y < h; y++) {
 
1320
        for (x = 0; x < w; x++) {
 
1321
            if (ufind[*buf] == max) {         /* if the label is the max one */
 
1322
                bitmask_setbit(output, x, y); /* set the bit in the mask */
 
1323
            }
 
1324
            buf++;
 
1325
        }
 
1326
    }
 
1327
 
 
1328
    free(image);
 
1329
    free(ufind);
 
1330
    free(largest);
 
1331
 
 
1332
    return 0;
 
1333
}
 
1334
 
 
1335
static PyObject* mask_connected_component(PyObject* self, PyObject* args)
 
1336
{
 
1337
    bitmask_t *input = PyMask_AsBitmap(self);
 
1338
    bitmask_t *output = bitmask_create(input->w, input->h);
 
1339
    PyMaskObject *maskobj = PyObject_New(PyMaskObject, &PyMask_Type);
 
1340
    int x, y;
 
1341
 
 
1342
    x = -1;
 
1343
 
 
1344
    if(!PyArg_ParseTuple(args, "|(ii)", &x, &y)) {
 
1345
        return NULL;
 
1346
    }
 
1347
 
 
1348
    /* if a coordinate is specified, make the pixel there is actually set */
 
1349
    if (x == -1 || bitmask_getbit(input, x, y)) {
 
1350
        if (largest_connected_comp(input, output, x, y) == -2) {
 
1351
            return RAISE (PyExc_MemoryError, "Not enough memory to get bounding rects. \n");
 
1352
        }
 
1353
    }
 
1354
 
 
1355
    if(maskobj)
 
1356
        maskobj->mask = output;
 
1357
 
 
1358
    return (PyObject*)maskobj;
 
1359
}
 
1360
 
 
1361
 
 
1362
static PyMethodDef mask_methods[] =
504
1363
{
505
1364
    { "get_size", mask_get_size, METH_VARARGS, DOC_MASKGETSIZE},
506
1365
    { "get_at", mask_get_at, METH_VARARGS, DOC_MASKGETAT },
507
1366
    { "set_at", mask_set_at, METH_VARARGS, DOC_MASKSETAT },
508
1367
    { "overlap", mask_overlap, METH_VARARGS, DOC_MASKOVERLAP },
509
 
    { "overlap_area", mask_overlap_area, METH_VARARGS,
510
 
      DOC_MASKOVERLAPAREA },
511
 
    { "get_bounding_rects", mask_get_bounding_rects, METH_VARARGS,
 
1368
    { "overlap_area", mask_overlap_area, METH_VARARGS, DOC_MASKOVERLAPAREA },
 
1369
    { "overlap_mask", mask_overlap_mask, METH_VARARGS, DOC_MASKOVERLAPMASK },
 
1370
    { "fill", mask_fill, METH_NOARGS, DOC_MASKFILL },
 
1371
    { "clear", mask_clear, METH_NOARGS, DOC_MASKCLEAR },
 
1372
    { "invert", mask_invert, METH_NOARGS, DOC_MASKINVERT },
 
1373
    { "scale", mask_scale, METH_VARARGS, DOC_MASKSCALE },
 
1374
    { "draw", mask_draw, METH_VARARGS, DOC_MASKDRAW },
 
1375
    { "erase", mask_erase, METH_VARARGS, DOC_MASKERASE },
 
1376
    { "count", mask_count, METH_NOARGS, DOC_MASKCOUNT },
 
1377
    { "centroid", mask_centroid, METH_NOARGS, DOC_MASKCENTROID },
 
1378
    { "angle", mask_angle, METH_NOARGS, DOC_MASKANGLE },
 
1379
    { "outline", mask_outline, METH_VARARGS, DOC_MASKOUTLINE },
 
1380
    { "convolve", mask_convolve, METH_VARARGS, DOC_MASKCONVOLVE },
 
1381
    { "connected_component", mask_connected_component, METH_VARARGS,
 
1382
      DOC_MASKCONNECTEDCOMPONENT },
 
1383
    { "connected_components", mask_connected_components, METH_VARARGS,
 
1384
      DOC_MASKCONNECTEDCOMPONENTS },
 
1385
    { "get_bounding_rects", mask_get_bounding_rects, METH_NOARGS,
512
1386
      DOC_MASKGETBOUNDINGRECTS },
513
1387
 
514
1388
    { NULL, NULL, 0, NULL }
526
1400
}
527
1401
 
528
1402
 
529
 
static PyObject* mask_getattr(PyObject* self, char* attrname)
530
 
{
531
 
    return Py_FindMethod(maskobj_builtins, self, attrname);
532
 
}
533
 
 
534
 
 
535
 
static PyTypeObject PyMask_Type = 
536
 
{
537
 
    PyObject_HEAD_INIT(NULL)
538
 
    0,
 
1403
 
 
1404
static PyTypeObject PyMask_Type =
 
1405
{
 
1406
    TYPE_HEAD (NULL, 0)
539
1407
    "pygame.mask.Mask",
540
1408
    sizeof(PyMaskObject),
541
1409
    0,
542
1410
    mask_dealloc,
543
1411
    0,
544
 
    mask_getattr,
 
1412
    0,
545
1413
    0,
546
1414
    0,
547
1415
    0,
548
1416
    0,
549
1417
    NULL,
550
 
    0, 
 
1418
    0,
551
1419
    (hashfunc)NULL,
552
1420
    (ternaryfunc)NULL,
553
1421
    (reprfunc)NULL,
554
1422
    0L,0L,0L,0L,
555
 
    DOC_PYGAMEMASKMASK /* Documentation string */
 
1423
    DOC_PYGAMEMASKMASK,                 /* Documentation string */
 
1424
    0,                                  /* tp_traverse */
 
1425
    0,                                  /* tp_clear */
 
1426
    0,                                  /* tp_richcompare */
 
1427
    0,                                  /* tp_weaklistoffset */
 
1428
    0,                                  /* tp_iter */
 
1429
    0,                                  /* tp_iternext */
 
1430
    mask_methods,                       /* tp_methods */
 
1431
    0,                                  /* tp_members */
 
1432
    0,                                  /* tp_getset */
 
1433
    0,                                  /* tp_base */
 
1434
    0,                                  /* tp_dict */
 
1435
    0,                                  /* tp_descr_get */
 
1436
    0,                                  /* tp_descr_set */
 
1437
    0,                                  /* tp_dictoffset */
 
1438
    0,                                  /* tp_init */
 
1439
    0,                                  /* tp_alloc */
 
1440
    0,                                  /* tp_new */
556
1441
};
557
1442
 
558
1443
 
569
1454
 
570
1455
    if(!mask)
571
1456
      return NULL; /*RAISE(PyExc_Error, "cannot create bitmask");*/
572
 
        
573
 
        /*create the new python object from mask*/        
 
1457
 
 
1458
        /*create the new python object from mask*/
574
1459
    maskobj = PyObject_New(PyMaskObject, &PyMask_Type);
575
1460
    if(maskobj)
576
1461
        maskobj->mask = mask;
579
1464
 
580
1465
 
581
1466
 
582
 
static PyMethodDef mask_builtins[] =
 
1467
static PyMethodDef _mask_methods[] =
583
1468
{
584
1469
    { "Mask", Mask, METH_VARARGS, DOC_PYGAMEMASKMASK },
585
1470
    { "from_surface", mask_from_surface, METH_VARARGS,
586
1471
      DOC_PYGAMEMASKFROMSURFACE},
 
1472
    { "from_threshold", mask_from_threshold, METH_VARARGS,
 
1473
      DOC_PYGAMEMASKFROMTHRESHOLD},
587
1474
    { NULL, NULL, 0, NULL }
588
1475
};
589
1476
 
590
 
void initmask(void)
 
1477
MODINIT_DEFINE (mask)
591
1478
{
592
 
  PyObject *module, *dict;
593
 
  PyType_Init(PyMask_Type);
594
 
  
595
 
  /* create the module */
596
 
  module = Py_InitModule3("mask", mask_builtins, DOC_PYGAMEMASK);
597
 
  dict = PyModule_GetDict(module);
598
 
  PyDict_SetItemString(dict, "MaskType", (PyObject *)&PyMask_Type);
599
 
  import_pygame_base ();
600
 
  import_pygame_surface ();
601
 
  import_pygame_rect ();
 
1479
    PyObject *module, *dict, *apiobj;
 
1480
    static void* c_api[PYGAMEAPI_MASK_NUMSLOTS];
 
1481
 
 
1482
#if PY3
 
1483
    static struct PyModuleDef _module = {
 
1484
        PyModuleDef_HEAD_INIT,
 
1485
        "mask",
 
1486
        DOC_PYGAMEMASK,
 
1487
        -1,
 
1488
        _mask_methods,
 
1489
        NULL, NULL, NULL, NULL
 
1490
    };
 
1491
#endif
 
1492
 
 
1493
    /* imported needed apis; Do this first so if there is an error
 
1494
       the module is not loaded.
 
1495
    */
 
1496
    import_pygame_base ();
 
1497
    if (PyErr_Occurred ()) {
 
1498
        MODINIT_ERROR;
 
1499
    } 
 
1500
    import_pygame_color ();
 
1501
    if (PyErr_Occurred ()) {
 
1502
        MODINIT_ERROR;
 
1503
    }
 
1504
    import_pygame_surface ();
 
1505
    if (PyErr_Occurred ()) {
 
1506
        MODINIT_ERROR;
 
1507
    }
 
1508
    import_pygame_rect ();
 
1509
    if (PyErr_Occurred ()) {
 
1510
        MODINIT_ERROR;
 
1511
    }
 
1512
 
 
1513
    /* create the mask type */
 
1514
    if (PyType_Ready (&PyMask_Type) < 0) {
 
1515
        MODINIT_ERROR;
 
1516
    }
 
1517
 
 
1518
    /* create the module */
 
1519
#if PY3
 
1520
    module = PyModule_Create (&_module);
 
1521
#else
 
1522
    module = Py_InitModule3(MODPREFIX "mask", _mask_methods, DOC_PYGAMEMASK);
 
1523
#endif
 
1524
    if (module == NULL) {
 
1525
        MODINIT_ERROR;
 
1526
    }
 
1527
    dict = PyModule_GetDict(module);
 
1528
    if (PyDict_SetItemString (dict, "MaskType",
 
1529
                              (PyObject *)&PyMask_Type) == -1) {
 
1530
        DECREF_MOD(module);
 
1531
        MODINIT_ERROR;
 
1532
    }
 
1533
    /* export the c api */
 
1534
    c_api[0] = &PyMask_Type;
 
1535
    apiobj = PyCObject_FromVoidPtr (c_api, NULL);
 
1536
    if (apiobj == NULL) {
 
1537
        DECREF_MOD (module);
 
1538
        MODINIT_ERROR;
 
1539
    }
 
1540
    if (PyModule_AddObject (module, PYGAMEAPI_LOCAL_ENTRY, apiobj) == -1) {
 
1541
        Py_DECREF (apiobj);
 
1542
        DECREF_MOD (module);
 
1543
        MODINIT_ERROR;
 
1544
    }
 
1545
    MODINIT_RETURN (module);
602
1546
}
603
1547