diff src/pixelarray.c @ 982:2c37905a2091

Added subscript support and make_surface() method to PixelArray.
author marcus
date Sun, 30 Mar 2008 12:22:57 +0000
parents a9b65f86052c
children 0b2c2858b09a
line wrap: on
line diff
--- a/src/pixelarray.c	Sun Mar 30 12:09:39 2008 +0000
+++ b/src/pixelarray.c	Sun Mar 30 12:22:57 2008 +0000
@@ -28,7 +28,6 @@
 #define PyIndex_Check(op) 0
 #endif
 
-
 typedef struct
 {
     PyObject_HEAD
@@ -67,11 +66,10 @@
     Uint32 row, SDL_PixelFormat *format, Uint32 color);
 static PyObject* _array_slice_internal (PyPixelArray *array, Sint32 _start,
     Sint32 _end, Sint32 _step);
+static PyObject* _make_surface(PyPixelArray *array);
 
 /* 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);
@@ -79,17 +77,17 @@
     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_inplace_concat (PyPixelArray *array, PyObject *seq);
-static PyObject* _pxarray_inplace_repeat (PyPixelArray *array, Py_ssize_t n);
 
 /* Mapping methods */
-static int _get_subslice (PyPixelArray *array, PyObject *op, Py_ssize_t length,
-    Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step);
+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);
@@ -102,6 +100,8 @@
  */
 static PyMethodDef _pxarray_methods[] =
 {
+    { "make_surface", (PyCFunction) _make_surface, METH_NOARGS,
+      DOC_PIXELARRAYMAKESURFACE },
     { NULL, NULL, 0, NULL }
 };
 
@@ -118,19 +118,21 @@
 
 /**
  * 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, /*(binaryfunc) _pxarray_concat,*/     /*sq_concat*/
-    (ssizeargfunc) _pxarray_repeat,             /*sq_repeat*/
+    NULL, /*sq_concat*/
+    NULL, /*sq_repeat*/
     (ssizeargfunc) _pxarray_item,               /*sq_item*/
     (ssizessizeargfunc) _pxarray_slice,         /*sq_slice*/
     (ssizeobjargproc) _pxarray_ass_item,        /*sq_ass_item*/
     (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*/
+    NULL, /*sq_inplace_concat*/
+    NULL, /*sq_inplace_repeat*/
 };
 
 /**
@@ -158,7 +160,7 @@
     (reprfunc) &_pxarray_repr,  /* tp_repr */
     0,                          /* tp_as_number */
     &_pxarray_sequence,         /* tp_as_sequence */
-    0, /*&_pxarray_mapping,*/          /* tp_as_mapping */
+    &_pxarray_mapping,          /* tp_as_mapping */
     0,                          /* tp_hash */
     0,                          /* tp_call */
     0,                          /* tp_str */
@@ -196,6 +198,9 @@
 
 #define PyPixelArray_Check(o) \
     ((o)->ob_type == (PyTypeObject *) &PyPixelArray_Type)
