Mercurial > pygame
view src/pixelarray.c @ 1849:301bc61643a9 math_module
merged changes from trunk
| author | lorenz |
|---|---|
| date | Mon, 16 Nov 2009 18:31:40 +0000 |
| parents | 02c1e8e9c102 |
| children | 42e2bde1a12c |
line wrap: on
line source
/* pygame - Python Game Library Copyright (C) 2007-2008 Marcus von Appen This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define PYGAMEAPI_PIXELARRAY_INTERNAL #include "pygame.h" #include "pgcompat.h" #include "doc/pixelarray_doc.h" #include "surface.h" #if PY_VERSION_HEX < 0x02050000 #define PyIndex_Check(op) 0 #endif typedef struct { PyObject_HEAD PyObject *dict; /* dict for subclassing */ PyObject *weakrefs; /* Weakrefs for subclassing */ PyObject *surface; /* Surface associated with the array. */ PyObject *lock; /* Lock object for the surface. */ Uint32 xstart; /* X offset for subarrays */ Uint32 ystart; /* Y offset for subarrays */ Uint32 xlen; /* X segment length. */ Uint32 ylen; /* Y segment length. */ Sint32 xstep; /* X offset step width. */ Sint32 ystep; /* Y offset step width. */ Uint32 padding; /* Padding to get to the next x offset. */ PyObject *parent; /* Parent pixel array */ } PyPixelArray; static PyPixelArray* _pxarray_new_internal (PyTypeObject *type, PyObject *surface, Uint32 xstart, Uint32 ystart, Uint32 xlen, Uint32 ylen, Sint32 xstep, Sint32 ystep, Uint32 padding, PyObject *parent); static PyObject* _pxarray_new (PyTypeObject *type, PyObject *args, PyObject *kwds); static void _pxarray_dealloc (PyPixelArray *self); static PyObject* _pxarray_get_dict (PyPixelArray *self, void *closure); static PyObject* _pxarray_get_surface (PyPixelArray *self, void *closure); static PyObject* _pxarray_repr (PyPixelArray *array); static PyObject* _array_slice_internal (PyPixelArray *array, Sint32 _start, Sint32 _end, Sint32 _step); /* Sequence methods */ static Py_ssize_t _pxarray_length (PyPixelArray *array); static PyObject* _pxarray_item (PyPixelArray *array, Py_ssize_t _index); #if !PY3 static PyObject* _pxarray_slice (PyPixelArray *array, Py_ssize_t low, Py_ssize_t high); #endif static int _array_assign_array (PyPixelArray *array, Py_ssize_t low, Py_ssize_t high, PyPixelArray *val); static int _array_assign_sequence (PyPixelArray *array, Py_ssize_t low, Py_ssize_t high, PyObject *val); static int _array_assign_slice (PyPixelArray *array, Py_ssize_t low, Py_ssize_t high, Uint32 color); static int _pxarray_ass_item (PyPixelArray *array, Py_ssize_t _index, PyObject *value); static int _pxarray_ass_slice (PyPixelArray *array, Py_ssize_t low, Py_ssize_t high, PyObject *value); static int _pxarray_contains (PyPixelArray *array, PyObject *value); static PyObject* _pxarray_iter (PyPixelArray *array); /* Mapping methods */ static int _get_subslice (PyObject *op, Py_ssize_t length, Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step); static PyObject* _pxarray_subscript (PyPixelArray *array, PyObject *op); static int _pxarray_ass_subscript (PyPixelArray *array, PyObject* op, PyObject* value); /* C API interfaces */ static PyObject* PyPixelArray_New (PyObject *surfobj); /* Incomplete forward declaration so we can use it in the methods included * below. */ static PyTypeObject PyPixelArray_Type; #define PyPixelArray_Check(o) \ (Py_TYPE (o) == (PyTypeObject *) &PyPixelArray_Type) #define SURFACE_EQUALS(x,y) \ (((PyPixelArray *)x)->surface == ((PyPixelArray *)y)->surface) #include "pixelarray_methods.c" /** * Methods, which are bound to the PyPixelArray type. */ static PyMethodDef _pxarray_methods[] = { { "compare", (PyCFunction) _compare, METH_VARARGS | METH_KEYWORDS, DOC_PIXELARRAYCOMPARE }, { "extract", (PyCFunction) _extract_color, METH_VARARGS | METH_KEYWORDS, DOC_PIXELARRAYEXTRACT }, { "make_surface", (PyCFunction) _make_surface, METH_VARARGS | METH_NOARGS, DOC_PIXELARRAYMAKESURFACE }, { "replace", (PyCFunction) _replace_color, METH_VARARGS | METH_KEYWORDS, DOC_PIXELARRAYREPLACE }, { NULL, NULL, 0, NULL } }; #if PY3 static void Text_ConcatAndDel (PyObject **string, PyObject *newpart) { PyObject *result = NULL; if (*string != NULL && newpart != NULL) { PyUnicode_Concat (*string, newpart); Py_DECREF (*string); Py_DECREF (newpart); } else { Py_XDECREF (*string); Py_XDECREF (newpart); } *string = result; } #else #define Text_ConcatAndDel PyString_ConcatAndDel #endif /** * Getters and setters for the PyPixelArray. */ static PyGetSetDef _pxarray_getsets[] = { { "__dict__", (getter) _pxarray_get_dict, NULL, NULL, NULL }, { "surface", (getter) _pxarray_get_surface, NULL, DOC_PIXELARRAYSURFACE, NULL }, { NULL, NULL, NULL, NULL, NULL } }; /** * Sequence interface support for the PyPixelArray. * concat and repeat are not implemented due to the possible confusion * of their behaviour (see lists numpy array). */ static PySequenceMethods _pxarray_sequence = { (lenfunc) _pxarray_length, /*sq_length*/ NULL, /*sq_concat*/ NULL, /*sq_repeat*/ (ssizeargfunc) _pxarray_item, /*sq_item*/ #if PY3 NULL, #else (ssizessizeargfunc) _pxarray_slice, /*sq_slice*/ #endif (ssizeobjargproc) _pxarray_ass_item, /*sq_ass_item*/ #if PY3 NULL, #else (ssizessizeobjargproc) _pxarray_ass_slice, /*sq_ass_slice*/ #endif (objobjproc) _pxarray_contains, /*sq_contains*/ NULL, /*sq_inplace_concat*/ NULL, /*sq_inplace_repeat*/ }; /** * Mapping interface support for the PyPixelArray. */ static PyMappingMethods _pxarray_mapping = { (inquiry) _pxarray_length, /*mp_length*/ (binaryfunc) _pxarray_subscript, /*mp_subscript*/ (objobjargproc) _pxarray_ass_subscript, /*mp_ass_subscript*/ }; static PyTypeObject PyPixelArray_Type = { TYPE_HEAD (NULL, 0) "pygame.PixelArray", /* tp_name */ sizeof (PyPixelArray), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor) _pxarray_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ (reprfunc) _pxarray_repr, /* tp_repr */ 0, /* tp_as_number */ &_pxarray_sequence, /* tp_as_sequence */ &_pxarray_mapping, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_WEAKREFS, DOC_PYGAMEPIXELARRAY, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ offsetof (PyPixelArray, weakrefs), /* tp_weaklistoffset */ (getiterfunc) _pxarray_iter, /* tp_iter */ 0, /* tp_iternext */ _pxarray_methods, /* tp_methods */ 0, /* tp_members */ _pxarray_getsets, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ offsetof (PyPixelArray, dict), /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ _pxarray_new, /* tp_new */ #ifndef __SYMBIAN32__ 0, /* tp_free */ 0, /* tp_is_gc */ 0, /* tp_bases */ 0, /* tp_mro */ 0, /* tp_cache */ 0, /* tp_subclasses */ 0, /* tp_weaklist */ 0 /* tp_del */ #endif }; static PyPixelArray* _pxarray_new_internal (PyTypeObject *type, PyObject *surface, Uint32 xstart, Uint32 ystart, Uint32 xlen, Uint32 ylen, Sint32 xstep, Sint32 ystep, Uint32 padding, PyObject *parent) { PyPixelArray *self = (PyPixelArray *) type->tp_alloc (type, 0); if (!self) return NULL; self->surface = (PyObject *) surface; self->lock = NULL; self->parent = NULL; Py_INCREF (surface); if (!parent) { /* Initial PixelArray */ if (surface) { self->lock = PySurface_LockLifetime (surface, (PyObject *) self); if (!self->lock) { Py_DECREF (surface); Py_TYPE (self)->tp_free ((PyObject *) self); return NULL; } } } else { self->parent = parent; Py_INCREF (parent); self->lock = ((PyPixelArray *)parent)->lock; Py_INCREF (self->lock); } self->weakrefs = NULL; self->dict = NULL; self->xstart = xstart; self->ystart = ystart; self->xlen = xlen; self->ylen = ylen; self->xstep = xstep; self->ystep = ystep; self->padding = padding; return self; } /** * Creates a new PyPixelArray. */ static PyObject* _pxarray_new (PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *surfobj; SDL_Surface* surface; if (!PyArg_ParseTuple (args, "O!", &PySurface_Type, &surfobj)) return NULL; surface = PySurface_AsSurface (surfobj); if (surface->format->BytesPerPixel < 1 || surface->format->BytesPerPixel > 4) return RAISE (PyExc_ValueError, "unsupport bit depth for reference array"); return (PyObject *) _pxarray_new_internal (type, surfobj, 0, 0, (Uint32) surface->w, (Uint32) surface->h, 1, 1, surface->pitch, NULL); } /** * Deallocates the PyPixelArray and its members. */ static void _pxarray_dealloc (PyPixelArray *self) { if (self->weakrefs) PyObject_ClearWeakRefs ((PyObject *) self); Py_XDECREF (self->lock); Py_XDECREF (self->parent); Py_XDECREF (self->dict); Py_DECREF (self->surface); Py_TYPE (self)->tp_free ((PyObject *) self); } /**** Getter and setter access ****/ /** * Getter for PixelArray.__dict__. */ static PyObject* _pxarray_get_dict (PyPixelArray *self, void *closure) { if (!self->dict) { self->dict = PyDict_New (); if (!self->dict) return NULL; } Py_INCREF (self->dict); return self->dict; } /** * Getter for PixelArray.surface */ static PyObject* _pxarray_get_surface (PyPixelArray *self, void *closure) { Py_XINCREF (self->surface); return self->surface; } /**** Methods ****/ /** * repr(PixelArray) */ static PyObject* _pxarray_repr (PyPixelArray *array) { PyObject *string; SDL_Surface *surface; int bpp; Uint8 *pixels; Uint8 *px24; Uint32 pixel; Uint32 x = 0; Uint32 y = 0; Sint32 xlen = 0; Sint32 absxstep; Sint32 absystep; Uint32 posx = 0; Uint32 posy = 0; surface = PySurface_AsSurface (array->surface); bpp = surface->format->BytesPerPixel; pixels = (Uint8 *) surface->pixels; /* printf ("::ARRAY: %d:%d:%d, %d:%d:%d %d\n", array->xstart, array->xlen, array->xstep, array->ystart, array->ylen, array->ystep, array->padding); */ string = Text_FromUTF8 ("PixelArray("); absxstep = ABS (array->xstep); absystep = ABS (array->ystep); xlen = (Sint32) array->xlen - absxstep; y = array->ystart; switch (bpp) { case 1: while (posy < array->ylen) { /* Construct the rows */ Text_ConcatAndDel (&string, Text_FromUTF8 ("\n [")); if (string == NULL) { return NULL; } posx = 0; x = array->xstart; while (posx < (Uint32)xlen) { /* Construct the columns */ pixel = (Uint32) *((Uint8 *) pixels + x + y * array->padding); Text_ConcatAndDel (&string, Text_FromFormat ("%ld, ", (long)pixel)); if (string == NULL) { return NULL; } x += array->xstep; posx += absxstep; } pixel = (Uint32) *((Uint8 *) pixels + x + y * array->padding); Text_ConcatAndDel (&string, Text_FromFormat ("%ld]", (long)pixel)); if (string == NULL) { return NULL; } y += array->ystep; posy += absystep; } break; case 2: while (posy < array->ylen) { /* Construct the rows */ Text_ConcatAndDel (&string, Text_FromUTF8 ("\n [")); if (string == NULL) { return NULL; } posx = 0; x = array->xstart; while (posx < (Uint32)xlen) { /* Construct the columns */ pixel = (Uint32) *((Uint16 *) (pixels + y * array->padding) + x); Text_ConcatAndDel (&string, Text_FromFormat ("%ld, ", (long)pixel)); if (string == NULL) { return NULL; } x += array->xstep; posx += absxstep; } pixel = (Uint32) *((Uint16 *) (pixels + y * array->padding) + x); Text_ConcatAndDel (&string, Text_FromFormat ("%ld]", (long)pixel)); if (string == NULL) { return NULL; } y += array->ystep; posy += absystep; } break; case 3: while (posy < array->ylen) { /* Construct the rows */ Text_ConcatAndDel (&string, Text_FromUTF8 ("\n [")); if (string == NULL) { return NULL; } posx = 0; x = array->xstart; while (posx < (Uint32)xlen) { /* Construct the columns */ px24 = ((Uint8 *) (pixels + y * array->padding) + x * 3); #if SDL_BYTEORDER == SDL_LIL_ENDIAN pixel = (px24[0]) + (px24[1] << 8) + (px24[2] << 16); #else pixel = (px24[2]) + (px24[1] << 8) + (px24[0] << 16); #endif Text_ConcatAndDel (&string, Text_FromFormat ("%ld, ", (long)pixel)); if (string == NULL) { return NULL; } x += array->xstep; posx += absxstep; } px24 = ((Uint8 *) (pixels + y * array->padding) + x * 3); #if SDL_BYTEORDER == SDL_LIL_ENDIAN pixel = (px24[0]) + (px24[1] << 8) + (px24[2] << 16); #else pixel = (px24[2]) + (px24[1] << 8) + (px24[0] << 16); #endif Text_ConcatAndDel (&string, Text_FromFormat ("%ld]", (long)pixel)); if (string == NULL) { return NULL; } y += array->ystep; posy += absystep; } break; default: /* 4bpp */ while (posy < array->ylen) { /* Construct the rows */ Text_ConcatAndDel (&string, Text_FromUTF8 ("\n [")); if (string == NULL) { return NULL; } posx = 0; x = array->xstart; while (posx < (Uint32)xlen) { /* Construct the columns */ pixel = *((Uint32 *) (pixels + y * array->padding) + x); Text_ConcatAndDel (&string, Text_FromFormat ("%ld, ", (long)pixel)); if (string == NULL) { return NULL; } x += array->xstep; posx += absxstep; } pixel = *((Uint32 *) (pixels + y * array->padding) + x); Text_ConcatAndDel (&string, Text_FromFormat ("%ld]", (long)pixel)); if (string == NULL) { return NULL; } y += array->ystep; posy += absystep; } break; } Text_ConcatAndDel (&string, Text_FromUTF8 ("\n)")); return string; } /** * Creates a 2D slice of the array. */ static PyObject* _array_slice_internal (PyPixelArray *array, Sint32 _start, Sint32 _end, Sint32 _step) { Uint32 xstart = 0; Uint32 ystart = 0; Uint32 xlen; Uint32 ylen; Sint32 xstep; Sint32 ystep; Uint32 padding; if (_end == _start) return RAISE (PyExc_IndexError, "array size must not be 0"); if (array->xlen == 1) { ystart = array->ystart + _start * array->ystep; xstart = array->xstart; xlen = array->xlen; ylen = ABS (_end - _start); ystep = _step; xstep = array->xstep; padding = array->padding; /* Out of bounds? */ if (_start >= (Sint32) array->ylen && ystep > 0) return RAISE (PyExc_IndexError, "array index out of range"); } else { xstart = array->xstart + _start * array->xstep; ystart = array->ystart; xlen = ABS (_end - _start); ylen = array->ylen; xstep = _step; ystep = array->ystep; padding = array->padding; /* Out of bounds? */ if (_start >= (Sint32) array->xlen && xstep > 0) return RAISE (PyExc_IndexError, "array index out of range"); } /* printf ("VALS: %d:%d, %d:%d %d:%d %d\n", xstart, ystart, xlen, xstep, ylen, ystep, padding); */ return (PyObject *) _pxarray_new_internal (&PyPixelArray_Type, array->surface, xstart, ystart, xlen, ylen, xstep, ystep, padding, (PyObject *) array); } /**** Sequence interfaces ****/ /** * len (array) */ static Py_ssize_t _pxarray_length (PyPixelArray *array) { if (array->xlen > 1) return array->xlen / ABS (array->xstep); return array->ylen / ABS (array->ystep); } /** * array[x] */ static PyObject* _pxarray_item (PyPixelArray *array, Py_ssize_t _index) { SDL_Surface *surface; int bpp; if (_index < 0) return RAISE (PyExc_IndexError, "array index out of range"); surface = PySurface_AsSurface (array->surface); bpp = surface->format->BytesPerPixel; /* Access of a single column. */ if (array->xlen == 1) { if ((Uint32) _index >= array->ystart + array->ylen) return RAISE (PyExc_IndexError, "array index out of range"); return _get_single_pixel ((Uint8 *) surface->pixels, bpp, array->xstart, _index * array->padding * array->ystep); } if (array->ylen == 1) { if ((Uint32) _index >= array->xstart + array->xlen) return RAISE (PyExc_IndexError, "array index out of range"); return _get_single_pixel ((Uint8 *) surface->pixels, bpp, array->xstart + _index * array->xstep, array->ystart * array->padding * array->ystep); } return _array_slice_internal (array, _index, _index + 1, 1); } #if !PY3 /** * array[x:y] */ static PyObject* _pxarray_slice (PyPixelArray *array, Py_ssize_t low, Py_ssize_t high) { if (low < 0) low = 0; else if (low > (Sint32) array->xlen) low = array->xlen; if (high < low) high = low; else if (high > (Sint32) array->xlen) high = array->xlen; if (low == high) Py_RETURN_NONE; return _array_slice_internal (array, low, high, 1); } #endif static int _array_assign_array (PyPixelArray *array, Py_ssize_t low, Py_ssize_t high, PyPixelArray *val) { SDL_Surface *surface; SDL_Surface *valsf = NULL; Uint32 x = 0; Uint32 y = 0; Uint32 vx = 0; Uint32 vy = 0; int bpp; int valbpp; Uint8 *pixels; Uint8 *valpixels; int copied = 0; Uint32 xstart = 0; Uint32 ystart = 0; Uint32 xlen; Uint32 ylen; Sint32 xstep; Sint32 ystep; Uint32 padding; Uint32 posx = 0; Uint32 posy = 0; Sint32 absxstep; Sint32 absystep; /* Set the correct slice indices */ surface = PySurface_AsSurface (array->surface); if (array->xlen == 1) { xstart = array->xstart; ystart = array->ystart + low * array->ystep; xlen = array->xlen; ylen = ABS (high - low); ystep = array->ystep; xstep = array->xstep; padding = array->padding; } else { xstart = array->xstart + low * array->xstep; ystart = array->ystart; xlen = ABS (high - low); ylen = array->ylen; xstep = array->xstep; ystep = array->ystep; padding = array->padding; } /* printf ("ARRAY: %d:%d:%d, %d:%d:%d -- VAL: %d:%d:%d, %d:%d:%d\n", xstart, xlen, xstep, ystart, ylen, ystep, val->xstart, val->xlen, val->xstep, val->ystart, val->ylen, val->ystep); */ if (val->ylen / ABS (val->ystep) != ylen / ABS (ystep) || val->xlen / ABS (val->xstep) != xlen / ABS (xstep)) { /* Bounds do not match. */ PyErr_SetString (PyExc_ValueError, "array sizes do not match"); return -1; } valsf = PySurface_AsSurface (val->surface); bpp = surface->format->BytesPerPixel; valbpp = valsf->format->BytesPerPixel; pixels = (Uint8 *) surface->pixels; valpixels = valsf->pixels; if (bpp != valbpp) { /* bpp do not match. We cannot guarantee that the padding and co * would be set correctly. */ PyErr_SetString (PyExc_ValueError, "bit depths do not match"); return -1; } /* If we reassign the same array, we need to copy the pixels * first. */ if (SURFACE_EQUALS (array, val)) { /* We assign a different view or so. Copy the source buffer. */ valpixels = malloc ((size_t) (surface->pitch * surface->h)); if (!valpixels) { PyErr_SetString (PyExc_ValueError, "could not copy pixels"); return -1; } valpixels = memcpy (valpixels, pixels, (size_t) (surface->pitch * surface->h)); copied = 1; } absxstep = ABS (xstep); absystep = ABS (ystep); y = ystart; vy = val->ystart; Py_BEGIN_ALLOW_THREADS; /* Single value assignment. */ switch (bpp) { case 1: while (posy < ylen) { vx = val->xstart; posx = 0; x = xstart; while (posx < xlen) { *((Uint8 *) pixels + y * padding + x) = (Uint8)*((Uint8 *) valpixels + vy * val->padding + vx); vx += val->xstep; x += xstep; posx += absxstep; } vy += val->ystep; y += ystep; posy += absystep; } break; case 2: while (posy < ylen) { vx = val->xstart; posx = 0; x = xstart; while (posx < xlen) { *((Uint16 *) (pixels + y * padding) + x) = (Uint16)*((Uint16 *) (valpixels + vy * val->padding) + vx); vx += val->xstep; x += xstep; posx += absxstep; } vy += val->ystep; y += ystep; posy += absystep; } break; case 3: { Uint8 *px; Uint8 *vpx; SDL_PixelFormat *format = surface->format; SDL_PixelFormat *vformat = valsf->format; while (posy < ylen) { vx = val->xstart; posx = 0; x = xstart; while (posx < xlen) { px = ((Uint8 *) (pixels + y * padding) + x * 3); vpx = ((Uint8 *) (valpixels + vy * val->padding) + vx * 3); #if (SDL_BYTEORDER == SDL_LIL_ENDIAN) *(px + (format->Rshift >> 3)) = *(vpx + (vformat->Rshift >> 3)); *(px + (format->Gshift >> 3)) = *(vpx + (vformat->Gshift >> 3)); *(px + (format->Bshift >> 3)) = *(vpx + (vformat->Bshift >> 3)); #else *(px + 2 - (format->Rshift >> 3)) = *(vpx + 2 - (vformat->Rshift >> 3)); *(px + 2 - (format->Gshift >> 3)) = *(vpx + 2 - (vformat->Gshift >> 3)); *(px + 2 - (format->Bshift >> 3)) = *(vpx + 2 - (vformat->Bshift >> 3)); #endif vx += val->xstep; x += xstep; posx += absxstep; } vy += val->ystep; y += ystep; posy += absystep; } break; } default: while (posy < ylen) { vx = val->xstart; posx = 0; x = xstart; while (posx < xlen) { *((Uint32 *) (pixels + y * padding) + x) = (Uint32)*((Uint32 *) (valpixels + vy * val->padding) + vx); vx += val->xstep; x += xstep; posx += absxstep; } vy += val->ystep; y += ystep; posy += absystep; } break; } Py_END_ALLOW_THREADS; if (copied) { free (valpixels); } return 0; } static int _array_assign_sequence (PyPixelArray *array, Py_ssize_t low, Py_ssize_t high, PyObject *val) { SDL_Surface *surface; Uint32 x = 0; Uint32 y = 0; int bpp; int gooverx = 0; Uint8 *pixels; Uint32 color = 0; Uint32 *colorvals = NULL; Uint32 *nextcolor = NULL; Py_ssize_t offset = 0; Py_ssize_t seqsize = PySequence_Size (val); Uint32 xstart = 0; Uint32 ystart = 0; Uint32 xlen; Uint32 ylen; Sint32 xstep; Sint32 ystep; Uint32 padding; Uint32 posx = 0; Uint32 posy = 0; Sint32 absxstep; Sint32 absystep; surface = PySurface_AsSurface (array->surface); bpp = surface->format->BytesPerPixel; pixels = (Uint8 *) surface->pixels; /* Set the correct slice indices */ if (array->xlen == 1) { xstart = array->xstart; ystart = array->ystart + low * array->ystep; xlen = array->xlen; ylen = ABS (high - low); ystep = array->ystep; xstep = array->xstep; padding = array->padding; } else { xstart = array->xstart + low * array->xstep; ystart = array->ystart; xlen = ABS (high - low); ylen = array->ylen; xstep = array->xstep; ystep = array->ystep; padding = array->padding; } if ((Uint32)seqsize != ylen / ABS (ystep)) { if ((Uint32)seqsize != xlen / ABS (xstep)) { PyErr_SetString(PyExc_ValueError, "sequence size mismatch"); return -1; } gooverx = 1; /* We have to iterate over the x axis. */ } if (seqsize == 1) { /* Single value assignment. */ _set_single_pixel (pixels, bpp, xstart, ystart + padding * ystep, surface->format, color); return 0; } /* Copy the values. */ colorvals = malloc (sizeof (Uint32) * seqsize); if (!colorvals) { PyErr_SetString (PyExc_ValueError, "could not copy colors"); return -1; } for (offset = 0; offset < seqsize; offset++) { if (!_get_color_from_object (PySequence_Fast_GET_ITEM (val, offset), surface->format, &color)) { free (colorvals); return -1; } colorvals[offset] = color; } absxstep = ABS (xstep); absystep = ABS (ystep); y = ystart; nextcolor = colorvals; Py_BEGIN_ALLOW_THREADS; switch (bpp) { case 1: if (gooverx) { while (posy < ylen) { posx = 0; x = xstart; nextcolor = colorvals; while (posx < xlen) { color = *nextcolor++; *((Uint8 *) pixels + y * padding + x) = (Uint8) color; x += xstep; posx += absxstep; } y += ystep; posy += absystep; } } else { while (posy < ylen) { posx = 0; x = xstart; color = *nextcolor++; while (posx < xlen) { *((Uint8 *) pixels + y * padding + x) = (Uint8) color; x += xstep; posx += absxstep; } y += ystep; posy += absystep; } } break; case 2: if (gooverx) { while (posy < ylen) { posx = 0; x = xstart; nextcolor = colorvals; while (posx < xlen) { color = *nextcolor++; *((Uint16 *) (pixels + y * padding) + x) = (Uint16) color; x += xstep; posx += absxstep; } y += ystep; posy += absystep; } } else { while (posy < ylen) { posx = 0; x = xstart; color = *nextcolor++; while (posx < xlen) { *((Uint16 *) (pixels + y * padding) + x) = (Uint16) color; x += xstep; posx += absxstep; } y += ystep; posy += absystep; } } break; case 3: { Uint8 *px; SDL_PixelFormat *format = surface->format; if (gooverx) { while (posy < ylen) { posx = 0; x = xstart; nextcolor = colorvals; while (posx < xlen) { color = *nextcolor++; px = ((Uint8 *) (pixels + y * padding) + x * 3); #if (SDL_BYTEORDER == SDL_LIL_ENDIAN) *(px + (format->Rshift >> 3)) = (Uint8) (color >> 16); *(px + (format->Gshift >> 3)) = (Uint8) (color >> 8); *(px + (format->Bshift >> 3)) = (Uint8) color; #else *(px + 2 - (format->Rshift >> 3)) = (Uint8) (color >> 16); *(px + 2 - (format->Gshift >> 3)) = (Uint8) (color >> 8); *(px + 2 - (format->Bshift >> 3)) = (Uint8) color; #endif x += xstep; posx += absxstep; } y += ystep; posy += absystep; } } else { while (posy < ylen) { posx = 0; x = xstart; color = *nextcolor++; while (posx < xlen) { px = ((Uint8 *) (pixels + y * padding) + x * 3); #if (SDL_BYTEORDER == SDL_LIL_ENDIAN) *(px + (format->Rshift >> 3)) = (Uint8) (color >> 16); *(px + (format->Gshift >> 3)) = (Uint8) (color >> 8); *(px + (format->Bshift >> 3)) = (Uint8) color; #else *(px + 2 - (format->Rshift >> 3)) = (Uint8) (color >> 16); *(px + 2 - (format->Gshift >> 3)) = (Uint8) (color >> 8); *(px + 2 - (format->Bshift >> 3)) = (Uint8) color; #endif x += xstep; posx += absxstep; } y += ystep; posy += absystep; } } break; } default: if (gooverx) { while (posy < ylen) { posx = 0; x = xstart; nextcolor = colorvals; while (posx < xlen) { color = *nextcolor++; *((Uint32 *) (pixels + y * padding) + x) = color; x += xstep; posx += absxstep; } y += ystep; posy += absystep; } } else { while (posy < ylen) { posx = 0; x = xstart; color = *nextcolor++; while (posx < xlen) { *((Uint32 *) (pixels + y * padding) + x) = color; x += xstep; posx += absxstep; } y += ystep; posy += absystep; } } break; } free (colorvals); Py_END_ALLOW_THREADS; return 0; } static int _array_assign_slice (PyPixelArray *array, Py_ssize_t low, Py_ssize_t high, Uint32 color) { SDL_Surface *surface; Uint32 x = 0; Uint32 y = 0; int bpp; Uint8 *pixels; Uint32 xstart = 0; Uint32 ystart = 0; Uint32 xlen; Uint32 ylen; Sint32 xstep; Sint32 ystep; Uint32 padding; Uint32 posx = 0; Uint32 posy = 0; Sint32 absxstep; Sint32 absystep; surface = PySurface_AsSurface (array->surface); bpp = surface->format->BytesPerPixel; pixels = (Uint8 *) surface->pixels; /* Set the correct slice indices */ if (array->xlen == 1) { xstart = array->xstart; ystart = array->ystart + low * array->ystep; xlen = array->xlen; ylen = ABS (high - low); ystep = array->ystep; xstep = array->xstep; padding = array->padding; } else { xstart = array->xstart + low * array->xstep; ystart = array->ystart; xlen = ABS (high - low); ylen = array->ylen; xstep = array->xstep; ystep = array->ystep; padding = array->padding; } absxstep = ABS (xstep); absystep = ABS (ystep); y = ystart; Py_BEGIN_ALLOW_THREADS; /* Single value assignment. */ switch (bpp) { case 1: while (posy < ylen) { posx = 0; x = xstart; while (posx < xlen) { *((Uint8 *) pixels + y * padding + x) = (Uint8) color; x += xstep; posx += absxstep; } y += ystep; posy += absystep; } break; case 2: while (posy < ylen) { posx = 0; x = xstart; while (posx < xlen) { *((Uint16 *) (pixels + y * padding) + x) = (Uint16) color; x += xstep; posx += absxstep; } y += ystep; posy += absystep; } break; case 3: { Uint8 *px; SDL_PixelFormat *format = surface->format; while (posy < ylen) { posx = 0; x = xstart; while (posx < xlen) { px = ((Uint8 *) (pixels + y * padding) + x * 3); #if (SDL_BYTEORDER == SDL_LIL_ENDIAN) *(px + (format->Rshift >> 3)) = (Uint8) (color >> 16); *(px + (format->Gshift >> 3)) = (Uint8) (color >> 8); *(px + (format->Bshift >> 3)) = (Uint8) color; #else *(px + 2 - (format->Rshift >> 3)) = (Uint8) (color >> 16); *(px + 2 - (format->Gshift >> 3)) = (Uint8) (color >> 8); *(px + 2 - (format->Bshift >> 3)) = (Uint8) color; #endif x += xstep; posx += absxstep; } y += ystep; posy += absystep; } break; } default: /* 4 bpp */ while (posy < ylen) { posx = 0; x = xstart; while (posx < xlen) { *((Uint32 *) (pixels + y * padding) + x) = color; x += xstep; posx += absxstep; } y += ystep; posy += absystep; } break; } Py_END_ALLOW_THREADS; return 0; } /** * array[x] = ... */ static int _pxarray_ass_item (PyPixelArray *array, Py_ssize_t _index, PyObject *value) { SDL_Surface *surface; Uint32 x = 0; Uint32 y = 0; int bpp; Uint8 *pixels; Uint32 color = 0; Uint32 xstart = 0; Uint32 ystart = 0; Uint32 xlen; Uint32 ylen; Sint32 xstep; Sint32 ystep; Uint32 padding; Uint32 posx = 0; Uint32 posy = 0; Sint32 absxstep; Sint32 absystep; surface = PySurface_AsSurface (array->surface); bpp = surface->format->BytesPerPixel; pixels = (Uint8 *) surface->pixels; if (!_get_color_from_object (value, surface->format, &color)) { if (PyPixelArray_Check (value)) { PyErr_Clear (); /* _get_color_from_object */ return _array_assign_array (array, _index, _index + 1, (PyPixelArray *) value); } else if (PySequence_Check (value)) { PyErr_Clear (); /* _get_color_from_object */ return _array_assign_sequence (array, _index, _index + 1, value); } else /* Error already set by _get_color_from_object(). */ return -1; } /* Set the correct slice indices */ if (array->xlen == 1) { xstart = array->xstart; ystart = array->ystart + _index * array->ystep; xlen = array->xlen; ylen = 1; ystep = array->ystep; xstep = array->xstep; padding = array->padding; } else { xstart = array->xstart + _index * array->xstep; ystart = array->ystart; xlen = 1; ylen = array->ylen; xstep = array->xstep; ystep = array->ystep; padding = array->padding; } /* printf ("ITEM: %d:%d, %d:%d %d:%d %d\n", xstart, ystart, xlen, xstep, ylen, ystep, padding); */ absxstep = ABS (xstep); absystep = ABS (ystep); y = ystart; Py_BEGIN_ALLOW_THREADS; /* Single value assignment. */ switch (bpp) { case 1: while (posy < ylen) { posx = 0; x = xstart; while (posx < xlen) { *((Uint8 *) pixels + y * padding + x) = (Uint8) color; x += xstep; posx += absxstep; } y += ystep; posy += absystep; } break; case 2: while (posy < ylen) { posx = 0; x = xstart; while (posx < xlen) { *((Uint16 *) (pixels + y * padding) + x) = (Uint16) color; x += xstep; posx += absxstep; } y += ystep; posy += absystep; } break; case 3: { Uint8 *px; SDL_PixelFormat *format = surface->format; while (posy < ylen) { posx = 0; x = xstart; while (posx < xlen) { px = ((Uint8 *) (pixels + y * padding) + x * 3); #if (SDL_BYTEORDER == SDL_LIL_ENDIAN) *(px + (format->Rshift >> 3)) = (Uint8) (color >> 16); *(px + (format->Gshift >> 3)) = (Uint8) (color >> 8); *(px + (format->Bshift >> 3)) = (Uint8) color; #else *(px + 2 - (format->Rshift >> 3)) = (Uint8) (color >> 16); *(px + 2 - (format->Gshift >> 3)) = (Uint8) (color >> 8); *(px + 2 - (format->Bshift >> 3)) = (Uint8) color; #endif x += xstep; posx += absxstep; } y += ystep; posy += absystep; } break; } default: /* 4 bpp */ while (posy < ylen) { posx = 0; x = xstart; while (posx < xlen) { *((Uint32 *) (pixels + y * padding) + x) = color; x += xstep; posx += absxstep; } y += ystep; posy += absystep; } break; } Py_END_ALLOW_THREADS; return 0; } /** * array[x:y] = .... */ static int _pxarray_ass_slice (PyPixelArray *array, Py_ssize_t low, Py_ssize_t high, PyObject *value) { SDL_Surface *surface; Uint32 color; if (array->xlen != 1) { if (low < 0) low = 0; else if (low > (Sint32) array->xlen) low = array->xlen; if (high < low) high = low; else if (high > (Sint32) array->xlen) high = array->xlen; } else { if (low < 0) low = 0; else if (low > (Sint32) array->ylen) low = array->ylen; if (high < low) high = low; else if (high > (Sint32) array->ylen) high = array->ylen; } surface = PySurface_AsSurface (array->surface); /* printf ("SLICE IS: %d:%d\n", low, high); */ if (PyPixelArray_Check (value)) { return _array_assign_array (array, low, high, (PyPixelArray *) value); } else if (_get_color_from_object (value, surface->format, &color)) { return _array_assign_slice (array, low, high, color); } else if (PySequence_Check (value)) { PyErr_Clear (); /* In case _get_color_from_object set it */ return _array_assign_sequence (array, low, high, value); } return 0; } /** * x in array */ static int _pxarray_contains (PyPixelArray *array, PyObject *value) { SDL_Surface *surface; Uint32 x = 0; Uint32 y = 0; Uint8 *pixels; int bpp; Uint32 color; Uint32 posx = 0; Uint32 posy = 0; Sint32 absxstep; Sint32 absystep; int found = 0; surface = PySurface_AsSurface (array->surface); bpp = surface->format->BytesPerPixel; pixels = (Uint8 *) surface->pixels; if (!_get_color_from_object (value, surface->format, &color)) return -1; absxstep = ABS (array->xstep); absystep = ABS (array->ystep); y = array->ystart; Py_BEGIN_ALLOW_THREADS; switch (bpp) { case 1: while (posy < array->ylen && !found) { posx = 0; x = array->xstart; while (posx < array->xlen) { if (*((Uint8 *) pixels + y * array->padding + x) == (Uint8) color) { found = 1; break; } x += array->xstep; posx += absxstep; } y += array->ystep; posy += absystep; } break; case 2: while (posy < array->ylen && !found) { posx = 0; x = array->xstart; while (posx < array->xlen) { if (*((Uint16 *) (pixels + y * array->padding) + x) == (Uint16) color) { found = 1; break; } x += array->xstep; posx += absxstep; } y += array->ystep; posy += absystep; } break; case 3: { Uint32 pxcolor; Uint8 *pix; while (posy < array->ylen && !found) { posx = 0; x = array->xstart; while (posx < array->xlen) { pix = ((Uint8 *) (pixels + y * array->padding) + x * 3); #if SDL_BYTEORDER == SDL_LIL_ENDIAN pxcolor = (pix[0]) + (pix[1] << 8) + (pix[2] << 16); #else pxcolor = (pix[2]) + (pix[1] << 8) + (pix[0] << 16); #endif if (pxcolor == color) { found = 1; break; } x += array->xstep; posx += absxstep; } y += array->ystep; posy += absystep; } break; } default: /* 4 bpp */ while (posy < array->ylen && !found) { posx = 0; x = array->xstart; while (posx < array->xlen) { if (*((Uint32 *) (pixels + y * array->padding) + x) == color) { found = 1; break; } x += array->xstep; posx += absxstep; } y += array->ystep; posy += absystep; } break; } Py_END_ALLOW_THREADS; return found; } /** * iter (arrray), for x in array */ static PyObject* _pxarray_iter (PyPixelArray *array) { /* printf ("Iter ARRAY: %d:%d:%d %d:%d:%d\n", array->xstart, array->xlen, array->xstep, array->ystart, array->ylen, array->ystep); */ return PySeqIter_New ((PyObject *) array); } /**** Mapping interfaces ****/ /** * Internally used parser function for the 2D slices: * array[x,y], array[:,:], ... */ static int _get_subslice (PyObject *op, Py_ssize_t length, Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step) { *start = -1; *stop = -1; *step = -1; if (PySlice_Check (op)) { Py_ssize_t slicelen; /* Operator is a slice: array[x::, */ if (PySlice_GetIndicesEx ((PySliceObject *) op, length, start, stop, step, &slicelen) < 0) { return 0; } } else if (PyInt_Check (op)) { /* Plain index: array[x, */ *start = PyInt_AsLong (op); if (*start < 0) *start += length; if (*start >= length || *start < 0) { PyErr_SetString(PyExc_IndexError, "invalid index"); return 0; } *stop = (*start) + 1; *step = 1; } else if (PyLong_Check (op)) { long long val = -1; /* Plain index: array[x, */ val = PyLong_AsLong (op); if ((val < INT_MIN) || (val > INT_MAX)) { PyErr_SetString(PyExc_ValueError, "index too big for array access"); return 0; } *start = (int) val; if (*start < 0) *start += length; if (*start >= length || *start < 0) { PyErr_SetString(PyExc_IndexError, "invalid index"); return 0; } *stop = (*start) + 1; *step = 1; } return 1; } /** * Slicing support for 1D and 2D access. * array[x,y] is only supported for 2D arrays. */ static PyObject* _pxarray_subscript (PyPixelArray *array, PyObject *op) { SDL_Surface *surface = PySurface_AsSurface (array->surface); /* Note: order matters here. * First check array[x,y], then array[x:y:z], then array[x] * Otherwise it'll fail. */ if (PySequence_Check (op)) { PyObject *obj; Py_ssize_t size = PySequence_Size (op); Py_ssize_t xstart, xstop, xstep; Py_ssize_t ystart, ystop, ystep; Py_ssize_t lenx, leny; if (size == 0) { /* array[,], array[()] ... */ Py_INCREF (array); return (PyObject *) array; } if (size > 2 || (size == 2 && array->xlen == 1)) return RAISE (PyExc_IndexError, "too many indices for the array"); lenx = (array->xlen > 1) ? array->xlen / ABS (array->xstep) : 0; leny = array->ylen / ABS (array->ystep); obj = PySequence_Fast_GET_ITEM (op, 0); if (obj == Py_Ellipsis || obj == Py_None) { /* Operator is the ellipsis or None * array[...,XXX], array[None,XXX] */ xstart = 0; xstop = array->xlen; xstep = array->xstep; } else if (!_get_subslice (obj, lenx, &xstart, &xstop, &xstep)) { /* Error on retrieving the subslice. */ return NULL; } if (size == 2) { obj = PySequence_Fast_GET_ITEM (op, 1); if (obj == Py_Ellipsis || obj == Py_None) { /* Operator is the ellipsis or None * array[XXX,...], array[XXX,None] */ ystart = array->ystart; ystop = array->ylen; ystep = array->ystep; } else if (!_get_subslice (obj, leny, &ystart, &ystop, &ystep)) { /* Error on retrieving the subslice. */ return NULL; } } else { ystart = array->ystart; ystop = array->ylen; ystep = array->ystep; } /* Null value? */ if (xstart == xstop || ystart == ystop) Py_RETURN_NONE; /* printf ("X: %d:%d:%d Y: %d:%d:%d\n", xstart, xstop, xstep, ystart, ystop, ystep); */ /* Single value? */ if (ABS (xstop - xstart) == 1 && ABS (ystop - ystart) == 1) { return _get_single_pixel ((Uint8 *) surface->pixels, surface->format->BytesPerPixel, array->xstart + xstart, ystart * array->padding * array->ystep); } /* printf ("NEW ARRAY: %d:%d:%d %d:%d:%d\n", array->xstart + xstart, ABS (xstop - xstart), xstep, array->ystart + ystart, ABS (ystop - ystart), ystep); */ return (PyObject *) _pxarray_new_internal (&PyPixelArray_Type, array->surface, (Uint32) array->xstart + xstart, (Uint32) array->ystart + ystart, (Uint32) ABS (xstop - xstart), (Uint32) ABS (ystop - ystart), (Sint32) xstep, (Sint32) ystep, (Uint32) array->padding, (PyObject *) array); } else if (PySlice_Check (op)) { /* A slice */ Py_ssize_t slicelen; Py_ssize_t step; Py_ssize_t start; Py_ssize_t stop; int retval; if (array->xlen > 1) { /* 2D array - slice along the x axis */ retval = PySlice_GetIndicesEx ((PySliceObject *) op, (Py_ssize_t) (array->xlen / ABS (array->xstep)), &start, &stop, &step, &slicelen); } else { /* 1D array - use the y axis. */ retval = PySlice_GetIndicesEx ((PySliceObject *) op, (Py_ssize_t) (array->ylen / ABS (array->ystep)), &start, &stop, &step, &slicelen); } if (retval < 0 || slicelen < 0) return NULL; if (slicelen == 0) Py_RETURN_NONE; /* printf ("start: %d, stop: %d, step: %d, len: %d\n", start, stop, step, slicelen); */ return (PyObject *) _array_slice_internal (array, start, stop, step); } else if (PyIndex_Check (op) || PyInt_Check (op) || PyLong_Check (op)) { Py_ssize_t i; #if PY_VERSION_HEX >= 0x02050000 PyObject *val = PyNumber_Index (op); if (!val) return NULL; /* A simple index. */ i = PyNumber_AsSsize_t (val, PyExc_IndexError); #else if (PyInt_Check (op)) i = PyInt_AsLong (op); else i = PyLong_AsLong (op); #endif if (i == -1 && PyErr_Occurred ()) return NULL; if (i < 0) i += (array->xlen > 1) ? array->xlen / ABS (array->xstep) : array->ylen / ABS (array->ystep); return _pxarray_item (array, i); } return RAISE (PyExc_TypeError, "index must be an integer, sequence or slice"); } static int _pxarray_ass_subscript (PyPixelArray *array, PyObject* op, PyObject* value) { /* TODO: by time we can make this faster by avoiding the creation of * temporary subarrays. */ /* Note: order matters here. * First check array[x,y], then array[x:y:z], then array[x] * Otherwise it'll fail. */ if (PySequence_Check (op)) { PyPixelArray *tmparray; PyObject *obj; Py_ssize_t size = PySequence_Size (op); Py_ssize_t xstart, xstop, xstep; Py_ssize_t ystart, ystop, ystep; Py_ssize_t lenx, leny; int retval; if (size == 0) { /* array[,], array[()] ... */ if (array->xlen == 1) return _pxarray_ass_slice (array, 0, (Py_ssize_t) array->ylen, value); else return _pxarray_ass_slice (array, 0, (Py_ssize_t) array->xlen, value); } if (size > 2 || (size == 2 && array->xlen == 1)) { PyErr_SetString (PyExc_IndexError, "too many indices for the array"); return -1; } lenx = (array->xlen > 1) ? array->xlen / ABS (array->xstep) : 0; leny = array->ylen / ABS (array->ystep); obj = PySequence_Fast_GET_ITEM (op, 0); if (obj == Py_Ellipsis || obj == Py_None) { /* Operator is the ellipsis or None * array[...,XXX], array[None,XXX] */ xstart = 0; xstop = array->xlen; xstep = array->xstep; } else if (!_get_subslice (obj, lenx, &xstart, &xstop, &xstep)) { /* Error on retrieving the subslice. */ return -1; } if (size == 2) { obj = PySequence_Fast_GET_ITEM (op, 1); if (obj == Py_Ellipsis || obj == Py_None) { /* Operator is the ellipsis or None * array[XXX,...], array[XXX,None] */ ystart = array->ystart; ystop = array->ylen; ystep = array->ystep; } else if (!_get_subslice (obj, leny, &ystart, &ystop, &ystep)) { /* Error on retrieving the subslice. */ return -1; } } else { ystart = array->ystart; ystop = array->ylen; ystep = array->ystep; } /* Null value? Do nothing then. */ if (xstart == xstop || ystart == ystop) return 0; /* Single value? */ if (ABS (xstop - xstart) == 1 && ABS (ystop - ystart) == 1) { tmparray = _pxarray_new_internal (&PyPixelArray_Type, array->surface, (Uint32) array->xstart + xstart, (Uint32) array->ystart + ystart, 1, 1, 1, 1, (Uint32) array->padding, (PyObject *) array); if (!tmparray) return -1; retval = _pxarray_ass_item (tmparray, 0, value); Py_DECREF (tmparray); return retval; } tmparray =_pxarray_new_internal (&PyPixelArray_Type, array->surface, (Uint32) array->xstart + xstart, (Uint32) array->ystart + ystart, (Uint32) ABS (xstop - xstart), (Uint32) ABS (ystop - ystart), (Sint32) xstep, (Sint32) ystep, (Uint32) array->padding, (PyObject *) array); if (!tmparray) return -1; if (tmparray->xlen == 1) retval = _pxarray_ass_slice (tmparray, 0, (Py_ssize_t) tmparray->ylen, value); else retval = _pxarray_ass_slice (tmparray, 0, (Py_ssize_t) tmparray->xlen, value); Py_DECREF (tmparray); return retval; } else if (PySlice_Check (op)) { /* A slice */ PyPixelArray *tmparray; Py_ssize_t slicelen; Py_ssize_t step; Py_ssize_t start; Py_ssize_t stop; int retval; if (array->xlen > 1) { /* 2D array - slice along the x axis */ retval = PySlice_GetIndicesEx ((PySliceObject *) op, (Py_ssize_t) (array->xlen / ABS (array->xstep)), &start, &stop, &step, &slicelen); } else { /* 1D array - use the y axis. */ retval = PySlice_GetIndicesEx ((PySliceObject *) op, (Py_ssize_t) (array->ylen / ABS (array->ystep)), &start, &stop, &step, &slicelen); } if (retval < 0 || slicelen < 0) return -1; if (slicelen == 0) return 0; /* printf ("start: %d, stop: %d, step: %d, len: %d\n", start, stop, step, slicelen); */ tmparray = (PyPixelArray *) _array_slice_internal (array, start, stop, step); if (!tmparray) return -1; if (tmparray->xlen == 1) retval = _pxarray_ass_slice (tmparray, 0, (Py_ssize_t) tmparray->ylen, value); else retval = _pxarray_ass_slice (tmparray, 0, (Py_ssize_t) tmparray->xlen, value); Py_DECREF (tmparray); return retval; } else if (PyIndex_Check (op) || PyInt_Check (op) || PyLong_Check (op)) { Py_ssize_t i; #if PY_VERSION_HEX >= 0x02050000 PyObject *val = PyNumber_Index (op); if (!val) return -1; /* A simple index. */ i = PyNumber_AsSsize_t (val, PyExc_IndexError); #else if (PyInt_Check (op)) i = PyInt_AsLong (op); else i = PyLong_AsLong (op); #endif if (i == -1 && PyErr_Occurred ()) return -1; if (i < 0) i += (array->xlen > 1) ? array->xlen / ABS (array->xstep) : array->ylen / ABS (array->ystep); return _pxarray_ass_item (array, i, value); } PyErr_SetString (PyExc_TypeError, "index must be an integer, sequence or slice"); return -1; } /**** C API interfaces ****/ static PyObject* PyPixelArray_New (PyObject *surfobj) { SDL_Surface *surface; if (!PySurface_Check (surfobj)) return RAISE (PyExc_TypeError, "argument is no a Surface"); surface = PySurface_AsSurface (surfobj); if (surface->format->BytesPerPixel < 1 || surface->format->BytesPerPixel > 4) return RAISE (PyExc_ValueError, "unsupported bit depth for reference array"); return (PyObject *) _pxarray_new_internal (&PyPixelArray_Type, surfobj, 0, 0, (Uint32) surface->w, (Uint32) surface->h, 1, 1, (Uint32) surface->pitch, NULL); } MODINIT_DEFINE (pixelarray) { PyObject *module; PyObject *dict; PyObject *apiobj; int ecode; static void* c_api[PYGAMEAPI_PIXELARRAY_NUMSLOTS]; #if PY3 static struct PyModuleDef _module = { PyModuleDef_HEAD_INIT, "pixelarray", NULL, -1, NULL, NULL, NULL, NULL, NULL }; #endif /* imported needed apis; Do this first so if there is an error the module is not loaded. */ import_pygame_base (); if (PyErr_Occurred ()) { MODINIT_ERROR; } import_pygame_color(); if (PyErr_Occurred ()) { MODINIT_ERROR; } import_pygame_surface (); if (PyErr_Occurred ()) { MODINIT_ERROR; } /* type preparation */ if (PyType_Ready (&PyPixelArray_Type) < 0) { MODINIT_ERROR; } /* create the module */ #if PY3 module = PyModule_Create (&_module); #else module = Py_InitModule3 (MODPREFIX "pixelarray", NULL, NULL); #endif if (module == NULL) { MODINIT_ERROR; } Py_INCREF (&PyPixelArray_Type); if (PyModule_AddObject (module, "PixelArray", (PyObject *) &PyPixelArray_Type) == -1) { Py_DECREF ((PyObject *) &PyPixelArray_Type); DECREF_MOD (module); MODINIT_ERROR; } PyPixelArray_Type.tp_getattro = PyObject_GenericGetAttr; dict = PyModule_GetDict (module); c_api[0] = &PyPixelArray_Type; c_api[1] = PyPixelArray_New; apiobj = PyCObject_FromVoidPtr (c_api, NULL); if (apiobj == NULL) { DECREF_MOD (module); MODINIT_ERROR; } ecode = PyDict_SetItemString (dict, PYGAMEAPI_LOCAL_ENTRY, apiobj); Py_DECREF (apiobj); if (ecode == -1) { DECREF_MOD (module); MODINIT_ERROR; } MODINIT_RETURN (module); }
