1 /*
2 Copyright (C) 2002-2007 Ulf Ekstrom except for the bitcount function.
3 This wrapper code was originally written by Danny van Bruggen(?) for
4 the SCAM library, it was then converted by Ulf Ekstrom to wrap the
5 bitmask library, a spinoff from SCAM.
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public
18 License along with this library; if not, write to the Free
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
21 */
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"
31
32 #include "pygame.h"
33
34 #include "pgcompat.h"
35
36 #include "doc/mask_doc.h"
37
38 #include "structmember.h"
39
40 #include <math.h>
41
42 #ifndef M_PI
43 #define M_PI 3.14159265358979323846
44 #endif
45
46 /* Macro to create mask objects. This will call the type's tp_new and tp_init.
47 * Params:
48 * w: width of mask
49 * h: height of mask
50 * f: fill, 1 is used to set all the bits (to 1) and 0 is used to clear
51 * all the bits (to 0)
52 */
53 #define CREATE_MASK_OBJ(w, h, f) \
54 (pgMaskObject *)PyObject_CallFunction((PyObject *)&pgMask_Type, "(ii)i", \
55 (w), (h), (f))
56
57 /* Prototypes */
58 static PyTypeObject pgMask_Type;
59 static PG_INLINE pgMaskObject *
60 create_mask_using_bitmask(bitmask_t *bitmask);
61 static PG_INLINE pgMaskObject *
62 create_mask_using_bitmask_and_type(bitmask_t *bitmask, PyTypeObject *ob_type);
63
64 /********** mask helper functions **********/
65
66 /* Calculate the absolute difference between 2 Uint32s. */
67 static PG_INLINE Uint32
abs_diff_uint32(Uint32 a,Uint32 b)68 abs_diff_uint32(Uint32 a, Uint32 b)
69 {
70 return (a > b) ? a - b : b - a;
71 }
72
73 /********** mask object methods **********/
74
75 /* Copies the given mask. */
76 static PyObject *
mask_copy(PyObject * self,PyObject * args)77 mask_copy(PyObject *self, PyObject *args)
78 {
79 bitmask_t *new_bitmask = bitmask_copy(pgMask_AsBitmap(self));
80
81 if (NULL == new_bitmask) {
82 return RAISE(PyExc_MemoryError, "cannot allocate memory for bitmask");
83 }
84
85 return (PyObject *)create_mask_using_bitmask_and_type(new_bitmask,
86 self->ob_type);
87 }
88
89 /* Redirects mask.copy() to mask.__copy__(). This is done to allow
90 * subclasses that override the __copy__() method to also override the copy()
91 * method automatically. */
92 static PyObject *
mask_call_copy(PyObject * self,PyObject * args)93 mask_call_copy(PyObject *self, PyObject *args)
94 {
95 return PyObject_CallMethodObjArgs(self, Text_FromUTF8("__copy__"), args);
96 }
97
98 static PyObject *
mask_get_size(PyObject * self,PyObject * args)99 mask_get_size(PyObject *self, PyObject *args)
100 {
101 bitmask_t *mask = pgMask_AsBitmap(self);
102
103 if (!PyArg_ParseTuple(args, ""))
104 return NULL;
105
106 return Py_BuildValue("(ii)", mask->w, mask->h);
107 }
108
109 /* Creates a Rect object based on the given mask's size. The rect's
110 * attributes can be altered via the kwargs.
111 *
112 * Returns:
113 * Rect object or NULL to indicate a fail
114 *
115 * Ref: src_c/surface.c surf_get_rect()
116 */
117 static PyObject *
mask_get_rect(PyObject * self,PyObject * args,PyObject * kwargs)118 mask_get_rect(PyObject *self, PyObject *args, PyObject *kwargs)
119 {
120 PyObject *rect = NULL;
121 bitmask_t *bitmask = pgMask_AsBitmap(self);
122
123 if (0 != PyTuple_GET_SIZE(args)) {
124 return RAISE(PyExc_TypeError,
125 "get_rect only supports keyword arguments");
126 }
127
128 rect = pgRect_New4(0, 0, bitmask->w, bitmask->h);
129
130 if (NULL == rect) {
131 return RAISE(PyExc_MemoryError, "cannot allocate memory for rect");
132 }
133
134 if (NULL != kwargs) {
135 PyObject *key = NULL, *value = NULL;
136 Py_ssize_t pos = 0;
137
138 while (PyDict_Next(kwargs, &pos, &key, &value)) {
139 if ((-1 == PyObject_SetAttr(rect, key, value))) {
140 Py_DECREF(rect);
141 return NULL;
142 }
143 }
144 }
145
146 return rect;
147 }
148
149 static PyObject *
mask_get_at(PyObject * self,PyObject * args,PyObject * kwargs)150 mask_get_at(PyObject *self, PyObject *args, PyObject *kwargs)
151 {
152 bitmask_t *mask = pgMask_AsBitmap(self);
153 int x, y, val;
154 PyObject* pos = NULL;
155 static char *keywords[] = {"pos", NULL};
156
157 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", keywords, &pos))
158 return NULL;
159
160 if (!pg_TwoIntsFromObj(pos, &x, &y)) {
161 return RAISE(PyExc_TypeError, "pos must be two numbers");
162 }
163
164 if (x >= 0 && x < mask->w && y >= 0 && y < mask->h) {
165 val = bitmask_getbit(mask, x, y);
166 }
167 else {
168 PyErr_Format(PyExc_IndexError, "%d, %d is out of bounds", x, y);
169 return NULL;
170 }
171
172 return PyInt_FromLong(val);
173 }
174
175 static PyObject *
mask_set_at(PyObject * self,PyObject * args,PyObject * kwargs)176 mask_set_at(PyObject *self, PyObject *args, PyObject *kwargs)
177 {
178 bitmask_t *mask = pgMask_AsBitmap(self);
179 int x, y, value = 1;
180 PyObject* pos = NULL;
181 static char *keywords[] = {"pos", "value", NULL};
182
183 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i", keywords, &pos, &value))
184 return NULL;
185
186 if (!pg_TwoIntsFromObj(pos, &x, &y)) {
187 return RAISE(PyExc_TypeError, "pos must be two numbers");
188 }
189
190 if (x >= 0 && x < mask->w && y >= 0 && y < mask->h) {
191 if (value) {
192 bitmask_setbit(mask, x, y);
193 }
194 else {
195 bitmask_clearbit(mask, x, y);
196 }
197 }
198 else {
199 PyErr_Format(PyExc_IndexError, "%d, %d is out of bounds", x, y);
200 return NULL;
201 }
202 Py_INCREF(Py_None);
203 return Py_None;
204 }
205
206 static PyObject *
mask_overlap(PyObject * self,PyObject * args,PyObject * kwargs)207 mask_overlap(PyObject *self, PyObject *args, PyObject *kwargs)
208 {
209 bitmask_t *mask = pgMask_AsBitmap(self);
210 bitmask_t *othermask;
211 PyObject *maskobj;
212 int x, y, val;
213 int xp, yp;
214 PyObject* offset = NULL;
215 static char *keywords[] = {"other", "offset", NULL};
216
217 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O", keywords, &pgMask_Type, &maskobj, &offset))
218 return NULL;
219
220 othermask = pgMask_AsBitmap(maskobj);
221
222 if (!pg_TwoIntsFromObj(offset, &x, &y)) {
223 return RAISE(PyExc_TypeError, "offset must be two numbers");
224 }
225
226 val = bitmask_overlap_pos(mask, othermask, x, y, &xp, &yp);
227 if (val) {
228 return Py_BuildValue("(ii)", xp, yp);
229 }
230 else {
231 Py_INCREF(Py_None);
232 return Py_None;
233 }
234 }
235
236 static PyObject *
mask_overlap_area(PyObject * self,PyObject * args,PyObject * kwargs)237 mask_overlap_area(PyObject *self, PyObject *args, PyObject *kwargs)
238 {
239 bitmask_t *mask = pgMask_AsBitmap(self);
240 bitmask_t *othermask;
241 PyObject *maskobj;
242 int x, y, val;
243 PyObject* offset = NULL;
244 static char *keywords[] = {"other", "offset", NULL};
245
246 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O", keywords, &pgMask_Type, &maskobj, &offset)) {
247 return NULL;
248 }
249
250 othermask = pgMask_AsBitmap(maskobj);
251
252 if (!pg_TwoIntsFromObj(offset, &x, &y)) {
253 return RAISE(PyExc_TypeError, "offset must be two numbers");
254 }
255
256 val = bitmask_overlap_area(mask, othermask, x, y);
257 return PyInt_FromLong(val);
258 }
259
260 static PyObject *
mask_overlap_mask(PyObject * self,PyObject * args,PyObject * kwargs)261 mask_overlap_mask(PyObject *self, PyObject *args, PyObject *kwargs)
262 {
263 int x, y;
264 bitmask_t *bitmask = pgMask_AsBitmap(self);
265 PyObject *maskobj = NULL;
266 pgMaskObject *output_maskobj = NULL;
267 PyObject* offset = NULL;
268 static char *keywords[] = {"other", "offset", NULL};
269
270 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O", keywords, &pgMask_Type, &maskobj, &offset)) {
271 return NULL; /* Exception already set. */
272 }
273
274 output_maskobj = CREATE_MASK_OBJ(bitmask->w, bitmask->h, 0);
275
276 if (!pg_TwoIntsFromObj(offset, &x, &y)) {
277 return RAISE(PyExc_TypeError, "offset must be two numbers");
278 }
279
280 if (NULL == output_maskobj) {
281 return NULL; /* Exception already set. */
282 }
283
284 bitmask_overlap_mask(bitmask, pgMask_AsBitmap(maskobj),
285 output_maskobj->mask, x, y);
286
287 return (PyObject *)output_maskobj;
288 }
289
290 static PyObject *
mask_fill(PyObject * self,PyObject * args)291 mask_fill(PyObject *self, PyObject *args)
292 {
293 bitmask_t *mask = pgMask_AsBitmap(self);
294
295 bitmask_fill(mask);
296
297 Py_RETURN_NONE;
298 }
299
300 static PyObject *
mask_clear(PyObject * self,PyObject * args)301 mask_clear(PyObject *self, PyObject *args)
302 {
303 bitmask_t *mask = pgMask_AsBitmap(self);
304
305 bitmask_clear(mask);
306
307 Py_RETURN_NONE;
308 }
309
310 static PyObject *
mask_invert(PyObject * self,PyObject * args)311 mask_invert(PyObject *self, PyObject *args)
312 {
313 bitmask_t *mask = pgMask_AsBitmap(self);
314
315 bitmask_invert(mask);
316
317 Py_RETURN_NONE;
318 }
319
320 static PyObject *
mask_scale(PyObject * self,PyObject * args,PyObject * kwargs)321 mask_scale(PyObject *self, PyObject *args, PyObject *kwargs)
322 {
323 int x, y;
324 bitmask_t *bitmask = NULL;
325 PyObject* scale = NULL;
326 static char *keywords[] = {"scale", NULL};
327
328 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", keywords, &scale)) {
329 return NULL; /* Exception already set. */
330 }
331
332 if (!pg_TwoIntsFromObj(scale, &x, &y)) {
333 return RAISE(PyExc_TypeError, "scale must be two numbers");
334 }
335
336 if (x < 0 || y < 0) {
337 return RAISE(PyExc_ValueError, "cannot scale mask to negative size");
338 }
339
340 bitmask = bitmask_scale(pgMask_AsBitmap(self), x, y);
341
342 if (NULL == bitmask) {
343 return RAISE(PyExc_MemoryError, "cannot allocate memory for bitmask");
344 }
345
346 return (PyObject *)create_mask_using_bitmask(bitmask);
347 }
348
349 static PyObject *
mask_draw(PyObject * self,PyObject * args,PyObject * kwargs)350 mask_draw(PyObject *self, PyObject *args, PyObject *kwargs)
351 {
352 bitmask_t *mask = pgMask_AsBitmap(self);
353 bitmask_t *othermask;
354 PyObject *maskobj;
355 int x, y;
356 PyObject* offset = NULL;
357 static char *keywords[] = {"other", "offset", NULL};
358
359 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O", keywords, &pgMask_Type, &maskobj, &offset)) {
360 return NULL;
361 }
362
363 if (!pg_TwoIntsFromObj(offset, &x, &y)) {
364 return RAISE(PyExc_TypeError, "offset must be two numbers");
365 }
366
367 othermask = pgMask_AsBitmap(maskobj);
368
369 bitmask_draw(mask, othermask, x, y);
370
371 Py_RETURN_NONE;
372 }
373
374 static PyObject *
mask_erase(PyObject * self,PyObject * args,PyObject * kwargs)375 mask_erase(PyObject *self, PyObject *args, PyObject *kwargs)
376 {
377 bitmask_t *mask = pgMask_AsBitmap(self);
378 bitmask_t *othermask;
379 PyObject *maskobj;
380 int x, y;
381 PyObject* offset = NULL;
382 static char *keywords[] = {"other", "offset", NULL};
383
384 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O", keywords, &pgMask_Type, &maskobj, &offset)) {
385 return NULL;
386 }
387
388 if (!pg_TwoIntsFromObj(offset, &x, &y)) {
389 return RAISE(PyExc_TypeError, "offset must be two numbers");
390 }
391
392 othermask = pgMask_AsBitmap(maskobj);
393
394 bitmask_erase(mask, othermask, x, y);
395
396 Py_RETURN_NONE;
397 }
398
399 static PyObject *
mask_count(PyObject * self,PyObject * args)400 mask_count(PyObject *self, PyObject *args)
401 {
402 bitmask_t *m = pgMask_AsBitmap(self);
403
404 return PyInt_FromLong(bitmask_count(m));
405 }
406
407 static PyObject *
mask_centroid(PyObject * self,PyObject * args)408 mask_centroid(PyObject *self, PyObject *args)
409 {
410 bitmask_t *mask = pgMask_AsBitmap(self);
411 int x, y;
412 long int m10, m01, m00;
413 PyObject *xobj, *yobj;
414
415 m10 = m01 = m00 = 0;
416
417 for (x = 0; x < mask->w; x++) {
418 for (y = 0; y < mask->h; y++) {
419 if (bitmask_getbit(mask, x, y)) {
420 m10 += x;
421 m01 += y;
422 m00++;
423 }
424 }
425 }
426
427 if (m00) {
428 xobj = PyInt_FromLong(m10 / m00);
429 yobj = PyInt_FromLong(m01 / m00);
430 }
431 else {
432 xobj = PyInt_FromLong(0);
433 yobj = PyInt_FromLong(0);
434 }
435
436 return Py_BuildValue("(NN)", xobj, yobj);
437 }
438
439 static PyObject *
mask_angle(PyObject * self,PyObject * args)440 mask_angle(PyObject *self, PyObject *args)
441 {
442 bitmask_t *mask = pgMask_AsBitmap(self);
443 int x, y;
444 long int m10, m01, m00, m20, m02, m11;
445
446 m10 = m01 = m00 = m20 = m02 = m11 = 0;
447
448 for (x = 0; x < mask->w; x++) {
449 for (y = 0; y < mask->h; y++) {
450 if (bitmask_getbit(mask, x, y)) {
451 m10 += x;
452 m20 += (long)x * x;
453 m11 += (long)x * y;
454 m02 += (long)y * y;
455 m01 += y;
456 m00++;
457 }
458 }
459 }
460
461 if (m00) {
462 int xc = m10 / m00;
463 int yc = m01 / m00;
464 double theta = -90.0 *
465 atan2(2 * (m11 / m00 - (long)xc * yc),
466 (m20 / m00 - (long)xc * xc) - (m02 / m00 - (long)yc * yc)) /
467 M_PI;
468 return PyFloat_FromDouble(theta);
469 }
470 else {
471 return PyFloat_FromDouble(0);
472 }
473 }
474
475 static PyObject *
mask_outline(PyObject * self,PyObject * args,PyObject * kwargs)476 mask_outline(PyObject *self, PyObject *args, PyObject *kwargs)
477 {
478 bitmask_t *c = pgMask_AsBitmap(self);
479 bitmask_t *m = NULL;
480 PyObject *plist = NULL;
481 PyObject *value = NULL;
482 int x, y, firstx, firsty, secx, secy, currx, curry, nextx, nexty, n;
483 int e, every = 1;
484 int a[] = {1, 1, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, -1, -1};
485 int b[] = {0, 1, 1, 1, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1};
486 static char *keywords[] = {"every", NULL};
487
488 n = firstx = firsty = secx = x = 0;
489
490 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", keywords, &every)) {
491 return NULL;
492 }
493
494 plist = PyList_New(0);
495 if (!plist) {
496 return RAISE(PyExc_MemoryError,
497 "outline cannot allocate memory for list");
498 }
499
500 if (!c->w || !c->h) {
501 return plist;
502 }
503
504 /* Copying to a larger mask to avoid border checking. */
505 m = bitmask_create(c->w + 2, c->h + 2);
506 if (!m) {
507 Py_DECREF(plist);
508 return RAISE(PyExc_MemoryError,
509 "outline cannot allocate memory for mask");
510 }
511
512 bitmask_draw(m, c, 1, 1);
513
514 /* find the first set pixel in the mask */
515 for (y = 1; y < m->h - 1; y++) {
516 for (x = 1; x < m->w - 1; x++) {
517 if (bitmask_getbit(m, x, y)) {
518 firstx = x;
519 firsty = y;
520 value = Py_BuildValue("(ii)", x - 1, y - 1);
521
522 if (NULL == value) {
523 Py_DECREF(plist);
524 bitmask_free(m);
525
526 return NULL; /* Exception already set. */
527 }
528
529 if (0 != PyList_Append(plist, value)) {
530 Py_DECREF(value);
531 Py_DECREF(plist);
532 bitmask_free(m);
533
534 return NULL; /* Exception already set. */
535 }
536
537 Py_DECREF(value);
538 break;
539 }
540 }
541 if (bitmask_getbit(m, x, y))
542 break;
543 }
544
545 /* covers the mask having zero pixels set or only the final pixel */
546 if ((x == m->w - 1) && (y == m->h - 1)) {
547 bitmask_free(m);
548 return plist;
549 }
550
551 e = every;
552
553 /* check just the first pixel for neighbors */
554 for (n = 0; n < 8; n++) {
555 if (bitmask_getbit(m, x + a[n], y + b[n])) {
556 currx = secx = x + a[n];
557 curry = secy = y + b[n];
558 e--;
559 if (!e) {
560 e = every;
561 value = Py_BuildValue("(ii)", secx - 1, secy - 1);
562
563 if (NULL == value) {
564 Py_DECREF(plist);
565 bitmask_free(m);
566
567 return NULL; /* Exception already set. */
568 }
569
570 if (0 != PyList_Append(plist, value)) {
571 Py_DECREF(value);
572 Py_DECREF(plist);
573 bitmask_free(m);
574
575 return NULL; /* Exception already set. */
576 }
577
578 Py_DECREF(value);
579 }
580 break;
581 }
582 }
583
584 /* if there are no neighbors, return */
585 if (!secx) {
586 bitmask_free(m);
587 return plist;
588 }
589
590 /* the outline tracing loop */
591 for (;;) {
592 /* look around the pixel, it has to have a neighbor */
593 for (n = (n + 6) & 7;; n++) {
594 if (bitmask_getbit(m, currx + a[n], curry + b[n])) {
595 nextx = currx + a[n];
596 nexty = curry + b[n];
597 e--;
598 if (!e) {
599 e = every;
600 if ((curry == firsty && currx == firstx) &&
601 (secx == nextx && secy == nexty)) {
602 break;
603 }
604
605 value = Py_BuildValue("(ii)", nextx - 1, nexty - 1);
606
607 if (NULL == value) {
608 Py_DECREF(plist);
609 bitmask_free(m);
610
611 return NULL; /* Exception already set. */
612 }
613
614 if (0 != PyList_Append(plist, value)) {
615 Py_DECREF(value);
616 Py_DECREF(plist);
617 bitmask_free(m);
618
619 return NULL; /* Exception already set. */
620 }
621
622 Py_DECREF(value);
623 }
624 break;
625 }
626 }
627 /* if we are back at the first pixel, and the next one will be the
628 second one we visited, we are done */
629 if ((curry == firsty && currx == firstx) &&
630 (secx == nextx && secy == nexty)) {
631 break;
632 }
633
634 curry = nexty;
635 currx = nextx;
636 }
637
638 bitmask_free(m);
639
640 return plist;
641 }
642
643 static PyObject *
mask_convolve(PyObject * aobj,PyObject * args,PyObject * kwargs)644 mask_convolve(PyObject *aobj, PyObject *args, PyObject *kwargs)
645 {
646 PyObject *bobj = NULL;
647 PyObject *oobj = Py_None;
648 bitmask_t *a = NULL, *b = NULL;
649 int xoffset = 0, yoffset = 0;
650 PyObject* offset = NULL;
651 static char *keywords[] = {"other", "output", "offset", NULL};
652
653 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|OO", keywords, &pgMask_Type, &bobj, &oobj,
654 &offset)) {
655 return NULL; /* Exception already set. */
656 }
657
658 if (offset && !pg_TwoIntsFromObj(offset, &xoffset, &yoffset)) {
659 return RAISE(PyExc_TypeError, "offset must be two numbers");
660 }
661
662 a = pgMask_AsBitmap(aobj);
663 b = pgMask_AsBitmap(bobj);
664
665 if (oobj != Py_None) {
666 /* Use this mask for the output. */
667 Py_INCREF(oobj);
668 }
669 else {
670 pgMaskObject *maskobj = CREATE_MASK_OBJ(MAX(0, a->w + b->w - 1),
671 MAX(0, a->h + b->h - 1), 0);
672
673 if (NULL == maskobj) {
674 return NULL; /* Exception already set. */
675 }
676
677 oobj = (PyObject *)maskobj;
678 }
679
680 bitmask_convolve(a, b, pgMask_AsBitmap(oobj), xoffset, yoffset);
681
682 return oobj;
683 }
684
685 /* Gets the color of a given pixel.
686 *
687 * Params:
688 * pixel: pixel to get the color of
689 * bpp: bytes per pixel
690 *
691 * Returns:
692 * pixel color
693 */
694 static PG_INLINE Uint32
get_pixel_color(Uint8 * pixel,Uint8 bpp)695 get_pixel_color(Uint8 *pixel, Uint8 bpp)
696 {
697 switch (bpp) {
698 case 1:
699 return *((Uint8 *)pixel);
700
701 case 2:
702 return *((Uint16 *)pixel);
703
704 case 3:
705 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
706 return (pixel[0]) + (pixel[1] << 8) + (pixel[2] << 16);
707 #else /* SDL_BIG_ENDIAN */
708 return (pixel[2]) + (pixel[1] << 8) + (pixel[0] << 16);
709 #endif /* SDL_BIG_ENDIAN */
710
711 default: /* case 4: */
712 return *((Uint32 *)pixel);
713 }
714 }
715
716 /* Sets the color of a given pixel.
717 *
718 * Params:
719 * pixel: pixel to set the color of
720 * bpp: bytes per pixel
721 * color: color to set
722 *
723 * Ref: src_c/draw.c set_pixel_32()
724 */
725 static void
set_pixel_color(Uint8 * pixel,Uint8 bpp,Uint32 color)726 set_pixel_color(Uint8 *pixel, Uint8 bpp, Uint32 color)
727 {
728 switch (bpp) {
729 case 1:
730 *pixel = color;
731 break;
732
733 case 2:
734 *(Uint16 *)pixel = color;
735 break;
736
737 case 3:
738 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
739 *(Uint16 *)pixel = color;
740 pixel[2] = color >> 16;
741 #else /* != SDL_LIL_ENDIAN */
742 pixel[2] = color;
743 pixel[1] = color >> 8;
744 pixel[0] = color >> 16;
745 #endif /* SDL_LIL_ENDIAN */
746 break;
747
748 default: /* case 4: */
749 *(Uint32 *)pixel = color;
750 break;
751 }
752 }
753
754 /* For each surface pixel's alpha that is greater than the threshold,
755 * the corresponding bitmask bit is set.
756 *
757 * Params:
758 * surf: surface
759 * bitmask: bitmask to alter
760 * threshold: threshold used check surface pixels (alpha) against
761 *
762 * Returns:
763 * void
764 */
765 static void
set_from_threshold(SDL_Surface * surf,bitmask_t * bitmask,int threshold)766 set_from_threshold(SDL_Surface *surf, bitmask_t *bitmask, int threshold)
767 {
768 SDL_PixelFormat *format = surf->format;
769 Uint8 bpp = format->BytesPerPixel;
770 Uint8 *pixel = NULL;
771 Uint8 rgba[4];
772 int x, y;
773
774 for (y = 0; y < surf->h; ++y) {
775 pixel = (Uint8 *)surf->pixels + y * surf->pitch;
776
777 for (x = 0; x < surf->w; ++x, pixel += bpp) {
778 SDL_GetRGBA(get_pixel_color(pixel, bpp), format, rgba, rgba + 1,
779 rgba + 2, rgba + 3);
780 if (rgba[3] > threshold) {
781 bitmask_setbit(bitmask, x, y);
782 }
783 }
784 }
785 }
786
787 /* For each surface pixel's color that is not equal to the colorkey, the
788 * corresponding bitmask bit is set.
789 *
790 * Params:
791 * surf: surface
792 * bitmask: bitmask to alter
793 * colorkey: color used to check surface pixels against
794 *
795 * Returns:
796 * void
797 */
798 static void
set_from_colorkey(SDL_Surface * surf,bitmask_t * bitmask,Uint32 colorkey)799 set_from_colorkey(SDL_Surface *surf, bitmask_t *bitmask, Uint32 colorkey)
800 {
801 Uint8 bpp = surf->format->BytesPerPixel;
802 Uint8 *pixel = NULL;
803 int x, y;
804
805 for (y = 0; y < surf->h; ++y) {
806 pixel = (Uint8 *)surf->pixels + y * surf->pitch;
807
808 for (x = 0; x < surf->w; ++x, pixel += bpp) {
809 if (get_pixel_color(pixel, bpp) != colorkey) {
810 bitmask_setbit(bitmask, x, y);
811 }
812 }
813 }
814 }
815
816 /* Creates a mask from a given surface.
817 *
818 * Returns:
819 * Mask object or NULL to indicate a fail
820 */
821 static PyObject *
mask_from_surface(PyObject * self,PyObject * args,PyObject * kwargs)822 mask_from_surface(PyObject *self, PyObject *args, PyObject *kwargs)
823 {
824 SDL_Surface *surf = NULL;
825 pgSurfaceObject *surfobj = NULL;
826 pgMaskObject *maskobj = NULL;
827 Uint32 colorkey;
828 int threshold = 127; /* default value */
829 int use_thresh = 1;
830 static char *keywords[] = {"surface", "threshold", NULL};
831
832 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|i", keywords, &pgSurface_Type, &surfobj,
833 &threshold)) {
834 return NULL; /* Exception already set. */
835 }
836
837 surf = pgSurface_AsSurface(surfobj);
838
839 if (surf->w < 0 || surf->h < 0) {
840 return RAISE(PyExc_ValueError,
841 "cannot create mask with negative size");
842 }
843
844 maskobj = CREATE_MASK_OBJ(surf->w, surf->h, 0);
845
846 if (NULL == maskobj) {
847 return NULL; /* Exception already set. */
848 }
849
850 if (surf->w == 0 || surf->h == 0) {
851 /* Nothing left to do for 0 sized surfaces. */
852 return (PyObject *)maskobj;
853 }
854
855 if (!pgSurface_Lock(surfobj)) {
856 Py_DECREF((PyObject *)maskobj);
857 return RAISE(PyExc_RuntimeError, "cannot lock surface");
858 }
859
860 Py_BEGIN_ALLOW_THREADS; /* Release the GIL. */
861
862 use_thresh = (SDL_GetColorKey(surf, &colorkey) == -1);
863
864 if (use_thresh) {
865 set_from_threshold(surf, maskobj->mask, threshold);
866 }
867 else {
868 set_from_colorkey(surf, maskobj->mask, colorkey);
869 }
870
871 Py_END_ALLOW_THREADS; /* Obtain the GIL. */
872
873 if (!pgSurface_Unlock(surfobj)) {
874 Py_DECREF((PyObject *)maskobj);
875 return RAISE(PyExc_RuntimeError, "cannot unlock surface");
876 }
877
878 return (PyObject *)maskobj;
879 }
880
881 /*
882
883 palette_colors - this only affects surfaces with a palette
884 if true we look at the colors from the palette,
885 otherwise we threshold the pixel values. This is useful if
886 the surface is actually greyscale colors, and not palette colors.
887
888 */
889
890 void
bitmask_threshold(bitmask_t * m,SDL_Surface * surf,SDL_Surface * surf2,Uint32 color,Uint32 threshold,int palette_colors)891 bitmask_threshold(bitmask_t *m, SDL_Surface *surf, SDL_Surface *surf2,
892 Uint32 color, Uint32 threshold, int palette_colors)
893 {
894 int x, y, rshift, gshift, bshift, rshift2, gshift2, bshift2;
895 int rloss, gloss, bloss, rloss2, gloss2, bloss2;
896 Uint8 *pixels, *pixels2;
897 SDL_PixelFormat *format, *format2;
898 Uint32 the_color, the_color2, rmask, gmask, bmask, rmask2, gmask2, bmask2;
899 Uint8 *pix;
900 Uint8 r, g, b, a;
901 Uint8 tr, tg, tb, ta;
902 int bpp1, bpp2;
903
904 format = surf->format;
905 rmask = format->Rmask;
906 gmask = format->Gmask;
907 bmask = format->Bmask;
908 rshift = format->Rshift;
909 gshift = format->Gshift;
910 bshift = format->Bshift;
911 rloss = format->Rloss;
912 gloss = format->Gloss;
913 bloss = format->Bloss;
914 bpp1 = surf->format->BytesPerPixel;
915
916 if (surf2) {
917 format2 = surf2->format;
918 rmask2 = format2->Rmask;
919 gmask2 = format2->Gmask;
920 bmask2 = format2->Bmask;
921 rshift2 = format2->Rshift;
922 gshift2 = format2->Gshift;
923 bshift2 = format2->Bshift;
924 rloss2 = format2->Rloss;
925 gloss2 = format2->Gloss;
926 bloss2 = format2->Bloss;
927 pixels2 = (Uint8 *)surf2->pixels;
928 bpp2 = surf->format->BytesPerPixel;
929 }
930 else { /* make gcc stop complaining */
931 rmask2 = gmask2 = bmask2 = 0;
932 rshift2 = gshift2 = bshift2 = 0;
933 rloss2 = gloss2 = bloss2 = 0;
934 format2 = NULL;
935 pixels2 = NULL;
936 bpp2 = 0;
937 }
938
939 SDL_GetRGBA(color, format, &r, &g, &b, &a);
940 SDL_GetRGBA(threshold, format, &tr, &tg, &tb, &ta);
941
942 for (y = 0; y < surf->h; y++) {
943 pixels = (Uint8 *)surf->pixels + y * surf->pitch;
944 if (surf2) {
945 pixels2 = (Uint8 *)surf2->pixels + y * surf2->pitch;
946 }
947 for (x = 0; x < surf->w; x++) {
948 /* the_color = surf->get_at(x,y) */
949 switch (bpp1) {
950 case 1:
951 the_color = (Uint32) * ((Uint8 *)pixels);
952 pixels++;
953 break;
954 case 2:
955 the_color = (Uint32) * ((Uint16 *)pixels);
956 pixels += 2;
957 break;
958 case 3:
959 pix = ((Uint8 *)pixels);
960 pixels += 3;
961 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
962 the_color = (pix[0]) + (pix[1] << 8) + (pix[2] << 16);
963 #else
964 the_color = (pix[2]) + (pix[1] << 8) + (pix[0] << 16);
965 #endif
966 break;
967 default: /* case 4: */
968 the_color = *((Uint32 *)pixels);
969 pixels += 4;
970 break;
971 }
972
973 if (surf2) {
974 switch (bpp2) {
975 case 1:
976 the_color2 = (Uint32) * ((Uint8 *)pixels2);
977 pixels2++;
978 break;
979 case 2:
980 the_color2 = (Uint32) * ((Uint16 *)pixels2);
981 pixels2 += 2;
982 break;
983 case 3:
984 pix = ((Uint8 *)pixels2);
985 pixels2 += 3;
986 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
987 the_color2 = (pix[0]) + (pix[1] << 8) + (pix[2] << 16);
988 #else
989 the_color2 = (pix[2]) + (pix[1] << 8) + (pix[0] << 16);
990 #endif
991 break;
992 default: /* case 4: */
993 the_color2 = *((Uint32 *)pixels2);
994 pixels2 += 4;
995 break;
996 }
997 /* TODO: will need to handle surfaces with palette colors.
998 */
999 if ((bpp2 == 1) && (bpp1 == 1) && (!palette_colors)) {
1000 /* Don't look at the color of the surface, just use the
1001 value. This is useful for 8bit images that aren't
1002 actually using the palette.
1003 */
1004 if (abs_diff_uint32(the_color2, the_color) < tr) {
1005 /* this pixel is within the threshold of othersurface.
1006 */
1007 bitmask_setbit(m, x, y);
1008 }
1009 }
1010 else if ((abs_diff_uint32(
1011 (((the_color2 & rmask2) >> rshift2) << rloss2),
1012 (((the_color & rmask) >> rshift) << rloss)) <
1013 tr) &&
1014 (abs_diff_uint32(
1015 (((the_color2 & gmask2) >> gshift2) << gloss2),
1016 (((the_color & gmask) >> gshift) << gloss)) <
1017 tg) &&
1018 (abs_diff_uint32(
1019 (((the_color2 & bmask2) >> bshift2) << bloss2),
1020 (((the_color & bmask) >> bshift) << bloss)) <
1021 tb)) {
1022 /* this pixel is within the threshold of othersurface. */
1023 bitmask_setbit(m, x, y);
1024 }
1025
1026 /* TODO: will need to handle surfaces with palette colors.
1027 TODO: will need to handle the case where palette_colors == 0
1028 */
1029 }
1030 else if ((abs_diff_uint32(
1031 (((the_color & rmask) >> rshift) << rloss), r) <
1032 tr) &&
1033 (abs_diff_uint32(
1034 (((the_color & gmask) >> gshift) << gloss), g) <
1035 tg) &&
1036 (abs_diff_uint32(
1037 (((the_color & bmask) >> bshift) << bloss), b) <
1038 tb)) {
1039 /* this pixel is within the threshold of the color. */
1040 bitmask_setbit(m, x, y);
1041 }
1042 }
1043 }
1044 }
1045
1046 static PyObject *
mask_from_threshold(PyObject * self,PyObject * args,PyObject * kwargs)1047 mask_from_threshold(PyObject *self, PyObject *args, PyObject *kwargs)
1048 {
1049 pgSurfaceObject *surfobj = NULL;
1050 pgSurfaceObject *surfobj2 = NULL;
1051 pgMaskObject *maskobj = NULL;
1052 SDL_Surface *surf = NULL, *surf2 = NULL;
1053 PyObject *rgba_obj_color, *rgba_obj_threshold = NULL;
1054 Uint8 rgba_color[4];
1055 Uint8 rgba_threshold[4] = {0, 0, 0, 255};
1056 Uint32 color;
1057 Uint32 color_threshold;
1058 int palette_colors = 1;
1059 static char* keywords[] = {"surface", "color", "threshold", "othersurface",
1060 "palette_colors", NULL};
1061
1062 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O|OO!i", keywords, &pgSurface_Type,
1063 &surfobj, &rgba_obj_color, &rgba_obj_threshold,
1064 &pgSurface_Type, &surfobj2, &palette_colors))
1065 return NULL;
1066
1067 surf = pgSurface_AsSurface(surfobj);
1068 if (surfobj2) {
1069 surf2 = pgSurface_AsSurface(surfobj2);
1070 }
1071
1072 if (PyInt_Check(rgba_obj_color)) {
1073 color = (Uint32)PyInt_AsLong(rgba_obj_color);
1074 }
1075 else if (PyLong_Check(rgba_obj_color)) {
1076 color = (Uint32)PyLong_AsUnsignedLong(rgba_obj_color);
1077 }
1078 else if (pg_RGBAFromColorObj(rgba_obj_color, rgba_color)) {
1079 color = SDL_MapRGBA(surf->format, rgba_color[0], rgba_color[1],
1080 rgba_color[2], rgba_color[3]);
1081 }
1082 else {
1083 return RAISE(PyExc_TypeError, "invalid color argument");
1084 }
1085
1086 if (rgba_obj_threshold) {
1087 if (PyInt_Check(rgba_obj_threshold))
1088 color_threshold = (Uint32)PyInt_AsLong(rgba_obj_threshold);
1089 else if (PyLong_Check(rgba_obj_threshold))
1090 color_threshold =
1091 (Uint32)PyLong_AsUnsignedLong(rgba_obj_threshold);
1092 else if (pg_RGBAFromColorObj(rgba_obj_threshold, rgba_threshold))
1093 color_threshold =
1094 SDL_MapRGBA(surf->format, rgba_threshold[0], rgba_threshold[1],
1095 rgba_threshold[2], rgba_threshold[3]);
1096 else
1097 return RAISE(PyExc_TypeError, "invalid threshold argument");
1098 }
1099 else {
1100 color_threshold =
1101 SDL_MapRGBA(surf->format, rgba_threshold[0], rgba_threshold[1],
1102 rgba_threshold[2], rgba_threshold[3]);
1103 }
1104
1105 maskobj = CREATE_MASK_OBJ(surf->w, surf->h, 0);
1106
1107 if (NULL == maskobj) {
1108 return NULL; /* Exception already set. */
1109 }
1110
1111 pgSurface_Lock(surfobj);
1112 if (surfobj2) {
1113 pgSurface_Lock(surfobj2);
1114 }
1115
1116 Py_BEGIN_ALLOW_THREADS;
1117 bitmask_threshold(maskobj->mask, surf, surf2, color, color_threshold,
1118 palette_colors);
1119 Py_END_ALLOW_THREADS;
1120
1121 pgSurface_Unlock(surfobj);
1122 if (surfobj2) {
1123 pgSurface_Unlock(surfobj2);
1124 }
1125
1126 return (PyObject *)maskobj;
1127 }
1128
1129 /* The initial labelling phase of the connected components algorithm.
1130 *
1131 * Connected component labeling based on the SAUF algorithm by Kesheng Wu,
1132 * Ekow Otoo, and Kenji Suzuki. The algorithm is best explained by their
1133 * paper, "Two Strategies to Speed up Connected Component Labeling Algorithms",
1134 * but in summary, it is a very efficient two pass method for 8-connected
1135 * components. It uses a decision tree to minimize the number of neighbors that
1136 * need to be checked. It stores equivalence information in an array based
1137 * union-find.
1138 *
1139 * Params:
1140 * input - the input mask
1141 * image - an array to store labelled pixels
1142 * ufind - the union-find label equivalence array
1143 * largest - an array to store the number of pixels for each label
1144 *
1145 * Returns:
1146 * the highest label in the labelled image
1147 */
1148 unsigned int
cc_label(bitmask_t * input,unsigned int * image,unsigned int * ufind,unsigned int * largest)1149 cc_label(bitmask_t *input, unsigned int *image, unsigned int *ufind,
1150 unsigned int *largest)
1151 {
1152 unsigned int *buf;
1153 unsigned int x, y, w, h, root, aroot, croot, temp, label;
1154
1155 label = 0;
1156 w = input->w;
1157 h = input->h;
1158
1159 ufind[0] = 0;
1160 buf = image;
1161
1162 /* special case for first pixel */
1163 if (bitmask_getbit(input, 0, 0)) { /* process for a new connected comp: */
1164 label++; /* create a new label */
1165 *buf = label; /* give the pixel the label */
1166 ufind[label] = label; /* put the label in the equivalence array */
1167 largest[label] = 1; /* the label has 1 pixel associated with it */
1168 }
1169 else {
1170 *buf = 0;
1171 }
1172 buf++;
1173
1174 /* special case for first row.
1175 Go over the first row except the first pixel.
1176 */
1177 for (x = 1; x < w; x++) {
1178 if (bitmask_getbit(input, x, 0)) {
1179 if (*(buf - 1)) { /* d label */
1180 *buf = *(buf - 1);
1181 }
1182 else { /* create label */
1183 label++;
1184 *buf = label;
1185 ufind[label] = label;
1186 largest[label] = 0;
1187 }
1188 largest[*buf]++;
1189 }
1190 else {
1191 *buf = 0;
1192 }
1193 buf++;
1194 }
1195
1196 /* the rest of the image */
1197 for (y = 1; y < h; y++) {
1198 /* first pixel of the row */
1199 if (bitmask_getbit(input, 0, y)) {
1200 if (*(buf - w)) { /* b label */
1201 *buf = *(buf - w);
1202 }
1203 else if (*(buf - w + 1)) { /* c label */
1204 *buf = *(buf - w + 1);
1205 }
1206 else { /* create label */
1207 label++;
1208 *buf = label;
1209 ufind[label] = label;
1210 largest[label] = 0;
1211 }
1212 largest[*buf]++;
1213 }
1214 else {
1215 *buf = 0;
1216 }
1217 buf++;
1218 /* middle pixels of the row */
1219 for (x = 1; x < (w - 1); x++) {
1220 if (bitmask_getbit(input, x, y)) {
1221 if (*(buf - w)) { /* b label */
1222 *buf = *(buf - w);
1223 }
1224 else if (*(buf - w + 1)) { /* c branch of tree */
1225 if (*(buf - w - 1)) { /* union(c, a) */
1226 croot = root = *(buf - w + 1);
1227 while (ufind[root] < root) { /* find root */
1228 root = ufind[root];
1229 }
1230 if (croot != *(buf - w - 1)) {
1231 temp = aroot = *(buf - w - 1);
1232 while (ufind[aroot] < aroot) { /* find root */
1233 aroot = ufind[aroot];
1234 }
1235 if (root > aroot) {
1236 root = aroot;
1237 }
1238 while (ufind[temp] > root) { /* set root */
1239 aroot = ufind[temp];
1240 ufind[temp] = root;
1241 temp = aroot;
1242 }
1243 }
1244 while (ufind[croot] > root) { /* set root */
1245 temp = ufind[croot];
1246 ufind[croot] = root;
1247 croot = temp;
1248 }
1249 *buf = root;
1250 }
1251 else if (*(buf - 1)) { /* union(c, d) */
1252 croot = root = *(buf - w + 1);
1253 while (ufind[root] < root) { /* find root */
1254 root = ufind[root];
1255 }
1256 if (croot != *(buf - 1)) {
1257 temp = aroot = *(buf - 1);
1258 while (ufind[aroot] < aroot) { /* find root */
1259 aroot = ufind[aroot];
1260 }
1261 if (root > aroot) {
1262 root = aroot;
1263 }
1264 while (ufind[temp] > root) { /* set root */
1265 aroot = ufind[temp];
1266 ufind[temp] = root;
1267 temp = aroot;
1268 }
1269 }
1270 while (ufind[croot] > root) { /* set root */
1271 temp = ufind[croot];
1272 ufind[croot] = root;
1273 croot = temp;
1274 }
1275 *buf = root;
1276 }
1277 else { /* c label */
1278 *buf = *(buf - w + 1);
1279 }
1280 }
1281 else if (*(buf - w - 1)) { /* a label */
1282 *buf = *(buf - w - 1);
1283 }
1284 else if (*(buf - 1)) { /* d label */
1285 *buf = *(buf - 1);
1286 }
1287 else { /* create label */
1288 label++;
1289 *buf = label;
1290 ufind[label] = label;
1291 largest[label] = 0;
1292 }
1293 largest[*buf]++;
1294 }
1295 else {
1296 *buf = 0;
1297 }
1298 buf++;
1299 }
1300 /* last pixel of the row, if its not also the first pixel of the row */
1301 if (w > 1) {
1302 if (bitmask_getbit(input, x, y)) {
1303 if (*(buf - w)) { /* b label */
1304 *buf = *(buf - w);
1305 }
1306 else if (*(buf - w - 1)) { /* a label */
1307 *buf = *(buf - w - 1);
1308 }
1309 else if (*(buf - 1)) { /* d label */
1310 *buf = *(buf - 1);
1311 }
1312 else { /* create label */
1313 label++;
1314 *buf = label;
1315 ufind[label] = label;
1316 largest[label] = 0;
1317 }
1318 largest[*buf]++;
1319 }
1320 else {
1321 *buf = 0;
1322 }
1323 buf++;
1324 }
1325 }
1326
1327 return label;
1328 }
1329
1330 /* Creates a bounding rect for each connected component in the given mask.
1331 *
1332 * Allocates memory for rects.
1333 *
1334 * NOTE: Caller is responsible for freeing the "ret_rects" memory.
1335 *
1336 * Params:
1337 * input - mask to search in for the connected components to bound
1338 * num_bounding_boxes - passes back the number of bounding rects found
1339 * ret_rects - passes back the bounding rects that are found with the first
1340 * rect at index 1, memory is allocated
1341 *
1342 * Returns:
1343 * 0 on success
1344 * -2 on memory allocation error
1345 */
1346 static int
get_bounding_rects(bitmask_t * input,int * num_bounding_boxes,GAME_Rect ** ret_rects)1347 get_bounding_rects(bitmask_t *input, int *num_bounding_boxes,
1348 GAME_Rect **ret_rects)
1349 {
1350 unsigned int *image, *ufind, *largest, *buf;
1351 unsigned int x_uf, label = 0;
1352 int x, y, w, h, temp, relabel;
1353 GAME_Rect *rects;
1354
1355 rects = NULL;
1356
1357 w = input->w;
1358 h = input->h;
1359
1360 if (!w || !h) {
1361 *ret_rects = rects;
1362 return 0;
1363 }
1364 /* a temporary image to assign labels to each bit of the mask */
1365 image = (unsigned int *)malloc(sizeof(int) * w * h);
1366 if (!image) {
1367 return -2;
1368 }
1369
1370 /* allocate enough space for the maximum possible connected components */
1371 /* the union-find array. see wikipedia for info on union find */
1372 ufind = (unsigned int *)malloc(sizeof(int) * (w / 2 + 1) * (h / 2 + 1));
1373 if (!ufind) {
1374 free(image);
1375 return -2;
1376 }
1377
1378 largest = (unsigned int *)malloc(sizeof(int) * (w / 2 + 1) * (h / 2 + 1));
1379 if (!largest) {
1380 free(image);
1381 free(ufind);
1382 return -2;
1383 }
1384
1385 /* do the initial labelling */
1386 label = cc_label(input, image, ufind, largest);
1387
1388 relabel = 0;
1389 /* flatten and relabel the union-find equivalence array. Start at label 1
1390 because label 0 indicates an unset pixel. For this reason, we also use
1391 <= label rather than < label. */
1392 for (x_uf = 1; x_uf <= label; ++x_uf) {
1393 if (ufind[x_uf] < x_uf) { /* is it a union find root? */
1394 ufind[x_uf] = ufind[ufind[x_uf]]; /* relabel it to its root */
1395 }
1396 else { /* its a root */
1397 relabel++;
1398 ufind[x_uf] = relabel; /* assign the lowest label available */
1399 }
1400 }
1401
1402 *num_bounding_boxes = relabel;
1403
1404 if (relabel == 0) {
1405 /* early out, as we didn't find anything. */
1406 free(image);
1407 free(ufind);
1408 free(largest);
1409 *ret_rects = rects;
1410 return 0;
1411 }
1412
1413 /* the bounding rects, need enough space for the number of labels */
1414 rects = (GAME_Rect *)malloc(sizeof(GAME_Rect) * (relabel + 1));
1415 if (!rects) {
1416 free(image);
1417 free(ufind);
1418 free(largest);
1419 return -2;
1420 }
1421
1422 for (temp = 0; temp <= relabel; temp++) {
1423 rects[temp].h = 0; /* so we know if its a new rect or not */
1424 }
1425
1426 /* find the bounding rect of each connected component */
1427 buf = image;
1428 for (y = 0; y < h; y++) {
1429 for (x = 0; x < w; x++) {
1430 if (ufind[*buf]) { /* if the pixel is part of a component */
1431 if (rects[ufind[*buf]].h) { /* the component has a rect */
1432 temp = rects[ufind[*buf]].x;
1433 rects[ufind[*buf]].x = MIN(x, temp);
1434 rects[ufind[*buf]].y = MIN(y, rects[ufind[*buf]].y);
1435 rects[ufind[*buf]].w =
1436 MAX(rects[ufind[*buf]].w + temp, x + 1) -
1437 rects[ufind[*buf]].x;
1438 rects[ufind[*buf]].h = MAX(rects[ufind[*buf]].h,
1439 y - rects[ufind[*buf]].y + 1);
1440 }
1441 else { /* otherwise, start the rect */
1442 rects[ufind[*buf]].x = x;
1443 rects[ufind[*buf]].y = y;
1444 rects[ufind[*buf]].w = 1;
1445 rects[ufind[*buf]].h = 1;
1446 }
1447 }
1448 buf++;
1449 }
1450 }
1451
1452 free(image);
1453 free(ufind);
1454 free(largest);
1455 *ret_rects = rects;
1456
1457 return 0;
1458 }
1459
1460 static PyObject *
mask_get_bounding_rects(PyObject * self,PyObject * args)1461 mask_get_bounding_rects(PyObject *self, PyObject *args)
1462 {
1463 GAME_Rect *regions;
1464 GAME_Rect *aregion;
1465 int num_bounding_boxes, i, r;
1466 PyObject *rect_list;
1467 PyObject *rect;
1468
1469 bitmask_t *mask = pgMask_AsBitmap(self);
1470
1471 rect_list = NULL;
1472 regions = NULL;
1473 aregion = NULL;
1474
1475 num_bounding_boxes = 0;
1476
1477 Py_BEGIN_ALLOW_THREADS;
1478
1479 r = get_bounding_rects(mask, &num_bounding_boxes, ®ions);
1480
1481 Py_END_ALLOW_THREADS;
1482
1483 if (r == -2) {
1484 /* memory out failure */
1485 return RAISE(PyExc_MemoryError,
1486 "Not enough memory to get bounding rects. \n");
1487 }
1488
1489 rect_list = PyList_New(0);
1490
1491 if (!rect_list) {
1492 free(regions);
1493
1494 return NULL; /* Exception already set. */
1495 }
1496
1497 /* build a list of rects to return. Starts at 1 because we never use 0. */
1498 for (i = 1; i <= num_bounding_boxes; i++) {
1499 aregion = regions + i;
1500 rect = pgRect_New4(aregion->x, aregion->y, aregion->w, aregion->h);
1501
1502 if (NULL == rect) {
1503 Py_DECREF(rect_list);
1504 free(regions);
1505
1506 return RAISE(PyExc_MemoryError,
1507 "cannot allocate memory for bounding rects");
1508 }
1509
1510 if (0 != PyList_Append(rect_list, rect)) {
1511 Py_DECREF(rect);
1512 Py_DECREF(rect_list);
1513 free(regions);
1514
1515 return NULL; /* Exception already set. */
1516 }
1517
1518 Py_DECREF(rect);
1519 }
1520
1521 free(regions);
1522
1523 return rect_list;
1524 }
1525
1526 /* Finds all the connected components in a given mask.
1527 *
1528 * Allocates memory for components.
1529 *
1530 * NOTE: Caller is responsible for freeing the "components" memory.
1531 *
1532 * Params:
1533 * mask - mask to search in for the connected components
1534 * components - passes back an array of connected component masks with the
1535 * first component at index 1, memory is allocated
1536 * min - minimum number of pixels for a component to be considered,
1537 * defaults to 0 for negative values
1538 *
1539 * Returns:
1540 * the number of connected components (>= 0)
1541 * -2 on memory allocation error
1542 */
1543 static int
get_connected_components(bitmask_t * mask,bitmask_t *** components,int min)1544 get_connected_components(bitmask_t *mask, bitmask_t ***components, int min)
1545 {
1546 unsigned int *image, *ufind, *largest, *buf;
1547 unsigned int x_uf, min_cc, label = 0;
1548 int x, y, w, h, relabel;
1549 bitmask_t **comps;
1550
1551 w = mask->w;
1552 h = mask->h;
1553
1554 if (!w || !h) {
1555 return 0;
1556 }
1557
1558 /* a temporary image to assign labels to each bit of the mask */
1559 image = (unsigned int *)malloc(sizeof(int) * w * h);
1560 if (!image) {
1561 return -2;
1562 }
1563
1564 /* allocate enough space for the maximum possible connected components */
1565 /* the union-find array. see wikipedia for info on union find */
1566 ufind = (unsigned int *)malloc(sizeof(int) * (w / 2 + 1) * (h / 2 + 1));
1567 if (!ufind) {
1568 free(image);
1569 return -2;
1570 }
1571
1572 largest = (unsigned int *)malloc(sizeof(int) * (w / 2 + 1) * (h / 2 + 1));
1573 if (!largest) {
1574 free(image);
1575 free(ufind);
1576 return -2;
1577 }
1578
1579 /* do the initial labelling */
1580 label = cc_label(mask, image, ufind, largest);
1581
1582 for (x_uf = 1; x_uf <= label; ++x_uf) {
1583 if (ufind[x_uf] < x_uf) {
1584 largest[ufind[x_uf]] += largest[x_uf];
1585 }
1586 }
1587
1588 relabel = 0;
1589 min_cc = (0 < min) ? (unsigned int)min : 0;
1590
1591 /* flatten and relabel the union-find equivalence array. Start at label 1
1592 because label 0 indicates an unset pixel. For this reason, we also use
1593 <= label rather than < label. */
1594 for (x_uf = 1; x_uf <= label; ++x_uf) {
1595 if (ufind[x_uf] < x_uf) { /* is it a union find root? */
1596 ufind[x_uf] = ufind[ufind[x_uf]]; /* relabel it to its root */
1597 }
1598 else { /* its a root */
1599 if (largest[x_uf] >= min_cc) {
1600 relabel++;
1601 ufind[x_uf] = relabel; /* assign the lowest label available */
1602 }
1603 else {
1604 ufind[x_uf] = 0;
1605 }
1606 }
1607 }
1608
1609 if (relabel == 0) {
1610 /* early out, as we didn't find anything. */
1611 free(image);
1612 free(ufind);
1613 free(largest);
1614 return 0;
1615 }
1616
1617 /* allocate space for the mask array */
1618 comps = (bitmask_t **)malloc(sizeof(bitmask_t *) * (relabel + 1));
1619 if (!comps) {
1620 free(image);
1621 free(ufind);
1622 free(largest);
1623 return -2;
1624 }
1625
1626 /* create the empty masks */
1627 for (x = 1; x <= relabel; x++) {
1628 comps[x] = bitmask_create(w, h);
1629 }
1630
1631 /* set the bits in each mask */
1632 buf = image;
1633 for (y = 0; y < h; y++) {
1634 for (x = 0; x < w; x++) {
1635 if (ufind[*buf]) { /* if the pixel is part of a component */
1636 bitmask_setbit(comps[ufind[*buf]], x, y);
1637 }
1638 buf++;
1639 }
1640 }
1641
1642 free(image);
1643 free(ufind);
1644 free(largest);
1645
1646 *components = comps;
1647
1648 return relabel;
1649 }
1650
1651 static PyObject *
mask_connected_components(PyObject * self,PyObject * args,PyObject * kwargs)1652 mask_connected_components(PyObject *self, PyObject *args, PyObject *kwargs)
1653 {
1654 PyObject *mask_list = NULL;
1655 pgMaskObject *maskobj = NULL;
1656 bitmask_t **components = NULL;
1657 bitmask_t *mask = pgMask_AsBitmap(self);
1658 int i, m, num_components, min = 0; /* Default min value. */
1659 static char *keywords[] = {"minimum", NULL};
1660
1661 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i", keywords, &min)) {
1662 return NULL; /* Exception already set. */
1663 }
1664
1665 Py_BEGIN_ALLOW_THREADS;
1666 num_components = get_connected_components(mask, &components, min);
1667 Py_END_ALLOW_THREADS;
1668
1669 if (num_components == -2) {
1670 return RAISE(PyExc_MemoryError,
1671 "cannot allocate memory for connected components");
1672 }
1673
1674 mask_list = PyList_New(0);
1675 if (!mask_list) {
1676 /* Components were allocated starting at index 1. */
1677 for (i = 1; i <= num_components; ++i) {
1678 bitmask_free(components[i]);
1679 }
1680
1681 free(components);
1682 return NULL; /* Exception already set. */
1683 }
1684
1685 /* Components were allocated starting at index 1. */
1686 for (i = 1; i <= num_components; ++i) {
1687 maskobj = create_mask_using_bitmask(components[i]);
1688
1689 if (NULL == maskobj) {
1690 /* Starting freeing with the current index. */
1691 for (m = i; m <= num_components; ++m) {
1692 bitmask_free(components[m]);
1693 }
1694
1695 free(components);
1696 Py_DECREF(mask_list);
1697 return NULL; /* Exception already set. */
1698 }
1699
1700 if (0 != PyList_Append(mask_list, (PyObject *)maskobj)) {
1701 /* Can't append to the list. Starting freeing with the next index
1702 * as maskobj contains the component from the current index. */
1703 for (m = i + 1; m <= num_components; ++m) {
1704 bitmask_free(components[m]);
1705 }
1706
1707 free(components);
1708 Py_DECREF((PyObject *)maskobj);
1709 Py_DECREF(mask_list);
1710 return NULL; /* Exception already set. */
1711 }
1712
1713 Py_DECREF((PyObject *)maskobj);
1714 }
1715
1716 free(components);
1717 return mask_list;
1718 }
1719
1720 /* Finds the largest connected component in a given mask.
1721 *
1722 * Tracks the number of pixels in each label, finding the biggest one while
1723 * flattening the union-find equivalence array. It then writes an output mask
1724 * containing only the largest connected component.
1725 *
1726 * Params:
1727 * input - mask to search in for the largest connected component
1728 * output - this mask is updated with the largest connected component
1729 * ccx - x index, if < 0 then the largest connected component in the input
1730 * mask is found and copied to the output mask, otherwise the connected
1731 * component at (ccx, ccy) is copied to the output mask
1732 * ccy - y index
1733 *
1734 * Returns:
1735 * 0 on success
1736 * -2 on memory allocation error
1737 */
1738 static int
largest_connected_comp(bitmask_t * input,bitmask_t * output,int ccx,int ccy)1739 largest_connected_comp(bitmask_t *input, bitmask_t *output, int ccx, int ccy)
1740 {
1741 unsigned int *image, *ufind, *largest, *buf;
1742 unsigned int max, x, y, w, h, label;
1743
1744 w = input->w;
1745 h = input->h;
1746
1747 if (!w || !h) {
1748 return 0;
1749 }
1750
1751 /* a temporary image to assign labels to each bit of the mask */
1752 image = (unsigned int *)malloc(sizeof(int) * w * h);
1753 if (!image) {
1754 return -2;
1755 }
1756 /* allocate enough space for the maximum possible connected components */
1757 /* the union-find array. see wikipedia for info on union find */
1758 ufind = (unsigned int *)malloc(sizeof(int) * (w / 2 + 1) * (h / 2 + 1));
1759 if (!ufind) {
1760 free(image);
1761 return -2;
1762 }
1763 /* an array to track the number of pixels associated with each label */
1764 largest = (unsigned int *)malloc(sizeof(int) * (w / 2 + 1) * (h / 2 + 1));
1765 if (!largest) {
1766 free(image);
1767 free(ufind);
1768 return -2;
1769 }
1770
1771 /* do the initial labelling */
1772 label = cc_label(input, image, ufind, largest);
1773
1774 max = 1;
1775 /* flatten the union-find equivalence array */
1776 for (x = 2; x <= label; x++) {
1777 if (ufind[x] != x) { /* is it a union find root? */
1778 largest[ufind[x]] += largest[x]; /* add its pixels to its root */
1779 ufind[x] = ufind[ufind[x]]; /* relabel it to its root */
1780 }
1781 if (largest[ufind[x]] > largest[max]) { /* is it the new biggest? */
1782 max = ufind[x];
1783 }
1784 }
1785
1786 /* write out the final image */
1787 buf = image;
1788 if (ccx >= 0)
1789 max = ufind[*(buf + ccy * w + ccx)];
1790 for (y = 0; y < h; y++) {
1791 for (x = 0; x < w; x++) {
1792 if (ufind[*buf] == max) { /* if the label is the max one */
1793 bitmask_setbit(output, x, y); /* set the bit in the mask */
1794 }
1795 buf++;
1796 }
1797 }
1798
1799 free(image);
1800 free(ufind);
1801 free(largest);
1802
1803 return 0;
1804 }
1805
1806 static PyObject *
mask_connected_component(PyObject * self,PyObject * args,PyObject * kwargs)1807 mask_connected_component(PyObject *self, PyObject *args, PyObject *kwargs)
1808 {
1809 bitmask_t *input = pgMask_AsBitmap(self);
1810 pgMaskObject *output_maskobj = NULL;
1811 int x = -1, y = -1;
1812 Py_ssize_t args_exist = PyTuple_Size(args);
1813 PyObject* pos = NULL;
1814 static char *keywords[] = {"pos", NULL};
1815
1816 if (kwargs)
1817 args_exist += PyDict_Size(kwargs);
1818
1819 if (args_exist) {
1820 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", keywords, &pos)) {
1821 return NULL; /* Exception already set. */
1822 }
1823
1824 if (!pg_TwoIntsFromObj(pos, &x, &y)) {
1825 return RAISE(PyExc_TypeError, "pos must be two numbers");
1826 }
1827
1828 if (x < 0 || x >= input->w || y < 0 || y >= input->h) {
1829 return PyErr_Format(PyExc_IndexError, "%d, %d is out of bounds", x,
1830 y);
1831 }
1832 }
1833
1834 output_maskobj = CREATE_MASK_OBJ(input->w, input->h, 0);
1835
1836 if (NULL == output_maskobj) {
1837 return NULL; /* Exception already set. */
1838 }
1839
1840 /* If a pixel index is provided and the indexed bit is not set, then the
1841 * returned mask is empty.
1842 */
1843 if (!args_exist || bitmask_getbit(input, x, y)) {
1844 if (largest_connected_comp(input, output_maskobj->mask, x, y) == -2) {
1845 Py_DECREF(output_maskobj);
1846 return RAISE(PyExc_MemoryError,
1847 "cannot allocate memory for connected component");
1848 }
1849 }
1850
1851 return (PyObject *)output_maskobj;
1852 }
1853
1854 /* Extract the color data from a color object.
1855 *
1856 * Params:
1857 * surf: surface that color will be mapped from
1858 * color_obj: color object to extract color data from
1859 * rbga_color: rbga array, contains default color if color_obj is NULL
1860 * color: color value extracted from the color_obj (or from the default
1861 * value of rbga_color)
1862 *
1863 * Returns:
1864 * int: 1, means the color data extraction was successful and the color
1865 * parameter contains a valid color value
1866 * 0, means the color data extraction has failed and an exception has
1867 * been set
1868 */
1869 static int
extract_color(SDL_Surface * surf,PyObject * color_obj,Uint8 rgba_color[],Uint32 * color)1870 extract_color(SDL_Surface *surf, PyObject *color_obj, Uint8 rgba_color[],
1871 Uint32 *color)
1872 {
1873 if (NULL == color_obj) {
1874 *color = SDL_MapRGBA(surf->format, rgba_color[0], rgba_color[1],
1875 rgba_color[2], rgba_color[3]);
1876 return 1;
1877 }
1878
1879 if (PyInt_Check(color_obj)) {
1880 long intval = PyInt_AsLong(color_obj);
1881
1882 if ((-1 == intval && PyErr_Occurred()) || intval > (long)0xFFFFFFFF) {
1883 PyErr_SetString(PyExc_ValueError, "invalid color argument");
1884 return 0;
1885 }
1886
1887 *color = (Uint32)intval;
1888 return 1;
1889 }
1890
1891 if (PyLong_Check(color_obj)) {
1892 unsigned long longval = PyLong_AsUnsignedLong(color_obj);
1893
1894 if (PyErr_Occurred() || longval > 0xFFFFFFFF) {
1895 PyErr_SetString(PyExc_ValueError, "invalid color argument");
1896 return 0;
1897 }
1898
1899 *color = (Uint32)longval;
1900 return 1;
1901 }
1902
1903 if (pg_RGBAFromFuzzyColorObj(color_obj, rgba_color)) {
1904 *color = SDL_MapRGBA(surf->format, rgba_color[0], rgba_color[1],
1905 rgba_color[2], rgba_color[3]);
1906 return 1;
1907 }
1908
1909 return 0; /* Exception already set. */
1910 }
1911
1912 /* Draws a mask on a surface.
1913 *
1914 * Params:
1915 * surf: surface to draw on
1916 * bitmask: bitmask to draw
1917 * x_dest: x position on surface of where to start drawing
1918 * y_dest: y position on surface of where to start drawing
1919 * draw_setbits: if non-zero then draw the set bits (bits==1)
1920 * draw_unsetbits: if non-zero then draw the unset bits (bits==0)
1921 * setsurf: use colors from this surface for set bits (bits==1)
1922 * unsetsurf: use colors from this surface for unset bits (bits==0)
1923 * setcolor: color for set bits, setsurf takes precedence (bits==1)
1924 * unsetcolor: color for unset bits, unsetsurf takes precedence (bits==0)
1925 *
1926 * Assumptions:
1927 * - surf and bitmask are non-NULL
1928 * - all surfaces have the same pixel format
1929 * - all surfaces that are non-NULL are locked
1930 */
1931 static void
draw_to_surface(SDL_Surface * surf,bitmask_t * bitmask,int x_dest,int y_dest,int draw_setbits,int draw_unsetbits,SDL_Surface * setsurf,SDL_Surface * unsetsurf,Uint32 * setcolor,Uint32 * unsetcolor)1932 draw_to_surface(SDL_Surface *surf, bitmask_t *bitmask, int x_dest, int y_dest,
1933 int draw_setbits, int draw_unsetbits, SDL_Surface *setsurf,
1934 SDL_Surface *unsetsurf, Uint32 *setcolor, Uint32 *unsetcolor)
1935 {
1936 Uint8 *pixel = NULL;
1937 Uint8 bpp;
1938 int x, y, x_end, y_end, x_start, y_start; /* surf indexing */
1939 int xm, ym, xm_start, ym_start; /* bitmask/setsurf/unsetsurf indexing */
1940
1941 /* There is nothing to do when any of these conditions exist:
1942 * - surface has a width or height of <= 0
1943 * - mask has a width or height of <= 0
1944 * - draw_setbits and draw_unsetbits are both 0 */
1945 if ((surf->h <= 0) || (surf->w <= 0) || (bitmask->h <= 0) ||
1946 (bitmask->w <= 0) || (!draw_setbits && !draw_unsetbits)) {
1947 return;
1948 }
1949
1950 /* There is also nothing to do when the destination position is such that
1951 * nothing will be drawn on the surface. */
1952 if ((x_dest >= surf->w) || (y_dest >= surf->h) || (-x_dest > bitmask->w) ||
1953 (-y_dest > bitmask->h)) {
1954 return;
1955 }
1956
1957 bpp = surf->format->BytesPerPixel;
1958
1959 xm_start = (x_dest < 0) ? -x_dest : 0;
1960 x_start = (x_dest > 0) ? x_dest : 0;
1961 x_end = MIN(surf->w, bitmask->w + x_dest);
1962
1963 ym_start = (y_dest < 0) ? -y_dest : 0;
1964 y_start = (y_dest > 0) ? y_dest : 0;
1965 y_end = MIN(surf->h, bitmask->h + y_dest);
1966
1967 if (NULL == setsurf && NULL == unsetsurf) {
1968 /* Draw just using color values. No surfaces. */
1969 draw_setbits = draw_setbits && NULL != setcolor;
1970 draw_unsetbits = draw_unsetbits && NULL != unsetcolor;
1971
1972 for (y = y_start, ym = ym_start; y < y_end; ++y, ++ym) {
1973 pixel = (Uint8 *)surf->pixels + y * surf->pitch + x_start * bpp;
1974
1975 for (x = x_start, xm = xm_start; x < x_end;
1976 ++x, ++xm, pixel += bpp) {
1977 if (bitmask_getbit(bitmask, xm, ym)) {
1978 if (draw_setbits) {
1979 set_pixel_color(pixel, bpp, *setcolor);
1980 }
1981 }
1982 else if (draw_unsetbits) {
1983 set_pixel_color(pixel, bpp, *unsetcolor);
1984 }
1985 }
1986 }
1987 }
1988 else if (NULL == setcolor && NULL == unsetcolor && NULL != setsurf &&
1989 NULL != unsetsurf && setsurf->h + y_dest >= y_end &&
1990 setsurf->w + x_dest >= x_end && unsetsurf->h + y_dest >= y_end &&
1991 unsetsurf->w + x_dest >= x_end) {
1992 /* Draw using surfaces that are as big (or bigger) as what is being
1993 * drawn and no color values are being used. */
1994 Uint8 *setpixel = NULL, *unsetpixel = NULL;
1995
1996 for (y = y_start, ym = ym_start; y < y_end; ++y, ++ym) {
1997 pixel = (Uint8 *)surf->pixels + y * surf->pitch + x_start * bpp;
1998 setpixel = (Uint8 *)setsurf->pixels + ym * setsurf->pitch +
1999 xm_start * bpp;
2000 unsetpixel = (Uint8 *)unsetsurf->pixels + ym * unsetsurf->pitch +
2001 xm_start * bpp;
2002
2003 for (x = x_start, xm = xm_start; x < x_end;
2004 ++x, ++xm, pixel += bpp, setpixel += bpp, unsetpixel += bpp) {
2005 if (bitmask_getbit(bitmask, xm, ym)) {
2006 if (draw_setbits) {
2007 set_pixel_color(pixel, bpp,
2008 get_pixel_color(setpixel, bpp));
2009 }
2010 }
2011 else if (draw_unsetbits) {
2012 set_pixel_color(pixel, bpp,
2013 get_pixel_color(unsetpixel, bpp));
2014 }
2015 }
2016 }
2017 }
2018 else {
2019 /* Draw using surfaces and color values. */
2020 Uint8 *setpixel = NULL, *unsetpixel = NULL;
2021 int use_setsurf, use_unsetsurf;
2022
2023 /* Looping over each bit in the mask and deciding whether to use a
2024 * color from setsurf/unsetsurf or from setcolor/unsetcolor. */
2025 for (y = y_start, ym = ym_start; y < y_end; ++y, ++ym) {
2026 pixel = (Uint8 *)surf->pixels + y * surf->pitch + x_start * bpp;
2027 use_setsurf =
2028 draw_setbits && NULL != setsurf && setsurf->h > ym;
2029 use_unsetsurf =
2030 draw_unsetbits && NULL != unsetsurf && unsetsurf->h > ym;
2031
2032 if (use_setsurf) {
2033 setpixel = (Uint8 *)setsurf->pixels + ym * setsurf->pitch +
2034 xm_start * bpp;
2035 }
2036
2037 if (use_unsetsurf) {
2038 unsetpixel = (Uint8 *)unsetsurf->pixels +
2039 ym * unsetsurf->pitch + xm_start * bpp;
2040 }
2041
2042 for (x = x_start, xm = xm_start; x < x_end;
2043 ++x, ++xm, pixel += bpp) {
2044 if (bitmask_getbit(bitmask, xm, ym)) {
2045 if (draw_setbits) {
2046 if (use_setsurf && setsurf->w > xm) {
2047 set_pixel_color(pixel, bpp,
2048 get_pixel_color(setpixel, bpp));
2049 }
2050 else if (NULL != setcolor) {
2051 set_pixel_color(pixel, bpp, *setcolor);
2052 }
2053 }
2054 }
2055 else if (draw_unsetbits) {
2056 if (use_unsetsurf && unsetsurf->w > xm) {
2057 set_pixel_color(pixel, bpp,
2058 get_pixel_color(unsetpixel, bpp));
2059 }
2060 else if (NULL != unsetcolor) {
2061 set_pixel_color(pixel, bpp, *unsetcolor);
2062 }
2063 }
2064
2065 if (use_setsurf) {
2066 setpixel += bpp;
2067 }
2068
2069 if (use_unsetsurf) {
2070 unsetpixel += bpp;
2071 }
2072 }
2073 }
2074 }
2075 }
2076
2077 /* Checks if the surfaces have the same pixel formats.
2078 *
2079 * Params:
2080 * surf: surface to check against
2081 * check_surf: surface to check
2082 *
2083 * Returns:
2084 * int: 0 to indicate surfaces don't have the same format
2085 * 1 to indicate the surfaces have the same format
2086 *
2087 * Assumptions:
2088 * - both parameters are non-NULL
2089 * - these checks are enough to assume the pixel formats are the same
2090 */
2091 static int
check_surface_pixel_format(SDL_Surface * surf,SDL_Surface * check_surf)2092 check_surface_pixel_format(SDL_Surface *surf, SDL_Surface *check_surf)
2093 {
2094 if ((surf->format->BytesPerPixel != check_surf->format->BytesPerPixel) ||
2095 (surf->format->BitsPerPixel != check_surf->format->BitsPerPixel)
2096 || (surf->format->format != check_surf->format->format)
2097 ) {
2098 return 0;
2099 }
2100
2101 return 1;
2102 }
2103
2104 /* Draws a mask on a surface.
2105 *
2106 * Returns:
2107 * Surface object or NULL to indicate a fail.
2108 */
2109 static PyObject *
mask_to_surface(PyObject * self,PyObject * args,PyObject * kwargs)2110 mask_to_surface(PyObject *self, PyObject *args, PyObject *kwargs)
2111 {
2112 PyObject *surfobj = Py_None, *setcolorobj = NULL, *unsetcolorobj = NULL;
2113 PyObject *setsurfobj = Py_None, *unsetsurfobj = Py_None;
2114 PyObject *destobj = NULL;
2115 SDL_Surface *surf = NULL, *setsurf = NULL, *unsetsurf = NULL;
2116 bitmask_t *bitmask = pgMask_AsBitmap(self);
2117 Uint32 *setcolor_ptr = NULL, *unsetcolor_ptr = NULL;
2118 Uint32 setcolor, unsetcolor;
2119 int draw_setbits = 0, draw_unsetbits = 0;
2120 int created_surfobj = 0; /* Set to 1 if this func creates the surfobj. */
2121 int x_dest = 0, y_dest = 0; /* Default destination coordinates. */
2122 Uint8 dflt_setcolor[] = {255, 255, 255, 255}; /* Default set color. */
2123 Uint8 dflt_unsetcolor[] = {0, 0, 0, 255}; /* Default unset color. */
2124
2125 static char *keywords[] = {"surface", "setsurface", "unsetsurface",
2126 "setcolor", "unsetcolor", "dest",
2127 NULL};
2128
2129 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOOOOO", keywords,
2130 &surfobj, &setsurfobj, &unsetsurfobj,
2131 &setcolorobj, &unsetcolorobj, &destobj)) {
2132 return NULL; /* Exception already set. */
2133 }
2134
2135 if (Py_None == surfobj) {
2136 surfobj = PyObject_CallFunction((PyObject *)&pgSurface_Type, "(ii)ii",
2137 bitmask->w, bitmask->h,
2138 PGS_SRCALPHA,
2139 32);
2140
2141 if (NULL == surfobj) {
2142 if (!PyErr_Occurred()) {
2143 return RAISE(PyExc_RuntimeError, "unable to create surface");
2144 }
2145 return NULL;
2146 }
2147
2148 created_surfobj = 1;
2149 }
2150 else if (!pgSurface_Check(surfobj)) {
2151 return RAISE(PyExc_TypeError, "invalid surface argument");
2152 }
2153
2154 surf = pgSurface_AsSurface(surfobj);
2155
2156 if (Py_None != setsurfobj) {
2157 if (!pgSurface_Check(setsurfobj)) {
2158 PyErr_SetString(PyExc_TypeError, "invalid setsurface argument");
2159 goto to_surface_error;
2160 }
2161
2162 setsurf = pgSurface_AsSurface(setsurfobj);
2163
2164 if (0 == check_surface_pixel_format(surf, setsurf)) {
2165 /* Needs to have the same format settings as surface. */
2166 PyErr_SetString(PyExc_ValueError,
2167 "setsurface needs to have same "
2168 "bytesize/bitsize/alpha format as surface");
2169 goto to_surface_error;
2170 }
2171 else if ((setsurf->h <= 0) || (setsurf->w <= 0)) {
2172 /* Surface has no usable color positions, so ignore it. */
2173 setsurf = NULL;
2174 }
2175 else {
2176 draw_setbits = 1;
2177 }
2178 }
2179
2180 if (Py_None != unsetsurfobj) {
2181 if (!pgSurface_Check(unsetsurfobj)) {
2182 PyErr_SetString(PyExc_TypeError, "invalid unsetsurface argument");
2183 goto to_surface_error;
2184 }
2185
2186 unsetsurf = pgSurface_AsSurface(unsetsurfobj);
2187
2188 if (0 == check_surface_pixel_format(surf, unsetsurf)) {
2189 /* Needs to have the same format settings as surface. */
2190 PyErr_SetString(PyExc_ValueError,
2191 "unsetsurface needs to have same "
2192 "bytesize/bitsize/alpha format as surface");
2193 goto to_surface_error;
2194 }
2195 else if ((unsetsurf->h <= 0) || (unsetsurf->w <= 0)) {
2196 /* Surface has no usable color positions, so ignore it. */
2197 unsetsurf = NULL;
2198 }
2199 else {
2200 draw_unsetbits = 1;
2201 }
2202 }
2203
2204 if (Py_None != setcolorobj) {
2205 if (!extract_color(surf, setcolorobj, dflt_setcolor, &setcolor)) {
2206 goto to_surface_error; /* Exception already set. */
2207 }
2208
2209 setcolor_ptr = &setcolor;
2210 draw_setbits = 1;
2211 }
2212
2213 if (Py_None != unsetcolorobj) {
2214 if (!extract_color(surf, unsetcolorobj, dflt_unsetcolor,
2215 &unsetcolor)) {
2216 goto to_surface_error; /* Exception already set. */
2217 }
2218
2219 unsetcolor_ptr = &unsetcolor;
2220 draw_unsetbits = 1;
2221 }
2222
2223 if (NULL != destobj) {
2224 int tempx, tempy;
2225
2226 /* Destination coordinates can be extracted from:
2227 * - lists/tuples with 2 items
2228 * - Rect (or Rect like) objects (uses x, y values) */
2229 if (pg_TwoIntsFromObj(destobj, &tempx, &tempy)) {
2230 x_dest = tempx;
2231 y_dest = tempy;
2232 }
2233 else {
2234 GAME_Rect temp_rect;
2235 GAME_Rect *dest_rect = pgRect_FromObject(destobj, &temp_rect);
2236
2237 if (NULL != dest_rect) {
2238 x_dest = dest_rect->x;
2239 y_dest = dest_rect->y;
2240 }
2241 else {
2242 PyErr_SetString(PyExc_TypeError, "invalid dest argument");
2243 goto to_surface_error;
2244 }
2245 }
2246 }
2247
2248 if (!pgSurface_Lock((pgSurfaceObject *)surfobj)) {
2249 PyErr_SetString(PyExc_RuntimeError, "cannot lock surface");
2250 goto to_surface_error;
2251 }
2252
2253 /* Only lock the setsurface if it is being used.
2254 * i.e. setsurf is non-NULL */
2255 if (NULL != setsurf && !pgSurface_Lock((pgSurfaceObject *)setsurfobj)) {
2256 PyErr_SetString(PyExc_RuntimeError, "cannot lock setsurface");
2257 goto to_surface_error;
2258 }
2259
2260 /* Only lock the unsetsurface if it is being used.
2261 * i.e.. unsetsurf is non-NULL. */
2262 if (NULL != unsetsurf &&
2263 !pgSurface_Lock((pgSurfaceObject *)unsetsurfobj)) {
2264 PyErr_SetString(PyExc_RuntimeError, "cannot lock unsetsurface");
2265 goto to_surface_error;
2266 }
2267
2268 Py_BEGIN_ALLOW_THREADS; /* Release the GIL. */
2269
2270 draw_to_surface(surf, bitmask, x_dest, y_dest, draw_setbits,
2271 draw_unsetbits, setsurf, unsetsurf, setcolor_ptr,
2272 unsetcolor_ptr);
2273
2274 Py_END_ALLOW_THREADS; /* Obtain the GIL. */
2275
2276 if (NULL != unsetsurf &&
2277 !pgSurface_Unlock((pgSurfaceObject *)unsetsurfobj)) {
2278 PyErr_SetString(PyExc_RuntimeError, "cannot unlock unsetsurface");
2279 goto to_surface_error;
2280 }
2281
2282 if (NULL != setsurf &&
2283 !pgSurface_Unlock((pgSurfaceObject *)setsurfobj)) {
2284 PyErr_SetString(PyExc_RuntimeError, "cannot unlock setsurface");
2285 goto to_surface_error;
2286 }
2287
2288 if (!pgSurface_Unlock((pgSurfaceObject *)surfobj)) {
2289 PyErr_SetString(PyExc_RuntimeError, "cannot unlock surface");
2290 goto to_surface_error;
2291 }
2292
2293 if (!created_surfobj) {
2294 /* Only increase ref count if this func didn't create the surfobj. */
2295 Py_INCREF(surfobj);
2296 }
2297
2298 return surfobj;
2299
2300 /* Handles the cleanup for fail cases. */
2301 to_surface_error:
2302 if (created_surfobj) {
2303 /* Only decrease ref count if this func created the surfobj. */
2304 Py_DECREF(surfobj);
2305 }
2306
2307 return NULL;
2308 }
2309
2310 static PyMethodDef mask_methods[] = {
2311 {"__copy__", mask_copy, METH_NOARGS, DOC_MASKCOPY},
2312 {"copy", mask_call_copy, METH_NOARGS, DOC_MASKCOPY},
2313 {"get_size", mask_get_size, METH_VARARGS, DOC_MASKGETSIZE},
2314 {"get_rect", (PyCFunction)mask_get_rect, METH_VARARGS | METH_KEYWORDS,
2315 DOC_MASKGETRECT},
2316 {"get_at", (PyCFunction)mask_get_at, METH_VARARGS | METH_KEYWORDS,
2317 DOC_MASKGETAT},
2318 {"set_at", (PyCFunction)mask_set_at, METH_VARARGS | METH_KEYWORDS,
2319 DOC_MASKSETAT},
2320 {"overlap", (PyCFunction)mask_overlap, METH_VARARGS | METH_KEYWORDS,
2321 DOC_MASKOVERLAP},
2322 {"overlap_area", (PyCFunction)mask_overlap_area, METH_VARARGS | METH_KEYWORDS,
2323 DOC_MASKOVERLAPAREA},
2324 {"overlap_mask", (PyCFunction)mask_overlap_mask, METH_VARARGS | METH_KEYWORDS,
2325 DOC_MASKOVERLAPMASK},
2326 {"fill", mask_fill, METH_NOARGS, DOC_MASKFILL},
2327 {"clear", mask_clear, METH_NOARGS, DOC_MASKCLEAR},
2328 {"invert", mask_invert, METH_NOARGS, DOC_MASKINVERT},
2329 {"scale", (PyCFunction)mask_scale, METH_VARARGS | METH_KEYWORDS,
2330 DOC_MASKSCALE},
2331 {"draw", (PyCFunction)mask_draw, METH_VARARGS | METH_KEYWORDS,
2332 DOC_MASKDRAW},
2333 {"erase", (PyCFunction)mask_erase, METH_VARARGS | METH_KEYWORDS,
2334 DOC_MASKERASE},
2335 {"count", mask_count, METH_NOARGS, DOC_MASKCOUNT},
2336 {"centroid", mask_centroid, METH_NOARGS, DOC_MASKCENTROID},
2337 {"angle", mask_angle, METH_NOARGS, DOC_MASKANGLE},
2338 {"outline", (PyCFunction)mask_outline, METH_VARARGS | METH_KEYWORDS,
2339 DOC_MASKOUTLINE},
2340 {"convolve", (PyCFunction)mask_convolve, METH_VARARGS | METH_KEYWORDS,
2341 DOC_MASKCONVOLVE},
2342 {"connected_component", (PyCFunction)mask_connected_component, METH_VARARGS | METH_KEYWORDS,
2343 DOC_MASKCONNECTEDCOMPONENT},
2344 {"connected_components", (PyCFunction)mask_connected_components, METH_VARARGS | METH_KEYWORDS,
2345 DOC_MASKCONNECTEDCOMPONENTS},
2346 {"get_bounding_rects", mask_get_bounding_rects, METH_NOARGS,
2347 DOC_MASKGETBOUNDINGRECTS},
2348 {"to_surface", (PyCFunction)mask_to_surface, METH_VARARGS | METH_KEYWORDS,
2349 DOC_MASKTOSURFACE},
2350
2351 {NULL, NULL, 0, NULL}};
2352
2353 /*mask object internals*/
2354
2355 /* This is a helper function for internal use only.
2356 * Creates a mask object using an existing bitmask.
2357 *
2358 * Params:
2359 * bitmask: pointer to the bitmask to use
2360 *
2361 * Returns:
2362 * Mask object or NULL to indicate a fail
2363 */
2364 static PG_INLINE pgMaskObject *
create_mask_using_bitmask(bitmask_t * bitmask)2365 create_mask_using_bitmask(bitmask_t *bitmask)
2366 {
2367 return create_mask_using_bitmask_and_type(bitmask, &pgMask_Type);
2368 }
2369
2370 /* This is a helper function for internal use only.
2371 * Creates a mask object using an existing bitmask and a type.
2372 *
2373 * Params:
2374 * bitmask: pointer to the bitmask to use
2375 * ob_type: pointer to the mask object type to create
2376 *
2377 * Returns:
2378 * Mask object or NULL to indicate a fail
2379 */
2380 static PG_INLINE pgMaskObject *
create_mask_using_bitmask_and_type(bitmask_t * bitmask,PyTypeObject * ob_type)2381 create_mask_using_bitmask_and_type(bitmask_t *bitmask, PyTypeObject *ob_type)
2382 {
2383 /* tp_init is not needed as the bitmask has already been created. */
2384 pgMaskObject *maskobj =
2385 (pgMaskObject *)pgMask_Type.tp_new(ob_type, NULL, NULL);
2386
2387 if (NULL == maskobj) {
2388 return (pgMaskObject *)RAISE(PyExc_MemoryError,
2389 "cannot allocate memory for mask");
2390 }
2391
2392 maskobj->mask = bitmask;
2393 return maskobj;
2394 }
2395
2396 static void
mask_dealloc(PyObject * self)2397 mask_dealloc(PyObject *self)
2398 {
2399 bitmask_t *bitmask = pgMask_AsBitmap(self);
2400
2401 if (NULL != bitmask) {
2402 /* Free up the bitmask. */
2403 bitmask_free(bitmask);
2404 }
2405
2406 /* Free up the mask. */
2407 Py_TYPE(self)->tp_free(self);
2408 }
2409
2410 static PyObject *
mask_repr(PyObject * self)2411 mask_repr(PyObject *self)
2412 {
2413 bitmask_t *mask = pgMask_AsBitmap(self);
2414 return Text_FromFormat("<Mask(%dx%d)>", mask->w, mask->h);
2415 }
2416
2417 static PyObject *
mask_new(PyTypeObject * subtype,PyObject * args,PyObject * kwargs)2418 mask_new(PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
2419 {
2420 pgMaskObject *maskobj = (pgMaskObject *)subtype->tp_alloc(subtype, 0);
2421
2422 if (NULL == maskobj) {
2423 return RAISE(PyExc_MemoryError, "cannot allocate memory for mask");
2424 }
2425
2426 maskobj->mask = NULL;
2427 return (PyObject *)maskobj;
2428 }
2429
2430 static int
mask_init(PyObject * self,PyObject * args,PyObject * kwargs)2431 mask_init(PyObject *self, PyObject *args, PyObject *kwargs)
2432 {
2433 bitmask_t *bitmask = NULL;
2434 PyObject* size = NULL;
2435 int w, h;
2436 int fill = 0; /* Default is false. */
2437 char *keywords[] = {"size", "fill", NULL};
2438 const char *format = "O|p";
2439
2440 if (!PyArg_ParseTupleAndKeywords(args, kwargs, format, keywords, &size,
2441 &fill)) {
2442 return -1;
2443 }
2444
2445 if (!pg_TwoIntsFromObj(size, &w, &h)) {
2446 PyErr_SetString(PyExc_TypeError, "size must be two numbers");
2447 return -1;
2448 }
2449
2450 if (w < 0 || h < 0) {
2451 PyErr_SetString(PyExc_ValueError,
2452 "cannot create mask with negative size");
2453 return -1;
2454 }
2455
2456 bitmask = bitmask_create(w, h);
2457
2458 if (NULL == bitmask) {
2459 PyErr_SetString(PyExc_MemoryError,
2460 "cannot allocate memory for bitmask");
2461 return -1;
2462 }
2463
2464 if (fill) {
2465 bitmask_fill(bitmask);
2466 }
2467
2468 ((pgMaskObject *)self)->mask = bitmask;
2469 return 0;
2470 }
2471
2472 typedef struct {
2473 int numbufs;
2474 Py_ssize_t shape[2];
2475 Py_ssize_t strides[2];
2476 } mask_bufinfo;
2477
2478 static int
pgMask_GetBuffer(pgMaskObject * self,Py_buffer * view,int flags)2479 pgMask_GetBuffer(pgMaskObject *self, Py_buffer *view, int flags)
2480 {
2481 bitmask_t *m = self->mask;
2482 mask_bufinfo *bufinfo = (mask_bufinfo*)self->bufdata;
2483
2484 if (bufinfo == NULL) {
2485 bufinfo = PyMem_RawMalloc(sizeof(mask_bufinfo));
2486 if (bufinfo == NULL) {
2487 PyErr_NoMemory();
2488 return -1;
2489 }
2490 bufinfo->numbufs = 1;
2491
2492 bufinfo->shape[0] = (m->w - 1) / BITMASK_W_LEN + 1;
2493 bufinfo->shape[1] = m->h;
2494
2495 bufinfo->strides[0] = m->h * sizeof(BITMASK_W);
2496 bufinfo->strides[1] = sizeof(BITMASK_W);
2497
2498 self->bufdata = bufinfo;
2499 }
2500 else {
2501 bufinfo->numbufs++;
2502 }
2503
2504 view->buf = m->bits;
2505 view->len = m->h * ((m->w - 1) / BITMASK_W_LEN + 1) * sizeof(BITMASK_W);
2506 view->readonly = 0;
2507 view->itemsize = sizeof(BITMASK_W);
2508 view->ndim = 2;
2509 view->internal = bufinfo;
2510 view->shape = (flags & PyBUF_ND) ? bufinfo->shape : NULL;
2511 view->strides = (flags & PyBUF_STRIDES) ? bufinfo->strides : NULL;
2512 if (flags & PyBUF_FORMAT) {
2513 view->format = "L"; /* L = unsigned long */
2514 }
2515 else {
2516 view->format = NULL;
2517 }
2518 view->suboffsets = NULL;
2519
2520 Py_INCREF(self);
2521 view->obj = (PyObject *)self;
2522
2523 return 0;
2524 }
2525
2526 static void
pgMask_ReleaseBuffer(pgMaskObject * self,Py_buffer * view)2527 pgMask_ReleaseBuffer(pgMaskObject *self, Py_buffer *view)
2528 {
2529 mask_bufinfo *bufinfo = (mask_bufinfo*)view->internal;
2530
2531 bufinfo->numbufs--;
2532 if (bufinfo->numbufs == 0) {
2533 PyMem_RawFree(bufinfo);
2534 self->bufdata = NULL;
2535 }
2536 }
2537
2538 static PyBufferProcs pgMask_BufferProcs = {
2539 (getbufferproc)pgMask_GetBuffer,
2540 (releasebufferproc)pgMask_ReleaseBuffer
2541 };
2542
2543
2544 static PyTypeObject pgMask_Type = {
2545 PyVarObject_HEAD_INIT(NULL,0)
2546 "pygame.mask.Mask", /* tp_name */
2547 sizeof(pgMaskObject), /* tp_basicsize */
2548 0, /* tp_itemsize */
2549 mask_dealloc, /* tp_dealloc */
2550 0, /* tp_print */
2551 0, /* tp_getattr */
2552 0, /* tp_setattr */
2553 0, /* tp_as_async (formerly tp_compare/tp_reserved) */
2554 (reprfunc)mask_repr, /* tp_repr */
2555 0, /* tp_as_number */
2556 NULL, /* tp_as_sequence */
2557 0, /* tp_as_mapping */
2558 (hashfunc)NULL, /* tp_hash */
2559 (ternaryfunc)NULL, /* tp_call */
2560 (reprfunc)NULL, /* tp_str */
2561 0L, /* tp_getattro */
2562 0L, /* tp_setattro */
2563 &pgMask_BufferProcs, /* tp_as_buffer */
2564 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
2565 DOC_PYGAMEMASKMASK, /* Documentation string */
2566 0, /* tp_traverse */
2567 0, /* tp_clear */
2568 0, /* tp_richcompare */
2569 0, /* tp_weaklistoffset */
2570 0, /* tp_iter */
2571 0, /* tp_iternext */
2572 mask_methods, /* tp_methods */
2573 0, /* tp_members */
2574 0, /* tp_getset */
2575 0, /* tp_base */
2576 0, /* tp_dict */
2577 0, /* tp_descr_get */
2578 0, /* tp_descr_set */
2579 0, /* tp_dictoffset */
2580 mask_init, /* tp_init */
2581 0, /* tp_alloc */
2582 mask_new, /* tp_new */
2583 };
2584
2585 /*mask module methods*/
2586 static PyMethodDef _mask_methods[] = {
2587 {"from_surface", (PyCFunction)mask_from_surface, METH_VARARGS | METH_KEYWORDS,
2588 DOC_PYGAMEMASKFROMSURFACE},
2589 {"from_threshold", (PyCFunction)mask_from_threshold, METH_VARARGS | METH_KEYWORDS,
2590 DOC_PYGAMEMASKFROMTHRESHOLD},
2591 {NULL, NULL, 0, NULL}};
2592
MODINIT_DEFINE(mask)2593 MODINIT_DEFINE(mask)
2594 {
2595 PyObject *module, *dict, *apiobj;
2596 static void *c_api[PYGAMEAPI_MASK_NUMSLOTS];
2597
2598 static struct PyModuleDef _module = {PyModuleDef_HEAD_INIT,
2599 "mask",
2600 DOC_PYGAMEMASK,
2601 -1,
2602 _mask_methods,
2603 NULL,
2604 NULL,
2605 NULL,
2606 NULL};
2607
2608 /* imported needed apis; Do this first so if there is an error
2609 the module is not loaded.
2610 */
2611 import_pygame_base();
2612 if (PyErr_Occurred()) {
2613 MODINIT_ERROR;
2614 }
2615 import_pygame_color();
2616 if (PyErr_Occurred()) {
2617 MODINIT_ERROR;
2618 }
2619 import_pygame_surface();
2620 if (PyErr_Occurred()) {
2621 MODINIT_ERROR;
2622 }
2623 import_pygame_rect();
2624 if (PyErr_Occurred()) {
2625 MODINIT_ERROR;
2626 }
2627
2628 /* create the mask type */
2629 if (PyType_Ready(&pgMask_Type) < 0) {
2630 MODINIT_ERROR;
2631 }
2632
2633 /* create the module */
2634 module = PyModule_Create(&_module);
2635 if (module == NULL) {
2636 MODINIT_ERROR;
2637 }
2638 dict = PyModule_GetDict(module);
2639 if (PyDict_SetItemString(dict, "MaskType", (PyObject *)&pgMask_Type) ==
2640 -1) {
2641 DECREF_MOD(module);
2642 MODINIT_ERROR;
2643 }
2644
2645 if (PyDict_SetItemString(dict, "Mask", (PyObject *)&pgMask_Type) == -1) {
2646 DECREF_MOD(module);
2647 MODINIT_ERROR;
2648 }
2649
2650 /* export the c api */
2651 c_api[0] = &pgMask_Type;
2652 apiobj = encapsulate_api(c_api, "mask");
2653 if (apiobj == NULL) {
2654 DECREF_MOD(module);
2655 MODINIT_ERROR;
2656 }
2657 if (PyModule_AddObject(module, PYGAMEAPI_LOCAL_ENTRY, apiobj) == -1) {
2658 Py_DECREF(apiobj);
2659 DECREF_MOD(module);
2660 MODINIT_ERROR;
2661 }
2662 MODINIT_RETURN(module);
2663 }
2664