static PyObject*
blit_array(PyObject* self, PyObject* arg)
{
    PyObject *surfobj, *arrayobj;
    PyObject *cobj;
    PyArrayInterface *inter;
    char *array_data;
    SDL_Surface* surf;
    SDL_PixelFormat* format;
    int loopx, loopy;
    int stridex, stridey, stridez=0, stridez2=0, sizex, sizey;
    int Rloss, Gloss, Bloss, Rshift, Gshift, Bshift;
    
    if (!PyArg_ParseTuple(arg, "O!O", &PySurface_Type, &surfobj, &arrayobj)) {
        return NULL;
    }
    surf = PySurface_AsSurface(surfobj);
    format = surf->format;
    
    if (!_get_array_interface(arrayobj, &cobj, &inter)) {
        return 0;
    }

    switch (inter->typekind) {
    case 'i':  /* integer */
	break;
    case 'u':  /* unsigned integer */ 
	break;
    case 'S':  /* fixed length character field */
	break;
    case 'V':  /* structured element: record */
	break;
    default:
	Py_DECREF(cobj);
	PyErr_Format(PyExc_ValueError, "unsupported array type '%c'",
		     inter->typekind);
	return NULL;
    }

    if (!(inter->nd == 2 || (inter->nd == 3 && inter->shape[2] == 3)))
        return RAISE(PyExc_ValueError, "must be a valid 2d or 3d array\n");

    if (surf->format->BytesPerPixel <= 0 || surf->format->BytesPerPixel > 4)
        return RAISE(PyExc_ValueError, "unsupport bit depth for surface");

    stridex = inter->strides[0];
    stridey = inter->strides[1];
    if (inter->nd == 3) {
        stridez = inter->strides[2];
        stridez2 = stridez*2;
    }
    sizex = inter->shape[0];
    sizey = inter->shape[1];
    Rloss = format->Rloss; Gloss = format->Gloss; Bloss = format->Bloss;
    Rshift = format->Rshift; Gshift = format->Gshift; Bshift = format->Bshift;

    if (sizex != surf->w || sizey != surf->h) {
        Py_DECREF(cobj);
        return RAISE(PyExc_ValueError, "array must match surface dimensions");
    }
    if (!PySurface_LockBy(surfobj, (PyObject *) arrayobj)) {
        Py_DECREF(cobj);
        return NULL;
    }
    
    array_data = (char *)inter->data;

    switch (surf->format->BytesPerPixel) {
    case 1:
        if (inter->nd == 2) {
            switch (inter->itemsize) {
            case sizeof (Uint8):
                COPYMACRO_2D(Uint8, Uint8);
                break;
            case sizeof (Uint16):
                COPYMACRO_2D(Uint8, Uint16);
                break;
            case sizeof (Uint32):
                COPYMACRO_2D(Uint8, Uint32);
                break;
            case sizeof (Uint64):
                COPYMACRO_2D(Uint8, Uint64);
                break;
            default:
                Py_DECREF(cobj);
                if (!PySurface_UnlockBy(surfobj, (PyObject *) arrayobj)) {
                    return NULL;
                }
                return RAISE(PyExc_ValueError,
                             "unsupported datatype for array\n");
            }
        }
        else {
            Py_DECREF(cobj);
            if (!PySurface_UnlockBy(surfobj, (PyObject *) arrayobj)) {
                return NULL;
            }
            return RAISE(PyExc_ValueError,
                         "unsupported datatype for array\n");
        }
        break;
    case 2:
        if (inter->nd == 2) {
            switch (inter->itemsize) {
            case sizeof (Uint16):
                COPYMACRO_2D(Uint16, Uint16);
                break;
            case sizeof (Uint32):
                COPYMACRO_2D(Uint16, Uint32);
                break;
            case sizeof (Uint64):
                COPYMACRO_2D(Uint16, Uint64);
                break;
            default:
                Py_DECREF(cobj);
                if (!PySurface_UnlockBy(surfobj, (PyObject *) arrayobj)) {
                    return NULL;
                }
                return RAISE(PyExc_ValueError,
                             "unsupported datatype for array\n");
            }
        }
        else {
	    Uint16 alpha = 0;
	    if (format->Amask) {
		alpha = 255 >> format->Aloss << format->Ashift;
	    }
            switch (inter->itemsize) {
            case sizeof (Uint8):
                COPYMACRO_3D(Uint16, Uint8);
                break;
            case sizeof (Uint16):
                COPYMACRO_3D(Uint16, Uint16);
                break;
            case sizeof (Uint32):
                COPYMACRO_3D(Uint16, Uint32);
                break;
            case sizeof (Uint64):
                COPYMACRO_3D(Uint16, Uint64);
                break;
            default:
                Py_DECREF(cobj);
                if (!PySurface_UnlockBy(surfobj, (PyObject *) arrayobj)) {
                    return NULL;
                }
                return RAISE(PyExc_ValueError,
                             "unsupported datatype for array\n");
            }
        }
        break;
    case 3:
        /* Assumption: The rgb components of a 24 bit pixel are in
           separate bytes.
	*/
        if (inter->nd == 2) {
            switch (inter->itemsize) {
            case sizeof (Uint32):
                COPYMACRO_2D_24(Uint32);
                break;
            case sizeof (Uint64):
                COPYMACRO_2D_24(Uint64);
                break;
            default:
                Py_DECREF(cobj);
                if (!PySurface_UnlockBy(surfobj, (PyObject *) arrayobj)) {
                    return NULL;
                }
                return RAISE(PyExc_ValueError,
                             "unsupported datatype for array\n");
            }
        }
        else {
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
	    size_t stridez_0 = (Rshift ==  0 ? 0        :
				Gshift ==  0 ? stridez  :
				               stridez2   );
	    size_t stridez_1 = (Rshift ==  8 ? 0        :
				Gshift ==  8 ? stridez  :
                                               stridez2   );
	    size_t stridez_2 = (Rshift == 16 ? 0        :
                                Gshift == 16 ? stridez  :
				               stridez2   );
#else
	    size_t stridez_2 = (Rshift ==  0 ? 0        :
				Gshift ==  0 ? stridez  :
				               stridez2   );
	    size_t stridez_1 = (Rshift ==  8 ? 0        :
				Gshift ==  8 ? stridez  :
                                               stridez2   );
	    size_t stridez_0 = (Rshift == 16 ? 0        :
                                Gshift == 16 ? stridez  :
				               stridez2   );
#endif
            switch (inter->itemsize) {
            case sizeof (Uint8):
                COPYMACRO_3D_24(Uint8);
                break;
            case sizeof (Uint16):
                COPYMACRO_3D_24(Uint16);
                break;
            case sizeof (Uint32):
                COPYMACRO_3D_24(Uint32);
                break;
            case sizeof (Uint64):
                COPYMACRO_3D_24(Uint64);
                break;
            default:
                Py_DECREF(cobj);
                if (!PySurface_UnlockBy(surfobj, (PyObject *) arrayobj)) {
                    return NULL;
                }
                return RAISE(PyExc_ValueError,
                             "unsupported datatype for array\n");
            }
        }
        break;
    case 4:
        if (inter->nd == 2) {
            switch (inter->itemsize) {
            case sizeof (Uint32):
                COPYMACRO_2D(Uint32, Uint32);
                break;
            case sizeof (Uint64):
                COPYMACRO_2D(Uint32, Uint64);
                break;
            default:
                Py_DECREF(cobj);
                if (!PySurface_UnlockBy(surfobj, (PyObject *) arrayobj)) {
                    return NULL;
                }
                return RAISE(PyExc_ValueError,
                            "unsupported datatype for array\n");
            }
        }
        else {
	    Uint32 alpha = 0;
	    if (format->Amask) {
		alpha = 255 >> format->Aloss << format->Ashift;
	    }
            switch (inter->itemsize) {
            case sizeof (Uint8):
                COPYMACRO_3D(Uint32, Uint8);
                break;
            case sizeof (Uint16):
                COPYMACRO_3D(Uint32, Uint16);
                break;
            case sizeof (Uint32):
                COPYMACRO_3D(Uint32, Uint32);
                break;
            case sizeof (Uint64):
                COPYMACRO_3D(Uint32, Uint64);
                break;
            default:
                Py_DECREF(cobj);
                if (!PySurface_UnlockBy(surfobj, (PyObject *) arrayobj)) {
                    return NULL;
                }
                return RAISE(PyExc_ValueError,
                             "unsupported datatype for array\n");
            }
        }
Example #2
0
static PyObject*
array_to_surface(PyObject *self, PyObject *arg)
{
    PyObject *surfobj, *arrayobj;
    Pg_buffer pg_view;
    Py_buffer *view_p = (Py_buffer *)&pg_view;
    char *array_data;
    SDL_Surface* surf;
    SDL_PixelFormat* format;
    int loopx, loopy;
    int stridex, stridey, stridez=0, stridez2=0, sizex, sizey;
    int Rloss, Gloss, Bloss, Rshift, Gshift, Bshift;

    if (!PyArg_ParseTuple(arg, "O!O", &PySurface_Type, &surfobj, &arrayobj)) {
        return NULL;
    }
    surf = PySurface_AsSurface(surfobj);
    format = surf->format;

    if (PgObject_GetBuffer(arrayobj, &pg_view, PyBUF_RECORDS_RO)) {
        return 0;
    }

    if (_validate_view_format(view_p->format)) {
        return 0;
    }

    if (!(view_p->ndim == 2 || (view_p->ndim == 3 && view_p->shape[2] == 3))) {
        return RAISE(PyExc_ValueError, "must be a valid 2d or 3d array\n");
    }

    if (surf->format->BytesPerPixel <= 0 || surf->format->BytesPerPixel > 4)
        return RAISE(PyExc_ValueError, "unsupport bit depth for surface");

    stridex = view_p->strides[0];
    stridey = view_p->strides[1];
    if (view_p->ndim == 3) {
        stridez = view_p->strides[2];
        stridez2 = stridez*2;
    }
    else {
        stridez = 1;
        stridez2 = 2;
    }
    sizex = view_p->shape[0];
    sizey = view_p->shape[1];
    Rloss = format->Rloss; Gloss = format->Gloss; Bloss = format->Bloss;
    Rshift = format->Rshift; Gshift = format->Gshift; Bshift = format->Bshift;

    /* Do any required broadcasting. */
    if (sizex == 1) {
        sizex = surf->w;
        stridex = 0;
    }
    if (sizey == 1) {
        sizey = surf->h;
        stridey = 0;
    }

    if (sizex != surf->w || sizey != surf->h) {
        PgBuffer_Release(&pg_view);
        return RAISE(PyExc_ValueError, "array must match surface dimensions");
    }
    if (!PySurface_LockBy(surfobj, arrayobj)) {
        PgBuffer_Release(&pg_view);
        return NULL;
    }

    array_data = (char *)view_p->buf;

    switch (surf->format->BytesPerPixel) {
    case 1:
        if (view_p->ndim == 2) {
            switch (view_p->itemsize) {
            case sizeof (Uint8):
                COPYMACRO_2D(Uint8, Uint8);
                break;
            case sizeof (Uint16):
                COPYMACRO_2D(Uint8, Uint16);
                break;
            case sizeof (Uint32):
                COPYMACRO_2D(Uint8, Uint32);
                break;
            case sizeof (Uint64):
                COPYMACRO_2D(Uint8, Uint64);
                break;
            default:
                PgBuffer_Release(&pg_view);
                if (!PySurface_UnlockBy(surfobj, arrayobj)) {
                    return NULL;
                }
                return RAISE(PyExc_ValueError,
                             "unsupported datatype for array\n");
            }
        }
        else {
            PgBuffer_Release(&pg_view);
            if (!PySurface_UnlockBy(surfobj, arrayobj)) {
                return NULL;
            }
            return RAISE(PyExc_ValueError,
                         "unsupported datatype for array\n");
        }
        break;
    case 2:
        if (view_p->ndim == 2) {
            switch (view_p->itemsize) {
            case sizeof (Uint16):
                COPYMACRO_2D(Uint16, Uint16);
                break;
            case sizeof (Uint32):
                COPYMACRO_2D(Uint16, Uint32);
                break;
            case sizeof (Uint64):
                COPYMACRO_2D(Uint16, Uint64);
                break;
            default:
                PgBuffer_Release(&pg_view);
                if (!PySurface_UnlockBy(surfobj, arrayobj)) {
                    return NULL;
                }
                return RAISE(PyExc_ValueError,
                             "unsupported datatype for array\n");
            }
        }
        else {
            Uint16 alpha = 0;
            if (format->Amask) {
                alpha = 255 >> format->Aloss << format->Ashift;
            }
            switch (view_p->itemsize) {
            case sizeof (Uint8):
                COPYMACRO_3D(Uint16, Uint8);
                break;
            case sizeof (Uint16):
                COPYMACRO_3D(Uint16, Uint16);
                break;
            case sizeof (Uint32):
                COPYMACRO_3D(Uint16, Uint32);
                break;
            case sizeof (Uint64):
                COPYMACRO_3D(Uint16, Uint64);
                break;
            default:
                PgBuffer_Release(&pg_view);
                if (!PySurface_UnlockBy(surfobj, arrayobj)) {
                    return NULL;
                }
                return RAISE(PyExc_ValueError,
                             "unsupported datatype for array\n");
            }
        }
        break;
    case 3:
        /* Assumption: The rgb components of a 24 bit pixel are in
           separate bytes.
        */
        if (view_p->itemsize >= (view_p->ndim == 2 ? 3 : 1) &&
            view_p->itemsize <= 9) {
            size_t stridez_0 = 0;
            size_t stridez_1 = 0;
            size_t stridez_2 = 0;
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
            if (view_p->ndim == 2) {
                stridez_1 = 1;
                stridez_2 = 2;
            }
            else {
                size_t offset = _is_swapped(view_p) ? view_p->itemsize - 1 : 0;
                stridez_0 = ((Rshift ==  0 ?
                              0 : (Gshift ==  0 ? stridez : stridez2)) +
                             offset);
                stridez_1 = ((Rshift ==  8 ?
                              0 : (Gshift ==  8 ? stridez : stridez2)) +
                             offset);
                stridez_2 = ((Rshift == 16 ?
                              0 : (Gshift == 16 ? stridez : stridez2)) +
                             offset);
            }
#else
            if (view_p->ndim == 2) {
                stridez_0 = view_p->itemsize - 3;
                stridez_1 = stridez_0 + 1;
                stridez_2 = stridez_1 + 1;
            }
            else {
                size_t offset = _is_swapped(view_p) ? 0 : view_p->itemsize - 1;
                stridez_2 = ((Rshift ==  0 ?
                              0 : (Gshift ==  0 ? stridez : stridez2)) +
                             offset);
                stridez_1 = ((Rshift ==  8 ?
                              0 : (Gshift ==  8 ? stridez : stridez2)) +
                             offset);
                stridez_0 = ((Rshift == 16 ?
                              0 : (Gshift == 16 ? stridez : stridez2)) +
                             offset);
            }
#endif
            for (loopy = 0; loopy < sizey; ++loopy)
            {
                Uint8 *pix = ((Uint8*)surf->pixels) + surf->pitch * loopy;
                Uint8 *data = (Uint8*)array_data + stridey * loopy;
                Uint8 *end = pix + 3 * sizex;
                while (pix != end) {
                    *pix++ = *(data + stridez_0);
                    *pix++ = *(data + stridez_1);
                    *pix++ = *(data + stridez_2);
                    data += stridex;
                }
            }
        }
        else {
            PgBuffer_Release(&pg_view);
            if (!PySurface_UnlockBy(surfobj, arrayobj)) {
                return NULL;
            }
            return RAISE(PyExc_ValueError,
                         "unsupported datatype for array\n");
        }
        break;
    case 4:
        if (view_p->ndim == 2) {
            switch (view_p->itemsize) {
            case sizeof (Uint32):
                COPYMACRO_2D(Uint32, Uint32);
                break;
            case sizeof (Uint64):
                COPYMACRO_2D(Uint32, Uint64);
                break;
            default:
                PgBuffer_Release(&pg_view);
                if (!PySurface_UnlockBy(surfobj, arrayobj)) {
                    return NULL;
                }
                return RAISE(PyExc_ValueError,
                            "unsupported datatype for array\n");
            }
        }
        else {
            Uint32 alpha = 0;
            if (format->Amask) {
                alpha = 255 >> format->Aloss << format->Ashift;
            }
            switch (view_p->itemsize) {
            case sizeof (Uint8):
                COPYMACRO_3D(Uint32, Uint8);
                break;
            case sizeof (Uint16):
                COPYMACRO_3D(Uint32, Uint16);
                break;
            case sizeof (Uint32):
                COPYMACRO_3D(Uint32, Uint32);
                break;
            case sizeof (Uint64):
                COPYMACRO_3D(Uint32, Uint64);
                break;
            default:
                PgBuffer_Release(&pg_view);
                if (!PySurface_UnlockBy(surfobj, arrayobj)) {
                    return NULL;
                }
                return RAISE(PyExc_ValueError,
                             "unsupported datatype for array\n");
            }
        }