diff src/pixelarray_methods.c @ 989:1bbdc02af359

Added PixelArray.replace() method. Moved pixelarray methods into an own source file.
author marcus
date Fri, 04 Apr 2008 08:04:49 +0000
parents
children 404e3a0be4f8
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pixelarray_methods.c	Fri Apr 04 08:04:49 2008 +0000
@@ -0,0 +1,438 @@
+/*
+  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
+
+*/
+
+/**
+ * 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 (!val)
+        return 0;
+
+    if (PyInt_Check (val))
+    {
+        long intval = PyInt_AsLong (val);
+        if ((intval < INT_MIN) || (intval > INT_MAX))
+        {
+            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 = PyLong_AsLong (val);
+        if ((longval < INT_MIN) || (longval > INT_MAX))
+        {
+            PyErr_SetString(PyExc_ValueError, "invalid color argument");
+            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 row)
+{
+    Uint32 pixel;
+
+    switch (bpp)
+    {
+    case 1:
+        pixel = (Uint32)*((Uint8 *) pixels + row + _index);
+        break;
+    case 2:
+        pixel = (Uint32)*((Uint16 *) (pixels + row) + _index);
+        break;
+    case 3:
+    {
+        Uint8 *px = ((Uint8 *) (pixels + row) + _index * 3);
+#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 + row) + _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 row,
+    SDL_PixelFormat *format, Uint32 color)
+{
+    switch (bpp)
+    {
+    case 1:
+        *((Uint8 *) pixels + row + _index) = (Uint8) color;
+        break;
+    case 2:
+        *((Uint16 *) (pixels + row) + _index) = (Uint16) color;
+        break;
+    case 3:
+#if (SDL_BYTEORDER == SDL_LIL_ENDIAN)
+        *((Uint8 *) (pixels + row) + _index * 3 + (format->Rshift >> 3)) =
+            (Uint8) (color >> 16);
+        *((Uint8 *) (pixels + row) + _index * 3 + (format->Gshift >> 3)) =
+            (Uint8) (color >> 8);
+        *((Uint8 *) (pixels + row) + _index * 3 + (format->Bshift >> 3)) =
+            (Uint8) color;
+#else
+        *((Uint8 *) (pixels + row) + _index * 3 + 2 - (format->Rshift >> 3)) =
+            (Uint8) (color >> 16);
+        *((Uint8 *) (pixels + row) + _index * 3 + 2 - (format->Gshift >> 3)) =
+            (Uint8) (color >> 8);
+        *((Uint8 *) (pixels + row) + _index * 3 + 2 - (format->Bshift >> 3)) =
+            (Uint8) color;
+#endif
+        break;
+    default: /* 4 bpp */
+        *((Uint32 *) (pixels + row) + _index) = color;
+        break;
+    }
+}
+
+/**
+ * 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;
+}
+
+static PyObject*
+_replace_color (PyPixelArray *array, PyObject *args)
+{
+    PyObject *delcolor = NULL;
+    PyObject *replcolor = NULL;
+    Uint32 dcolor;
+    Uint32 rcolor;
+    SDL_Surface *surface;
+
+    Uint32 x = 0;
+    Uint32 y = 0;
+    Uint32 posx = 0;
+    Uint32 posy = 0;
+    Sint32 absxstep;
+    Sint32 absystep;
+    Uint8 *pixels;
+
+    if (!PyArg_ParseTuple (args, "OO", &delcolor, &replcolor))
+        return NULL;
+
+    surface = PySurface_AsSurface (array->surface);
+    if (!_get_color_from_object (delcolor, surface->format, &dcolor) ||
+        !_get_color_from_object (replcolor, surface->format, &rcolor))
+        return NULL;
+
+    surface = PySurface_AsSurface (array->surface);
+    pixels = surface->pixels;
+    absxstep = ABS (array->xstep);
+    absystep = ABS (array->ystep);
+    y = array->ystart;
+
+    switch (surface->format->BytesPerPixel)
+    {
+    case 1:
+    {
+        Uint8 *pixel;
+        while (posy < array->ylen)
+        {
+            x = array->xstart;
+            posx = 0;
+            while (posx < array->xlen)
+            {
+                pixel = ((Uint8 *) pixels + y * surface->pitch + x);
+                if (*pixel == dcolor)
+                    *pixel = (Uint8) rcolor;
+                x += array->xstep;
+                posx += absxstep;
+            }
+            y += array->ystep;
+            posy += absystep;
+        }
+        break;
+    }
+    case 2:
+    {
+        Uint16 *pixel;
+        while (posy < array->ylen)
+        {
+            x = array->xstart;
+            posx = 0;
+            while (posx < array->xlen)
+            {
+                pixel = ((Uint16 *) (pixels + y * surface->pitch) + x);
+                if (*pixel == dcolor)
+                    *pixel = (Uint16) rcolor;
+                x += array->xstep;
+                posx += absxstep;
+            }
+            y += array->ystep;
+            posy += absystep;
+        }
+        break;
+    }
+    case 3:
+    {
+        Uint8 *px;
+        Uint32 pxcolor;
+        SDL_PixelFormat *format = surface->format;
+        while (posy < array->ylen)
+        {
+            x = array->xstart;
+            posx = 0;
+            while (posx < array->xlen)
+            {
+                px = (Uint8 *) (pixels + y * surface->pitch) + x * 3;
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+                pxcolor = (px[0]) + (px[1] << 8) + (px[2] << 16);
+                if (pxcolor == dcolor)
+                {
+                    *(px + (format->Rshift >> 3)) = (Uint8) (rcolor >> 16);
+                    *(px + (format->Gshift >> 3)) = (Uint8) (rcolor >> 8);
+                    *(px + (format->Bshift >> 3)) = (Uint8) rcolor;
+                }
+#else
+                pxcolor = (px[2]) + (px[1] << 8) + (px[0] << 16);
+                if (pxcolor == dcolor)
+                {
+                    *(px + 2 - (format->Rshift >> 3)) = (Uint8) (rcolor >> 16);
+                    *(px + 2 - (format->Gshift >> 3)) = (Uint8) (rcolor >> 8);
+                    *(px + 2 - (format->Bshift >> 3)) = (Uint8) rcolor;
+                }
+#endif
+                x += array->xstep;
+                posx += absxstep;
+            }
+            y += array->ystep;
+            posy += absystep;
+        }
+        break;
+    }
+    default:
+    {
+        Uint32 *pixel;
+        while (posy < array->ylen)
+        {
+            x = array->xstart;
+            posx = 0;
+            while (posx < array->xlen)
+            {
+                pixel = ((Uint32 *) (pixels + y * surface->pitch) + x);
+                if (*pixel == dcolor)
+                    *pixel = rcolor;
+                x += array->xstep;
+                posx += absxstep;
+            }
+            y += array->ystep;
+            posy += absystep;
+        }
+        break;
+    }
+    }
+    Py_RETURN_NONE;
+}