Mercurial > pygame
diff src/pixelarray.c @ 852:4db78800a93a
A PixelArray class, which is meant to replace surfarray.
It acts as a buffer for surface data.
Written by Marcus.
It's not quite complete, but basic functionality is implemented.
| author | Rene Dudfield <renesd@gmail.com> |
|---|---|
| date | Wed, 22 Aug 2007 08:10:12 +0000 |
| parents | |
| children | 41b22371307e |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pixelarray.c Wed Aug 22 08:10:12 2007 +0000 @@ -0,0 +1,1269 @@ +/* + pygame - Python Game Library + Copyright (C) 2007 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 + +*/ + +#include "pygame.h" +#include "pygamedocs.h" +#include "surface.h" + +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 start; /* Start offset for subarrays */ + Uint32 end; /* End offset for subarrays */ + Uint32 xlen; /* X segment length. */ + Uint32 ylen; /* Y segment length. */ + Uint32 xstep; /* X offset step width. */ + Uint32 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 start, Uint32 end, + Uint32 xlen, Uint32 ylen, + Uint32 xstep, Uint32 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 int _get_color_from_object (PyObject *val, SDL_PixelFormat *format, + Uint32 *color); +static PyObject* _get_single_pixel (Uint8 *pixels, int bpp, Uint32 _index); +static void _set_single_pixel (Uint8 *pixels, int bpp, Uint32 _index, + Uint32 color); +static PyObject* _array_slice_internal (PyPixelArray *array, Uint32 _start, + Uint32 _end, Uint32 _step); + +/* Sequence methods */ +static Py_ssize_t _pxarray_length (PyPixelArray *array); +static PyObject* _pxarray_concat (PyPixelArray *array, PyObject *value); +static PyObject* _pxarray_repeat (PyPixelArray *a, Py_ssize_t n); +static PyObject* _pxarray_item (PyPixelArray *array, Py_ssize_t _index); +static PyObject* _pxarray_slice (PyPixelArray *array, Py_ssize_t low, + Py_ssize_t high); +static int _array_assign_array (PyPixelArray *array, Py_ssize_t _index, + PyPixelArray *val); +static int _array_assign_sequence (PyPixelArray *array, Py_ssize_t _index, + PyObject *val); +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_inplace_concat (PyPixelArray *array, PyObject *seq); +static PyObject* _pxarray_inplace_repeat (PyPixelArray *array, Py_ssize_t n); + +/* Mapping methods */ +/* +static int _get_subslice (SDL_Surface *surface, PyObject *op, 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); +*/ +/* Buffer methods */ +static Py_ssize_t _pxarray_getreadbuf (PyPixelArray *array, Py_ssize_t _index, + const void **ptr); +static Py_ssize_t _pxarray_getwritebuf (PyPixelArray *array, Py_ssize_t _index, + const void **ptr); +static Py_ssize_t _pxarray_getsegcount (PyPixelArray *array, Py_ssize_t *lenp); + +/** + * Methods, which are bound to the PyPixelArray type. + */ +static PyMethodDef _pxarray_methods[] = +{ + { NULL, NULL, 0, NULL } +}; + +/** + * Getters and setters for the PyPixelArray. + */ +static PyGetSetDef _pxarray_getsets[] = +{ + { "__dict__", (getter) _pxarray_get_dict, NULL, NULL, NULL }, + { "surface", (getter) _pxarray_get_surface, NULL, NULL, + DOC_PIXELARRAYSURFACE }, + { NULL, NULL, NULL, NULL, NULL } +}; + +/** + * Sequence interface support for the PyPixelArray. + */ +static PySequenceMethods _pxarray_sequence = +{ + (lenfunc) _pxarray_length, /*sq_length*/ + NULL, /*(binaryfunc) _pxarray_concat,*/ /*sq_concat*/ + (ssizeargfunc) _pxarray_repeat, /*sq_repeat*/ + (ssizeargfunc) _pxarray_item, /*sq_item*/ + NULL, /*(ssizessizeargfunc) _pxarray_slice,*/ /*sq_slice*/ + (ssizeobjargproc) _pxarray_ass_item, /*sq_ass_item*/ + NULL, /*(ssizessizeobjargproc) _pxarray_ass_slice,*/ /*sq_ass_slice*/ + (objobjproc) _pxarray_contains, /*sq_contains*/ + NULL, /*(binaryfunc) _pxarray_inplace_concat,*/ /*sq_inplace_concat*/ + NULL, /*(ssizeargfunc) _pxarray_inplace_repeat*/ /*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*\/ */ +/* }; */ + +/** + * Buffer interface support for the PyPixelArray. + */ +static PyBufferProcs _pxarray_as_buffer = +{ + (readbufferproc) _pxarray_getreadbuf, + (writebufferproc) _pxarray_getwritebuf, + (segcountproc) _pxarray_getsegcount, + NULL, +}; + +static PyTypeObject PyPixelArray_Type = +{ + PyObject_HEAD_INIT(NULL) + 0, + "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 */ + 0, /*&_pxarray_mapping ,*/ /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + &_pxarray_as_buffer, /* 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 */ + 0, /* 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 */ + 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 */ +}; + +#define PyPixelArray_Check(o) \ + ((o)->ob_type == (PyTypeObject *) &PyPixelArray_Type) + +static PyPixelArray* +_pxarray_new_internal (PyTypeObject *type, PyObject *surface, + Uint32 start, Uint32 end, Uint32 xlen, Uint32 ylen, + Uint32 xstep, Uint32 ystep, Uint32 padding, + PyObject *parent) +{ + PyPixelArray *self = (PyPixelArray *) type->tp_alloc (type, 0); + if (!self) + return NULL; + + self->surface = (PyObject *) surface; + if (surface) + { + self->lock = PySurface_LockLifetime (surface); + if (!self->lock) + { + self->ob_type->tp_free ((PyObject *) self); + return NULL; + } + } + self->weakrefs = NULL; + self->dict = NULL; + self->start = start; + self->end = end; + self->xlen = xlen; + self->ylen = ylen; + self->xstep = xstep; + self->ystep = ystep; + self->padding = padding; + self->parent = parent; + 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, (Uint32) surface->w * surface->h, + (Uint32) surface->w, (Uint32) surface->h, 1, 1, (Uint32) surface->w, + NULL); +} + +/** + * Deallocates the PyPixelArray and its members. + */ +static void +_pxarray_dealloc (PyPixelArray *self) +{ + if (self->weakrefs) + PyObject_ClearWeakRefs ((PyObject *) self); + if (self->lock) + { + Py_DECREF (self->lock); + } + Py_XDECREF (self->dict); + self->ob_type->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; + Uint32 pixel; + Uint32 x = 0; + Uint32 y = 0; + + surface = PySurface_AsSurface (array->surface); + bpp = surface->format->BytesPerPixel; + pixels = (Uint8 *) surface->pixels; + + string = PyString_FromString ("PixelArray("); + switch (bpp) + { + case 1: + break; + case 2: + break; + case 3: + { + /* TODO: is this correct? */ + Uint8 *px; + px = ((Uint8 *) pixels + y * array->xstep); +#if SDL_BYTEORDER == SDL_LIL_ENDIAN + pixel = (px[0]) + (px[1] << 8) + (px[2] << 16); +#else + pixel = (px[2]) + (px[1] << 8) + (px[0] << 16); +#endif + break; + } + default: /* 4bpp */ + for (y = 0; y < array->ylen; y += array->ystep) + { + /* Construct the rows */ + PyString_ConcatAndDel (&string, PyString_FromString ("\n [")); + + for (x = 0; x < array->xlen - array->xstep; x += array->xstep) + { + /* Construct the columns */ + pixel = *((Uint32 *) pixels + array->start + x + + y * array->padding); + PyString_ConcatAndDel (&string, PyString_FromFormat + ("%d, ", pixel)); + } + pixel = *((Uint32 *) pixels + array->start + x +y * array->padding); + PyString_ConcatAndDel (&string, PyString_FromFormat ("%d]", pixel)); + } + break; + } + PyString_ConcatAndDel (&string, PyString_FromString ("\n)")); + return string; +} + +/** + * Tries to retrieve a valid color for a Surface. + */ +static int +_get_color_from_object (PyObject *val, SDL_PixelFormat *format, Uint32 *color) +{ + Uint8 rgba[4]; + + if (PyInt_Check (val)) + { + int intval = PyInt_AsLong (val); + if (intval < 0) + { + if (!PyErr_Occurred ()) + PyErr_SetString (PyExc_ValueError, "invalid color argument"); + return 0; + } + *color = (Uint32) intval; + return 1; + } + else if (PyLong_Check (val)) + { + long long longval = -1; + /* Plain index: array[x, */ + + longval = PyLong_AsLong (val); + if ((longval < INT_MIN) || (longval > INT_MAX)) + { + PyErr_SetString(PyExc_ValueError, "index too big for array access"); + return 0; + } + *color = (Uint32) longval; + return 1; + } + else if (RGBAFromObj (val, rgba)) + { + *color = (Uint32) SDL_MapRGBA + (format, rgba[0], rgba[1], rgba[2], rgba[3]); + return 1; + } + else + PyErr_SetString (PyExc_ValueError, "invalid color argument"); + return 0; +} + +/** + * Retrieves a single pixel located at index from the surface pixel + * array. + */ +static PyObject* +_get_single_pixel (Uint8 *pixels, int bpp, Uint32 _index) +{ + Uint32 pixel; + + switch (bpp) + { + case 1: + pixel = (Uint32)*((Uint8 *) pixels + _index); + break; + case 2: + pixel = (Uint32)*((Uint16 *) pixels + _index); + break; + case 3: + { + /* TODO: is this correct? */ + Uint8 *px = ((Uint8 *) pixels + _index); +#if SDL_BYTEORDER == SDL_LIL_ENDIAN + pixel = (px[0]) + (px[1] << 8) + (px[2] << 16); +#else + pixel = (px[2]) + (px[1] << 8) + (px[0] << 16); +#endif + break; + } + default: /* 4 bpp */ + pixel = *((Uint32 *) pixels + _index); + break; + } + + return PyInt_FromLong ((long)pixel); +} + +/** + * Sets a single pixel located at index from the surface pixel array. + */ +static void +_set_single_pixel (Uint8 *pixels, int bpp, Uint32 _index, Uint32 color) +{ + Uint32 pixel; + + switch (bpp) + { + case 1: + *((Uint8 *) pixels + _index) = (Uint8) color; + break; + case 2: + *((Uint16 *) pixels + _index) = (Uint16) color; + break; + case 3: + { + /* TODO: is this correct? */ + Uint8 *px = ((Uint8 *) pixels + _index); +#if SDL_BYTEORDER == SDL_LIL_ENDIAN + pixel = (px[0]) + (px[1] << 8) + (px[2] << 16); +#else + pixel = (px[2]) + (px[1] << 8) + (px[0] << 16); +#endif + break; + } + default: /* 4 bpp */ + *((Uint32 *) pixels + _index) = color; + break; + } +} + +/** + * Creates a 2D slice of the array. + */ +static PyObject* +_array_slice_internal (PyPixelArray *array, Uint32 _start, Uint32 _end, + Uint32 _step) +{ + Uint32 start; + Uint32 end; + Uint32 xlen; + Uint32 ylen; + Uint32 xstep; + Uint32 ystep; + Uint32 padding; + + start = array->start + _start; + end = array->end - array->xlen + _start; + + ylen = array->ylen; + ystep = array->ystep; + + xlen = _end - _start + 1; + xstep = _step; + + padding = array->xlen - xlen + 1; + + return (PyObject *) _pxarray_new_internal + (&PyPixelArray_Type, array->surface, start, end, 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 / array->xstep; + return array->ylen / array->ystep; +} + +/** + * TODO + */ +static PyObject* +_pxarray_concat (PyPixelArray *array, PyObject *value) +{ + /* TODO */ + return RAISE (PyExc_NotImplementedError, "method not implemented"); +} + +/** + * array * 2 + */ +static PyObject* +_pxarray_repeat (PyPixelArray *array, Py_ssize_t n) +{ + /* TODO */ + return RAISE (PyExc_NotImplementedError, "method not implemented"); +} + +/** + * array[x] + */ +static PyObject* +_pxarray_item (PyPixelArray *array, Py_ssize_t _index) +{ + SDL_Surface *surface; + int bpp; + Uint8 *pixels; + + surface = PySurface_AsSurface (array->surface); + bpp = surface->format->BytesPerPixel; + pixels = (Uint8 *) surface->pixels; + + if (_index < 0) + return RAISE (PyExc_IndexError, "array index out of range"); + + if (array->xlen == 1) /* Access of a single column. */ + return _get_single_pixel + (pixels, bpp, array->start + _index * array->padding *array->ystep); + + return _array_slice_internal (array, (Uint32) _index, (Uint32) _index, 1); +} + +/** + * array[x:y] + */ +static PyObject* +_pxarray_slice (PyPixelArray *array, Py_ssize_t low, Py_ssize_t high) +{ + return _array_slice_internal (array, (Uint32) low, (Uint32) high, 1); +} + +static int +_array_assign_array (PyPixelArray *array, Py_ssize_t _index, PyPixelArray *val) +{ + SDL_Surface *surface; + SDL_Surface *valsf; + Uint32 x; + Uint32 y; + int bpp; + int valbpp; + Uint8 *pixels; + Py_ssize_t offset = 0; + + Uint32 start; + Uint32 end; + Uint32 xlen; + Uint32 ylen; + Uint32 xstep; + Uint32 ystep; + Uint32 padding; + + /* Set the correct slice indices */ + start = array->start + _index; + end = array->end - array->xlen + _index; + ylen = array->ylen; + ystep = array->ystep; + xlen = 1; + xstep = 1; + padding = array->xlen - xlen + 1; + + if (val->ylen / val->ystep != ylen / ystep || + val->xlen / val->xstep != xlen / xstep) + { + /* Bounds do not match. */ + PyErr_SetString (PyExc_ValueError, "array sizes do not match"); + return -1; + } + + surface = PySurface_AsSurface (array->surface); + valsf = PySurface_AsSurface (val->surface); + bpp = surface->format->BytesPerPixel; + valbpp = valsf->format->BytesPerPixel; + pixels = (Uint8 *) surface->pixels; + + if (bpp != valbpp) + { + /* bpp do not match. */ + /* TODO */ + PyErr_SetString (PyExc_ValueError, "bit depths do not match"); + return -1; + } + + /* Single value assignment. */ + for (y = 0; y < ylen; y += ystep) + { + for (x = 0; x < xlen; x += xstep) + { + offset = start + x + y * padding; + + switch (bpp) + { + case 1: + *((Uint8 *) pixels + offset) = + (Uint8)*((Uint8 *) valsf->pixels + val->start + + x * val->xstep + y * val->ystep * val->padding); + break; + case 2: + *((Uint16 *) pixels + offset) = + (Uint16)*((Uint16 *) valsf->pixels + val->start + + x * val->xstep + y * val->ystep * val->padding); + break; + case 3: + /* TODO */ + break; + default: /* 4 bpp */ + *((Uint32 *) pixels + offset) = + *((Uint32 *) valsf->pixels + val->start + + x * val->xstep + y * val->ystep * val->padding); + break; + } + } + } + + return 0; +} + +static int +_array_assign_sequence (PyPixelArray *array, Py_ssize_t _index, PyObject *val) +{ + SDL_Surface *surface; + Uint32 x = 0; + Uint32 y = 0; + int bpp; + Uint8 *pixels; + Uint32 color = 0; + Uint32 *colorvals = NULL; + Py_ssize_t offset = 0; + Py_ssize_t seqsize = PySequence_Size (val); + + Uint32 start; + Uint32 end; + Uint32 xlen; + Uint32 ylen; + Uint32 xstep; + Uint32 ystep; + Uint32 padding; + + surface = PySurface_AsSurface (array->surface); + bpp = surface->format->BytesPerPixel; + pixels = (Uint8 *) surface->pixels; + + /* Set the correct slice indices */ + start = array->start + _index; + end = array->end - array->xlen + _index; + ylen = array->ylen; + ystep = array->ystep; + xlen = 1; + xstep = 1; + padding = array->xlen - xlen + 1; + + if ((Uint32)seqsize != ylen / ystep) + { + PyErr_SetString(PyExc_ValueError, "sequence size mismatch"); + return -1; + } + + if (seqsize == 1) + { + /* Single value assignment. */ + offset = start + x + y * padding; + switch (bpp) + { + case 1: + *((Uint8 *) pixels + offset) = (Uint8) color; + break; + case 2: + *((Uint16 *) pixels + offset) = (Uint16) color; + break; + case 3: + /* TODO */ + break; + default: /* 4 bpp */ + *((Uint32 *) pixels + offset) = color; + break; + } + return 0; + } + + /* Copy the values. */ + colorvals = malloc (sizeof (Uint32) * seqsize); + if (!colorvals) + { + PyErr_SetString(PyExc_ValueError, "could not copy pixels"); + 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; + } + + for (y = 0; y < ylen; y += ystep) + { + for (x = 0; x < xlen; x += xstep) + { + offset = start + x + y * padding; + color = *colorvals++; + switch (bpp) + { + case 1: + *((Uint8 *) pixels + offset) = (Uint8) color; + break; + case 2: + *((Uint16 *) pixels + offset) = (Uint16) color; + break; + case 3: + /* TODO */ + break; + default: /* 4 bpp */ + *((Uint32 *) pixels + offset) = color; + break; + } + } + } + + return 0; +} + +/** + * array[x] = ... + */ +static int +_pxarray_ass_item (PyPixelArray *array, Py_ssize_t _index, PyObject *value) +{ + SDL_Surface *surface; + Uint32 x; + Uint32 y; + int bpp; + Uint8 *pixels; + Uint32 color = 0; + Py_ssize_t offset = 0; + + Uint32 start; + Uint32 end; + Uint32 xlen; + Uint32 ylen; + Uint32 xstep; + Uint32 ystep; + Uint32 padding; + + 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, (PyPixelArray *) value); + } + else if (PySequence_Check (value)) + { + PyErr_Clear (); /* _get_color_from_object */ + return _array_assign_sequence (array, _index, value); + } + else /* Error already set by _get_color_from_object(). */ + return -1; + } + + if (array->xlen == 1) /* Single pixel access. */ + { + _set_single_pixel + (pixels, bpp, array->start + _index * array->padding * array->ystep, + color); + return 0; + } + + /* Set the correct slice indices */ + start = array->start + _index; + end = array->end - array->xlen + _index; + ylen = array->ylen; + ystep = array->ystep; + xlen = 1; + xstep = 1; + padding = array->xlen - xlen + 1; + + /* Single value assignment. */ + for (y = 0; y < ylen; y += ystep) + { + for (x = 0; x < xlen; x += xstep) + { + offset = start + x + y * padding; + switch (bpp) + { + case 1: + *((Uint8 *) pixels + offset) = (Uint8) color; + break; + case 2: + *((Uint16 *) pixels + offset) = (Uint16) color; + break; + case 3: + /* TODO */ + break; + default: /* 4 bpp */ + *((Uint32 *) pixels + offset) = color; + break; + } + } + } + + return 0; +} + +/** + * array[x:y] = .... + */ +/* TODO: support: + array[x:y] = [...] for 2D and 1D arrays + array[x:y] = z for 2D and 1D arrays + */ +static int +_pxarray_ass_slice (PyPixelArray *array, Py_ssize_t low, Py_ssize_t high, + PyObject *value) +{ + /* TODO */ + PyErr_SetString (PyExc_NotImplementedError, "method not implemented"); + return -1; +} + +/** + * x in array + */ +/* TODO: support: + [...] in array for 2D arrays + x in array for 1D and 2D arrays + */ +static int +_pxarray_contains (PyPixelArray *array, PyObject *value) +{ + SDL_Surface *surface; + Uint32 x; + Uint32 y; + Py_ssize_t _index; + Uint8 *pixels; + int bpp; + Uint32 color; + + surface = PySurface_AsSurface (array->surface); + bpp = surface->format->BytesPerPixel; + pixels = (Uint8 *) surface->pixels; + + if (!_get_color_from_object (value, surface->format, &color)) + { + /* TODO */ + PyErr_SetString (PyExc_TypeError, "invalid color argument"); + return -1; + } + + switch (bpp) + { + case 1: + for (x = 0; x < array->ylen; x += array->ystep) + { + for (y = 0; y < array->xlen; y += array->xstep) + { + _index = array->start + x + y * array->padding; + if (*((Uint8 *) pixels + _index) == (Uint8) color) + return 1; + } + } + case 2: + for (x = 0; x < array->ylen; x += array->ystep) + { + for (y = 0; y < array->xlen; y += array->xstep) + { + _index = array->start + x + y * array->padding; + if (*((Uint16 *) pixels + _index) == (Uint16) color) + return 1; + } + } + break; + case 3: + /* TODO */ + break; + default: /* 4 bpp */ + for (x = 0; x < array->ylen; x += array->ystep) + { + for (y = 0; y < array->xlen; y += array->xstep) + { + _index = array->start + x + y * array->padding; + if (*((Uint32 *) pixels + _index) == color) + return 1; + } + } + break; + } + return 0; +} + +/** + * array += .... + */ +static PyObject* +_pxarray_inplace_concat (PyPixelArray *array, PyObject *seq) +{ + /* TODO */ + return RAISE (PyExc_NotImplementedError, "method not implemented"); +} + +/** + * array *= ... + */ +static PyObject* +_pxarray_inplace_repeat (PyPixelArray *array, Py_ssize_t n) +{ + /* TODO */ + return RAISE (PyExc_NotImplementedError, "method not implemented"); +} + +/**** Mapping interfaces ****/ + +/** + * Internally used parser function for the 2D slices: + * array[x,y], array[:,:], ... + */ +/* static int */ +/* _get_subslice (SDL_Surface *surface, PyObject *op, Py_ssize_t *start, */ +/* Py_ssize_t *stop, Py_ssize_t *step) */ +/* { */ +/* *start = -1; */ +/* *stop = -1; */ +/* *step = -1; */ + +/* if (PyInt_Check (op)) */ +/* { */ +/* printf ("Found int\n"); */ +/* /\* Plain index: array[x, *\/ */ +/* *start = PyInt_AsLong (op); */ +/* return 1; */ +/* } */ +/* else if (PyLong_Check (op)) */ +/* { */ +/* long long val = -1; */ +/* /\* Plain index: array[x, *\/ */ + +/* printf ("Found long\n"); */ +/* val = PyLong_AsLong (op); */ +/* if ((val < INT_MIN) || (val > INT_MAX)) */ +/* { */ +/* PyErr_SetString(PyExc_ValueError, "index too big for array access"); */ +/* return -1; */ +/* } */ +/* *start = (int) val; */ +/* } */ +/* else if (op == Py_Ellipsis) */ +/* { */ +/* /\* Operator is the ellipsis: array[..., *\/ */ +/* printf ("Found ellipsis\n"); */ +/* /\* TODO *\/ */ +/* } */ +/* else if (PySlice_Check (op)) */ +/* { */ +/* Py_ssize_t slicelen; */ + +/* /\* Operator is a slice: array[x::, *\/ */ +/* printf ("Found slice\n"); */ +/* if (PySlice_GetIndicesEx ((PySliceObject *) op, surface->w * surface->h, */ +/* start, stop, step, &slicelen) < 0) */ +/* { */ +/* return 0; */ +/* } */ +/* } */ +/* return 0; */ +/* } */ + +/** + * Slicing support for 1D and 2D access. + * array[x,y] is only supported for 2D arrays. + */ +/* static PyObject* */ +/* _pxarray_subscript (PyPixelArray *array, PyObject *op) */ +/* { */ +/* Py_ssize_t step; */ +/* Py_ssize_t start; */ +/* Py_ssize_t stop; */ +/* 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 *sub; */ +/* Py_ssize_t i; */ + +/* if (PySequence_Size (op) > 2) */ +/* return RAISE (PyExc_IndexError, */ +/* "too many indices for the 2D array"); */ + +/* for (i = 0; i < PySequence_Size (op); i++) */ +/* { */ +/* sub = PySequence_GetItem (op, i); */ +/* if (!_get_subslice (surface, sub, &start, &stop, &step)) */ +/* { */ +/* /\* Error on retrieving the subslice. *\/ */ +/* printf ("Error\n"); */ +/* Py_DECREF (sub); */ +/* return NULL; */ +/* } */ + +/* if (stop == -1) */ +/* { */ +/* /\* Not an index *\/ */ +/* printf ("Slice: %d:%d:%d\n", start, stop, step); */ +/* } */ + +/* Py_DECREF (sub); */ +/* } */ +/* Py_DECREF (sub); */ +/* } */ +/* else if (PySlice_Check (op)) */ +/* { */ +/* /\* A slice *\/ */ +/* PyObject *result; */ +/* Py_ssize_t slicelen; */ + +/* if (PySlice_GetIndicesEx ((PySliceObject *) op, surface->w * surface->h, */ +/* &start, &stop, &step, &slicelen) < 0) */ +/* return NULL; */ + +/* if (slicelen < 0) /\* TODO: empty surface with 0x0 px? *\/ */ +/* return NULL; */ +/* /\* */ +/* result = (PyObject *) _pxarray_new_internal */ +/* (&PyPixelArray_Type, array->surface, (Uint32) start, (Uint32) stop, */ +/* 1, step, 1, (PyObject *) array); */ +/* *\/ */ +/* return result; */ +/* } */ +/* else if (PyIndex_Check (op)) */ +/* { */ +/* /\* A simple index. *\/ */ +/* Py_ssize_t i = PyNumber_AsSsize_t (op, PyExc_IndexError); */ + +/* if (i == -1 && PyErr_Occurred ()) */ +/* return NULL; */ + +/* if (i < 0) */ +/* i += surface->w * surface->h; */ +/* 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) */ +/* { */ +/* SDL_Surface *surface = PySurface_AsSurface (array->surface); */ + +/* if (PyIndex_Check (op)) */ +/* { */ +/* /\* A simple index. *\/ */ +/* Py_ssize_t i = PyNumber_AsSsize_t (op, PyExc_IndexError); */ +/* if (i == -1 && PyErr_Occurred ()) */ +/* return -1; */ + +/* if (i < 0) */ +/* i += surface->w * surface->h; */ +/* return _pxarray_ass_item (array, i, value); */ +/* } */ +/* PyErr_SetString (PyExc_NotImplementedError, "method not implemented"); */ +/* return -1; */ +/* } */ + +/**** Buffer interfaces ****/ + +static Py_ssize_t +_pxarray_getreadbuf (PyPixelArray *array, Py_ssize_t _index, const void **ptr) +{ + SDL_Surface *surface; + size_t mod = 0; + + if (_index != 0) + { + PyErr_SetString (PyExc_SystemError, + "Accessing non-existent array segment"); + return -1; + } + if (array->parent) + { + *ptr = NULL; + return 0; /* TODO: subarrays? */ + } + surface = PySurface_AsSurface (array->surface); + + switch (surface->format->BytesPerPixel) + { + case 1: + mod = sizeof (Uint8); + break; + case 2: + mod = sizeof (Uint16); + break; + case 3: + mod = sizeof (Uint8) * 3; + break; + default: + mod = sizeof (Uint32); + break; + } + + *ptr = (void *) surface->pixels; + return surface->w * surface->h * mod; +} + +static Py_ssize_t +_pxarray_getwritebuf (PyPixelArray *array, Py_ssize_t _index, const void **ptr) +{ + SDL_Surface *surface = NULL; + size_t mod = 0; + + if (_index != 0) + { + PyErr_SetString (PyExc_SystemError, + "Accessing non-existent array segment"); + return -1; + } + if (array->parent) + { + *ptr = NULL; + return 0; /* TODO: subarrays? */ + } + + switch (surface->format->BytesPerPixel) + { + case 1: + mod = sizeof (Uint8); + break; + case 2: + mod = sizeof (Uint16); + break; + case 3: + mod = sizeof (Uint8) * 3; + break; + default: + mod = sizeof (Uint32); + break; + } + + surface = PySurface_AsSurface (array->surface); + *ptr = (void *) surface->pixels; + return surface->w * surface->h * mod; +} + +static Py_ssize_t +_pxarray_getsegcount (PyPixelArray *array, Py_ssize_t *lenp) +{ + if (array->parent) + { + *lenp = 0; + return 0; /* TODO: subarrays? */ + } + if (lenp) + { + SDL_Surface *surface = PySurface_AsSurface (array->surface); + size_t mod = 0; + + switch (surface->format->BytesPerPixel) + { + case 1: + mod = sizeof (Uint8); + break; + case 2: + mod = sizeof (Uint16); + break; + case 3: + mod = sizeof (Uint8) * 3; + break; + default: + mod = sizeof (Uint32); + break; + } + + *lenp = surface->w * surface->h * mod; + if (array->parent) + { + *lenp = 0; + return 1; /* TODO: subarrays? */ + } + } + return 1; +} + +static PyMethodDef surfarray_builtins[] = +{ + { NULL, NULL, 0, NULL } +}; + +PYGAME_EXPORT +void initpixelarray (void) +{ + PyObject *module; + + if (PyType_Ready (&PyPixelArray_Type) < 0) + return; + + /* create the module */ + module = Py_InitModule3 ("pixelarray", NULL, NULL); + Py_INCREF (&PyPixelArray_Type); + PyModule_AddObject (module, "PixelArray", (PyObject *) &PyPixelArray_Type); + + /*imported needed apis*/ + import_pygame_base (); + import_pygame_surface (); +}