+#define SURFACE_EQUALS(x,y) \
+    (((PyPixelArray *)x)->surface == ((PyPixelArray *)y)->surface)
+
 
 static PyPixelArray*
 _pxarray_new_internal (PyTypeObject *type, PyObject *surface,
@@ -340,8 +345,8 @@
     pixels = (Uint8 *) surface->pixels;
 
 /*
-    printf ("ARRAY: %d:%d, %d:%d %d:%d %d\n",
-        array->start, array->end, array->xlen, array->xstep,
+    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 = PyString_FromString ("PixelArray(");
@@ -355,13 +360,13 @@
     switch (bpp)
     {
     case 1:
-        while (posy != array->ylen)
+        while (posy < array->ylen)
         {
             /* Construct the rows */
             PyString_ConcatAndDel (&string, PyString_FromString ("\n  ["));
             posx = 0;
             x = array->xstart;
-            while (posx != (Uint32)xlen)
+            while (posx < (Uint32)xlen)
             {
                 /* Construct the columns */
                 pixel = (Uint32) *((Uint8 *) pixels + x + y * array->padding);
@@ -378,13 +383,13 @@
         }
         break;
     case 2:
-        while (posy != array->ylen)
+        while (posy < array->ylen)
         {
             /* Construct the rows */
             PyString_ConcatAndDel (&string, PyString_FromString ("\n  ["));
             posx = 0;
             x = array->xstart;
-            while (posx != (Uint32)xlen)
+            while (posx < (Uint32)xlen)
             {
                 /* Construct the columns */
                 pixel = (Uint32)
@@ -402,13 +407,13 @@
         }
         break;
     case 3:
-        while (posy != array->ylen)
+        while (posy < array->ylen)
         {
             /* Construct the rows */
             PyString_ConcatAndDel (&string, PyString_FromString ("\n  ["));
             posx = 0;
             x = array->xstart;
-            while (posx != (Uint32)xlen)
+            while (posx < (Uint32)xlen)
             {
                 /* Construct the columns */
                 px24 = ((Uint8 *) (pixels + y * array->padding) + x * 3);
@@ -435,13 +440,13 @@
         }
         break;
     default: /* 4bpp */
-        while (posy != array->ylen)
+        while (posy < array->ylen)
         {
             /* Construct the rows */
             PyString_ConcatAndDel (&string, PyString_FromString ("\n  ["));
             posx = 0;
             x = array->xstart;
-            while (posx != (Uint32)xlen)
+            while (posx < (Uint32)xlen)
             {
                 /* Construct the columns */
                 pixel = *((Uint32 *) (pixels + y * array->padding) + x);
@@ -629,6 +634,174 @@
          xstep, ystep, padding, (PyObject *) array);
 }
 
+/**
+ * Creates a new surface using the currently applied dimensions, step
+ * size, etc.
+ */
+static PyObject*
+_make_surface(PyPixelArray *array)
+{
+    PyObject *newsf;
+    SDL_Surface *tmpsf;
+    SDL_Surface *newsurf;
+    Uint8 *pixels;
+    Uint8 *origpixels;
+
+    SDL_Surface *surface;
+    int bpp;
+    Uint32 x = 0;
+    Uint32 y = 0;
+    Uint32 vx = 0;
+    Uint32 vy = 0;
+    Uint32 posx = 0;
+    Uint32 posy = 0;
+    Uint32 absxstep;
+    Uint32 absystep;
+
+    surface = PySurface_AsSurface (array->surface);
+    bpp = surface->format->BytesPerPixel;
+
+    /* Create the second surface. */
+    tmpsf = SDL_CreateRGBSurface (surface->flags,
+        (int) (array->xlen / ABS (array->xstep)),
+        (int) (array->ylen / ABS (array->ystep)), bpp, surface->format->Rmask,
+        surface->format->Gmask, surface->format->Bmask, surface->format->Amask);
+    if (!tmpsf)
+        return RAISE (PyExc_SDLError, SDL_GetError ());
+
+    /* Guarantee an identical format. */
+    newsurf = SDL_ConvertSurface (tmpsf, surface->format, surface->flags);
+    if (!newsurf)
+    {
+        SDL_FreeSurface (tmpsf);
+        return RAISE (PyExc_SDLError, SDL_GetError ());
+    }
+    SDL_FreeSurface (tmpsf);
+
+    /* Acquire a temporary lock. */
+    if (SDL_MUSTLOCK (newsurf) == 0)
+        SDL_LockSurface (newsurf);
+
+    pixels = (Uint8 *) newsurf->pixels;
+    origpixels = (Uint8 *) surface->pixels;
+
+    absxstep = ABS (array->xstep);
+    absystep = ABS (array->ystep);
+    y = array->ystart;
+
+    /* Single value assignment. */
+    switch (bpp)
+    {
+    case 1:
+        while (posy < array->ylen)
+        {
+            vx = 0;
+            x = array->xstart;
+            posx = 0;
+            while (posx < array->xlen)
+            {
+                *((Uint8 *) pixels + vy * newsurf->pitch + vx) =
+                    (Uint8)*((Uint8 *) origpixels + y * array->padding + x);
+                vx++;
+                x += array->xstep;
+                posx += absxstep;
+            }
+            vy++;
+            y += array->ystep;
+            posy += absystep;
+        }
+        break;
+    case 2:
+        while (posy < array->ylen)
+        {
+            vx = 0;
+            x = array->xstart;
+            posx = 0;
+            while (posx < array->xlen)
+            {
+                *((Uint16 *) (pixels + vy * newsurf->pitch) + vx) =
+                    (Uint16)*((Uint16 *) (origpixels + y * array->padding) + x);
+                vx++;
+                x += array->xstep;
+                posx += absxstep;
+            }
+            vy++;
+            y += array->ystep;
+            posy += absystep;
+        }
+        break;
+    case 3:
+    {
+        Uint8 *px;
+        Uint8 *vpx;
+        SDL_PixelFormat *format = newsurf->format;
+        SDL_PixelFormat *vformat = surface->format;
+
+        while (posy < array->ylen)
+        {
+            vx = 0;
+            x = array->xstart;
+            posx = 0;
+            while (posx < array->xlen)
+            {
+                px = (Uint8 *) (pixels + vy * newsurf->pitch) + vx * 3;
+                vpx = (Uint8 *) ((Uint8*) origpixels + y * array->padding) +
+                    x * 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++;
+                x += array->xstep;
+                posx += absxstep;
+            }
+            vy++;
+            y += array->ystep;
+            posy += absystep;
+        }
+        break;
+    }
+    default:
+        while (posy < array->ylen)
+        {
+            vx = 0;
+            x = array->xstart;
+            posx = 0;
+            while (posx < array->xlen)
+            {
+                *((Uint32 *) (pixels + vy * newsurf->pitch) + vx) =
+                    (Uint32)*((Uint32 *) (origpixels + y * array->padding) + x);
+                vx++;
+                x += array->xstep;
+                posx += absxstep;
+            }
+            vy++;
+            y += array->ystep;
+            posy += absystep;
+        }
+        break;
+    }
+    if (SDL_MUSTLOCK (newsurf) == 0)
+        SDL_UnlockSurface (newsurf);
+    newsf = PySurface_New (newsurf);
+    if (!newsf)
+        return NULL;
+    return newsf;
+}
+
+
 /**** Sequence interfaces ****/
 
 /**
@@ -643,77 +816,6 @@
 }
 
 /**
- * array + value -> new array with new surface.
- */
-static PyObject*
-_pxarray_concat (PyPixelArray *array, PyObject *value)
-{
-    /* TODO */
-    return RAISE (PyExc_NotImplementedError, "method not implemented");
-}
-
-/**
- * array * x -> new array with new surface.
- */
-static PyObject*
-_pxarray_repeat (PyPixelArray *array, Py_ssize_t n)
-{
-    /* TODO */
-    return RAISE (PyExc_NotImplementedError, "method not implemented");
-/*     PyObject *newsf; */
-/*     SDL_Surface *tmpsf; */
-/*     SDL_Surface *newsurf; */
-/*     PyPixelArray *newarray; */
-
-/*     SDL_Surface *surface; */
-/*     int bpp; */
-/*     Uint8 *pixels; */
-/*     Uint32 x = 0; */
-/*     Uint32 y = 0; */
-/*     Uint32 vx = 0; */
-/*     Uint32 vy = 0; */
-/*     Uint32 posx = 0; */
-/*     Uint32 posy = 0; */
-
-/*     Uint32 maxcolor; */
-
-/*     surface = PySurface_AsSurface (array->surface); */
-/*     bpp = surface->format->BytesPerPixel; */
-/*     maxcolor = SDL_MapRGB (surface->format, 255, 255, 255); */
-
-/*     /\* Check the factor bounds. *\/ */
-/*     if (n < 0) */
-/*         return RAISE (PyExc_TypeError, "negative factors are not allowed"); */
-/*     if ((Uint32) n > maxcolor) */
-/*         return RAISE (PyExc_ArithmeticError, "integer overflow for factor"); */
-
-/*     /\* Anything's fine, create the second surface. *\/ */
-/*     tmpsf = SDL_CreateRGBSurface (surface->flags, */
-/*         (int) (array->xlen / array->xstep), */
-/*         (int) (array->ylen / array->ystep), bpp, surface->format->Rmask, */
-/*         surface->format->Gmask, surface->format->Bmask, surface->format->Amask); */
-/*     if (!tmpsf) */
-/*         return RAISE (PyExc_SDLError, SDL_GetError ()); */
-/*     /\* Guarantee an identical format. *\/ */
-/*     newsurf = SDL_ConvertSurface (tmpsf, surface->format, surface->flags); */
-/*     if (!newsurf) */
-/*     { */
-/*         SDL_FreeSurface (tmpsf); */
-/*         return RAISE (PyExc_SDLError, SDL_GetError ()); */
-/*     } */
-/*     SDL_FreeSurface (tmpsf); */
-    
-/*     newsf = PySurface_New (newsurf); */
-/*     if (!newsf) */
-/*         return NULL; */
-/*     newarray = _pxarray_new_internal (&PyPixelArray_Type, newsf, 0, 0, */
-/*         (Uint32) newsurf->w, (Uint32) newsurf->h, 1, 1, (Uint32) newsurf->pitch, */
-/*         NULL); */
-/*     if (!newarray) */
-/*         return NULL; */
-}
-
-/**
  * array[x]
  */
 static PyObject*
@@ -778,6 +880,8 @@
     int bpp;
     int valbpp;
     Uint8 *pixels;
+    Uint8 *valpixels;
+    int copied = 0;
 
     Uint32 xstart = 0;
     Uint32 ystart = 0;
@@ -815,8 +919,14 @@
         padding = array->padding;
     }
 
-    if (val->ylen / val->ystep != ylen / ystep ||
-        val->xlen / val->xstep != xlen / xstep)
+/*
+    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");
@@ -827,6 +937,7 @@
     bpp = surface->format->BytesPerPixel;
     valbpp = valsf->format->BytesPerPixel;
     pixels = (Uint8 *) surface->pixels;
+    valpixels = valsf->pixels;
 
     if (bpp != valbpp)
     {
@@ -836,24 +947,41 @@
         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;
 
     /* Single value assignment. */
     switch (bpp)
     {
     case 1:
-        while (posy != ylen)
+        while (posy < ylen)
         {
             vx = val->xstart;
             posx = 0;
             x = xstart;
-            while (posx != xlen)
+            while (posx < xlen)
             {
                 *((Uint8 *) pixels + y * padding + x) =
-                    (Uint8)*((Uint8 *) valsf->pixels + vy * val->padding + vx);
+                    (Uint8)*((Uint8 *) valpixels + vy * val->padding + vx);
                 vx += val->xstep;
                 x += xstep;
                 posx += absxstep;
@@ -864,16 +992,15 @@
         }
         break;
     case 2:
-        while (posy != ylen)
+        while (posy < ylen)
         {
             vx = val->xstart;
             posx = 0;
             x = xstart;
-            while (posx != xlen)
+            while (posx < xlen)
             {
                 *((Uint16 *) (pixels + y * padding) + x) =
-                    (Uint16)*((Uint16 *)
-                        ((Uint8*)valsf->pixels + vy * val->padding) + vx);
+                    (Uint16)*((Uint16 *) (valpixels + vy * val->padding) + vx);
                 vx += val->xstep;
                 x += xstep;
                 posx += absxstep;
@@ -890,15 +1017,15 @@
         SDL_PixelFormat *format = surface->format;
         SDL_PixelFormat *vformat = valsf->format;
 
-        while (posy != ylen)
+        while (posy < ylen)
         {
             vx = val->xstart;
             posx = 0;
             x = xstart;
-            while (posx != xlen)
+            while (posx < xlen)
             {
                 px = (Uint8 *) (pixels + y * padding) + x * 3;
-                vpx = (Uint8 *) ((Uint8*)valsf->pixels + y * val->padding) +
+                vpx = (Uint8 *) ((Uint8*) valpixels + vy * val->padding) +
                     vx * 3;
 
 #if (SDL_BYTEORDER == SDL_LIL_ENDIAN)
@@ -927,16 +1054,15 @@
         break;
     }
     default:
-        while (posy != ylen)
+        while (posy < ylen)
         {
             vx = val->xstart;
             posx = 0;
             x = xstart;
-            while (posx != xlen)
+            while (posx < xlen)
             {
                 *((Uint32 *) (pixels + y * padding) + x) =
-                    *((Uint32 *)
-                        ((Uint8*)valsf->pixels + y * val->padding) + vx);
+                    (Uint32)*((Uint32 *) (valpixels + vy * val->padding) + vx);
                 vx += val->xstep;
                 x += xstep;
                 posx += absxstep;
@@ -947,6 +1073,11 @@
         }
         break;
     }
+    
+    if (copied)
+    {
+        free (valpixels);
+    }
     return 0;
 }
 
@@ -1005,9 +1136,9 @@
 /*
     printf ("LEN: %d:%d - %d\n", xlen / xstep, ylen / ystep, seqsize);
 */
-    if ((Uint32)seqsize != ylen / ystep)
+    if ((Uint32)seqsize != ylen / ABS (ystep))
     {
-        if ((Uint32)seqsize != xlen / xstep)
+        if ((Uint32)seqsize != xlen / ABS (xstep))
         {
             PyErr_SetString(PyExc_ValueError, "sequence size mismatch");
             return -1;
@@ -1017,7 +1148,7 @@
     if (seqsize == 1)
     {
         /* Single value assignment. */
-        _set_single_pixel (pixels, bpp, xstart, x * padding * ystep,
+        _set_single_pixel (pixels, bpp, xstart, ystart + padding * ystep,
             surface->format, color);
         return 0;
     }
@@ -1048,11 +1179,11 @@
     switch (bpp)
     {
     case 1:
-        while (posy != ylen)
+        while (posy < ylen)
         {
             posx = 0;
             x = xstart;
-            while (posx != xlen)
+            while (posx < xlen)
             {
                 color = *colorvals++;
                 *((Uint8 *) pixels + y * padding + x) = (Uint8) color;
@@ -1064,11 +1195,11 @@
         }
         break;
     case 2:
-        while (posy != ylen)
+        while (posy < ylen)
         {
             posx = 0;
             x = xstart;
-            while (posx != xlen)
+            while (posx < xlen)
             {
                 color = *colorvals++;
                 *((Uint16 *) (pixels + y * padding) + x) = (Uint16) color;
@@ -1084,11 +1215,11 @@
         Uint8 *px;
         SDL_PixelFormat *format = surface->format;
 
-        while (posy != ylen)
+        while (posy < ylen)
         {
             posx = 0;
             x = xstart;
-            while (posx != xlen)
+            while (posx < xlen)
             {
                 color = *colorvals++;
                 px = (Uint8 *) (pixels + y * padding) + x * 3;
@@ -1110,11 +1241,11 @@
         break;
     }
     default:
-        while (posy != ylen)
+        while (posy < ylen)
         {
             posx = 0;
             x = xstart;
-            while (posx != xlen)
+            while (posx < xlen)
             {
                 color = *colorvals++;
                 *((Uint32 *) (pixels + y * padding) + x) = color;
@@ -1129,6 +1260,139 @@
     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 = high;
+        ystep = array->ystep;
+        xstep = array->xstep;
+        padding = array->padding;
+    }
+    else
+    {
+        xstart = array->xstart + low * array->xstep;
+        ystart = array->ystart;
+        xlen = high;
+        ylen = array->ylen;
+        xstep = array->xstep;
+        ystep = array->ystep;
+        padding = array->padding;
+    }
+
+    absxstep = ABS (xstep);
+    absystep = ABS (ystep);
+    y = ystart;
+
+    /* 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 - (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;
+    }
+    return 0;
+}
+
 /**
  * array[x] = ...
  */
@@ -1209,11 +1473,11 @@
     switch (bpp)
     {
     case 1:
-        while (posy != ylen)
+        while (posy < ylen)
         {
             posx = 0;
             x = xstart;
-            while (posx != xlen)
+            while (posx < xlen)
             {
                 *((Uint8 *) pixels + y * padding + x) = (Uint8) color;
                 x += xstep;
@@ -1224,11 +1488,11 @@
         }
         break;
     case 2:
-        while (posy != ylen)
+        while (posy < ylen)
         {
             posx = 0;
             x = xstart;
-            while (posx != xlen)
+            while (posx < xlen)
             {
                 *((Uint16 *) (pixels + y * padding) + x) = (Uint16) color;
                 x += xstep;
@@ -1243,11 +1507,11 @@
         Uint8 *px;
         SDL_PixelFormat *format = surface->format;
 
-        while (posy != ylen)
+        while (posy < ylen)
         {
             posx = 0;
             x = xstart;
-            while (posx != xlen)
+            while (posx < xlen)
             {
                 px = (Uint8 *) (pixels + y * padding) + x * 3;
 #if (SDL_BYTEORDER == SDL_LIL_ENDIAN)
@@ -1268,11 +1532,11 @@
         break;
     }
     default: /* 4 bpp */
-        while (posy != ylen)
+        while (posy < ylen)
         {
             posx = 0;
             x = xstart;
-            while (posx != xlen)
+            while (posx < xlen)
             {
                 *((Uint32 *) (pixels + y * padding) + x) = color;
                 x += xstep;
@@ -1295,7 +1559,6 @@
 {
     SDL_Surface *surface;
     Uint32 color;
-    int i = 0;
 
     if (array->xlen != 1)
     {
@@ -1332,41 +1595,7 @@
     }
     else if (_get_color_from_object (value, surface->format, &color))
     {
-        if (array->xlen == 1)
-        {
-            for (i = low; i < high; i++)
-            {
-                _set_single_pixel ((Uint8*) surface->pixels,
-                    surface->format->BytesPerPixel,
-                    array->xstart, i * array->padding * array->ystep,
-                    surface->format, color);
-            }
-        }
-        else if (array->ylen == 1)
-        {
-            for (i = low; i < high; i++)
-            {
-                _set_single_pixel ((Uint8*) surface->pixels,
-                    surface->format->BytesPerPixel,
-                    array->xstart + i * array->xstep,
-                    array->ystart * array->padding,
-                    surface->format, color);
-            }
-        }
-        else
-        {
-            Uint32 y;
-            for (y = array->ystart; y < array->ylen; y += array->ystep)
-            {
-                for (i = low; i < high; i++)
-                {
-                    _set_single_pixel ((Uint8*) surface->pixels,
-                        surface->format->BytesPerPixel,
-                        array->xstart + i * array->xstep, y * array->padding,
-                        surface->format, color);
-                }
-            }
-        }
+        return _array_assign_slice (array, low, high, color);
     }
     else if (PySequence_Check (value))
     {
@@ -1408,11 +1637,11 @@
     switch (bpp)
     {
     case 1:
-        while (posy != array->ylen)
+        while (posy < array->ylen)
         {
             posx = 0;
             x = array->xstart;
-            while (posx != array->xlen)
+            while (posx < array->xlen)
             {
                 if (*((Uint8 *) pixels + y * array->padding + x)
                     == (Uint8) color)
@@ -1425,11 +1654,11 @@
         }
         break;
     case 2:
-        while (posy != array->ylen)
+        while (posy < array->ylen)
         {
             posx = 0;
             x = array->xstart;
-            while (posx != array->xlen)
+            while (posx < array->xlen)
             {
                 if (*((Uint16 *) (pixels + y * array->padding) + x)
                     == (Uint16) color)
@@ -1446,11 +1675,11 @@
         Uint32 pxcolor;
         Uint8 *pix;
 
-        while (posy != array->ylen)
+        while (posy < array->ylen)
         {
             posx = 0;
             x = array->xstart;
-            while (posx != array->xlen)
+            while (posx < array->xlen)
             {
                 pix = ((Uint8 *) (pixels + y * array->padding) + x * 3);
 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
@@ -1469,11 +1698,11 @@
         break;
     }
     default: /* 4 bpp */
-        while (posy != array->ylen)
+        while (posy < array->ylen)
         {
             posx = 0;
             x = array->xstart;
-            while (posx != array->xlen)
+            while (posx < array->xlen)
             {
                 if (*((Uint32 *) (pixels + y * array->padding) + x)
                     == color)
@@ -1489,120 +1718,6 @@
     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");
-/*     SDL_Surface *surface; */
-/*     int bpp; */
-/*     Uint8 *pixels; */
-/*     Uint32 x = 0; */
-/*     Uint32 y = 0; */
-/*     Uint32 posx = 0; */
-/*     Uint32 posy = 0; */
-/*     Sint32 absxstep; */
-/*     Sint32 absystep; */
-/*     Uint32 maxcolor; */
-
-/*     surface = PySurface_AsSurface (array->surface); */
-/*     bpp = surface->format->BytesPerPixel; */
-/*     maxcolor = SDL_MapRGB (surface->format, 255, 255, 255); */
-
-/*     /\* Check the factor bounds. *\/ */
-/*     if (n < 0) */
-/*         return RAISE (PyExc_TypeError, "negative factors are not allowed"); */
-/*     if ((Uint32) n > maxcolor) */
-/*         return RAISE (PyExc_ArithmeticError, "integer overflow for factor"); */
-
-/*     pixels = (Uint8 *) surface->pixels; */
-/*     absxstep = ABS (array->xstep); */
-/*     absystep = ABS (array->ystep); */
-/*     y = array->ystart; */
-    
-/*     switch (bpp) */
-/*     { */
-/*     case 1: */
-/*         while (posy != array->ylen) */
-/*         { */
-/*             x = array->xstart; */
-/*             posx = 0; */
-/*             while (posx != array->xlen) */
-/*             { */
-/*                 *((Uint8 *) pixels + y * array->padding + x) *= n; */
-/*                 x += array->xstep; */
-/*                 posx += absxstep; */
-/*             } */
-/*             y += array->ystep; */
-/*             posy += absystep; */
-/*         } */
-/*         break; */
-/*     case 2: */
-/*         while (posy != array->ylen) */
-/*         { */
-/*             x = array->xstart; */
-/*             posx = 0; */
-/*             while (posx != array->xlen) */
-/*             { */
-/*                 *((Uint16 *) (pixels + y * array->padding) + x) *= n; */
-/*                 x += array->xstep; */
-/*                 posx += absxstep; */
-/*             } */
-/*             y += array->ystep; */
-/*             posy += absystep; */
-/*         } */
-/*         break; */
-/*     case 3: */
-/*     { */
-/*         Uint8 *px; */
-
-/*         while (posy != array->ylen) */
-/*         { */
-/*             x = array->xstart; */
-/*             posx = 0; */
-/*             while (posx != array->xlen) */
-/*             { */
-/*                 px = (Uint8 *) (pixels + y * array->padding) + x * 3; */
-/*                 x += array->xstep; */
-/*                 posx += absxstep; */
-/*             } */
-/*             y += array->ystep; */
-/*             posy += absystep; */
-/*         } */
-/*         break; */
-/*     } */
-/*     default: */
-/*         while (posy != array->ylen) */
-/*         { */
-/*             x = array->xstart; */
-/*             posx = 0; */
-/*             while (posx != array->xlen) */
-/*             { */
-/*                 *((Uint32 *) (pixels + y * array->padding) + x) *= n; */
-/*                 x += array->xstep; */
-/*                 posx += absxstep; */
-/*             } */
-/*             y += array->ystep; */
-/*             posy += absystep; */
-/*         } */
-/*         break; */
-/*     } */
-/*     return (PyObject *)array; */
-}
-
 /**** Mapping interfaces ****/
 
 /**
@@ -1610,17 +1725,35 @@
  * array[x,y], array[:,:], ...
  */
 static int
-_get_subslice (PyPixelArray *array, PyObject *op, Py_ssize_t length,
-    Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step)
+_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 (PyInt_Check (op))
+    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;
     }
@@ -1637,20 +1770,16 @@
             return 0;
         }
         *start = (int) val;
-        *stop = *start + 1;
+        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 (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;
-        }
-    }
     return 1;
 }
 
@@ -1684,8 +1813,8 @@
         if (size > 2 || (size == 2 && array->xlen == 1))
             return RAISE (PyExc_IndexError, "too many indices for the array");
 
-        lenx = (array->xlen > 1) ? array->xlen / array->xstep : 0;
-        leny = array->ylen / array->ystep;
+        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)
@@ -1697,7 +1826,7 @@
             xstop = array->xlen;
             xstep = array->xstep;
         }
-        else if (!_get_subslice (array, obj, lenx, &xstart, &xstop, &xstep))
+        else if (!_get_subslice (obj, lenx, &xstart, &xstop, &xstep))
         {
             /* Error on retrieving the subslice. */
             return NULL;
@@ -1715,7 +1844,7 @@
                 ystop = array->ylen;
                 ystep = array->ystep;
             }
-            else if (!_get_subslice (array, obj, leny, &ystart, &ystop, &ystep))
+            else if (!_get_subslice (obj, leny, &ystart, &ystop, &ystep))
             {
                 /* Error on retrieving the subslice. */
                 return NULL;
@@ -1731,63 +1860,29 @@
         /* Null value? */
         if (xstart == xstop || ystart == ystop)
             Py_RETURN_NONE;
-
-        /* Check boundaries. */
-        if (xstart + xstep >= xstop)
-        {
-            xstop = xstart + 1;
-            xstep = 1;
-        }
-
-        if (ystart + ystep >= ystop)
-        {
-            ystop = ystart + 1;
-            ystep = 1;
-        }
-
-        /* Move to the correct offsets. */
-        if (xstart < 0)
-            xstart += array->xstart + array->xlen;
-        if (ystart < 0)
-            ystart += array->ystart + array->ylen;
-        if (xstop < 0)
-            xstop += array->xstart + array->xlen;
-        if (ystop < 0)
-            ystop += array->ystart + array->ylen;
-
+/*
+        printf ("X: %d:%d:%d Y: %d:%d:%d\n", xstart, xstop, xstep,
+            ystart, ystop, ystep);
+*/
         /* Single value? */
-        if (xstart + xstep >= xstop && ystart + ystep >= ystop)
+        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 ("X: %d:%d:%d Y: %d:%d:%d\n", xstart, xstop, xstep,
-            ystart, ystop, ystep);
-*/
-/*        
-        printf ("NEW ARRAY: %d:%d %d:%d:%d %d:%d:%d %d\n",
-            array->xstart + xstart, array->ystart + ystart,
-            xstart, xstop, xstep, ystart, ystop, ystep, array->padding);
-*/
-/*
-        lenx = MAX((xstop - xstart) / xstep, 1);
-        leny = MAX((ystop - ystart) / ystep, 1);
-*/
 
 /*
-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);
+        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) xstop - xstart,
-            (Uint32) ystop - ystart,
+            (Uint32) ABS (xstop - xstart),
+            (Uint32) ABS (ystop - ystart),
             (Sint32) xstep,
             (Sint32) ystep,
             (Uint32) array->padding, (PyObject *) array);
@@ -1805,25 +1900,24 @@
         {
             /* 2D array - slice along the x axis */
             retval = PySlice_GetIndicesEx ((PySliceObject *) op,
-                (Py_ssize_t) (array->xlen / array->xstep), &start, &stop, &step,
-                &slicelen);
+                (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 / array->ystep), &start, &stop, &step,
-                &slicelen);
+                (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))
@@ -1857,9 +1951,167 @@
 static int
 _pxarray_ass_subscript (PyPixelArray *array, PyObject* op, PyObject* value)
 {
-    SDL_Surface *surface = PySurface_AsSurface (array->surface);
+    /* TODO: by time we can make this faster by avoiding the creation of
+     * temporary subarrays.
+     */
     
-    if (PyIndex_Check (op) || PyInt_Check (op) || PyLong_Check (op))
+    /* 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, array->xstart + xstart,
+                ystart * array->padding * array->ystep, 1, 1, 1, 1,
+                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
@@ -1876,14 +2128,15 @@
 #endif 
         if (i == -1 && PyErr_Occurred ())
             return -1;
-
         if (i < 0)
-            i += (array->xlen > 1) ? array->xlen / array->xstep :
-                array->ylen / array->ystep;
+            i += (array->xlen > 1) ? array->xlen / ABS (array->xstep) :
+                array->ylen / ABS (array->ystep);
 
         return _pxarray_ass_item (array, i, value);
     }
-    PyErr_SetString (PyExc_NotImplementedError, "method not implemented");
+
+    PyErr_SetString (PyExc_TypeError,
+        "index must be an integer, sequence or slice");
     return -1;
 }