/* pygame - Python Game Library Copyright (C) 2000-2001 Pete Shinners 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 Pete Shinners pete@shinners.org */ /* * pygame Surface module */ #define PYGAMEAPI_SURFACE_INTERNAL #include "pygame.h" #include "structmember.h" staticforward PyTypeObject PySurface_Type; static PyObject* PySurface_New(SDL_Surface* info); #define PySurface_Check(x) ((x)->ob_type == &PySurface_Type) extern int pygame_AlphaBlit(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect); static PyObject* surface_new(PyTypeObject *type, PyObject *args, PyObject *kwds); static int surface_init(PySurfaceObject *self, PyObject *args, PyObject *kwds); /* surface object methods */ /*DOC*/ static char doc_surf_get_at[] = /*DOC*/ "Surface.get_at(position) -> RGBA\n" /*DOC*/ "get a pixel color\n" /*DOC*/ "\n" /*DOC*/ "Returns the RGB color values at a given pixel. If the\n" /*DOC*/ "Surface has no per-pixel alpha, the alpha will be 255 (opaque).\n" /*DOC*/ "A pixel outside the surface area will raise an IndexError.\n" /*DOC*/ "\n" /*DOC*/ "\n" /*DOC*/ "This function will need to temporarily lock the surface.\n" /*DOC*/ ; static PyObject* surf_get_at(PyObject* self, PyObject* arg) { SDL_Surface* surf = PySurface_AsSurface(self); SDL_PixelFormat* format = surf->format; Uint8* pixels = (Uint8*)surf->pixels; int x, y; Uint32 color; Uint8* pix; Uint8 r, g, b, a; if(!PyArg_ParseTuple(arg, "(ii)", &x, &y)) return NULL; if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); if(surf->flags & SDL_OPENGL) return RAISE(PyExc_SDLError, "Cannot call on OPENGL Surfaces"); if(x < 0 || x >= surf->w || y < 0 || y >= surf->h) return RAISE(PyExc_IndexError, "pixel index out of range"); if(format->BytesPerPixel < 1 || format->BytesPerPixel > 4) return RAISE(PyExc_RuntimeError, "invalid color depth for surface"); if(!PySurface_Lock(self)) return NULL; pixels = (Uint8*)surf->pixels; switch(format->BytesPerPixel) { case 1: color = (Uint32)*((Uint8*)pixels + y * surf->pitch + x); break; case 2: color = (Uint32)*((Uint16*)(pixels + y * surf->pitch) + x); break; case 3: pix = ((Uint8*)(pixels + y * surf->pitch) + x * 3); #if SDL_BYTEORDER == SDL_LIL_ENDIAN color = (pix[0]) + (pix[1]<<8) + (pix[2]<<16); #else color = (pix[2]) + (pix[1]<<8) + (pix[0]<<16); #endif break; default: /*case 4:*/ color = *((Uint32*)(pixels + y * surf->pitch) + x); break; } if(!PySurface_Unlock(self)) return NULL; SDL_GetRGBA(color, format, &r, &g, &b, &a); return Py_BuildValue("(bbbb)", r, g, b, a); } /*DOC*/ static char doc_surf_set_at[] = /*DOC*/ "Surface.set_at(position, RGBA) -> None\n" /*DOC*/ "set pixel at given position\n" /*DOC*/ "\n" /*DOC*/ "Assigns color to the image at the give position. Color can be a\n" /*DOC*/ "RGBA sequence or a mapped color integer. Setting the pixel outside\n" /*DOC*/ "the clip area or surface area will have no effect.\n" /*DOC*/ "\n" /*DOC*/ "In some situations just using the fill() function with a one-pixel\n" /*DOC*/ "sized rectangle will be quicker. Also the fill function does not\n" /*DOC*/ "require the surface to be locked.\n" /*DOC*/ "\n" /*DOC*/ "This function will need to temporarily lock the surface.\n" /*DOC*/ ; static PyObject* surf_set_at(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); SDL_PixelFormat* format = surf->format; Uint8* pixels; int x, y; Uint32 color; Uint8 rgba[4]; PyObject* rgba_obj; Uint8* byte_buf; if(!PyArg_ParseTuple(args, "(ii)O", &x, &y, &rgba_obj)) return NULL; if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); if(surf->flags & SDL_OPENGL) return RAISE(PyExc_SDLError, "Cannot call on OPENGL Surfaces"); if(format->BytesPerPixel < 1 || format->BytesPerPixel > 4) return RAISE(PyExc_RuntimeError, "invalid color depth for surface"); if(x < surf->clip_rect.x || x >= surf->clip_rect.x + surf->clip_rect.w || y < surf->clip_rect.y || y >= surf->clip_rect.y + surf->clip_rect.h) { /*out of clip area*/ RETURN_NONE } if(PyInt_Check(rgba_obj)) color = (Uint32)PyInt_AsLong(rgba_obj); else if(RGBAFromObj(rgba_obj, rgba)) color = SDL_MapRGBA(surf->format, rgba[0], rgba[1], rgba[2], rgba[3]); else return RAISE(PyExc_TypeError, "invalid color argument"); if(!PySurface_Lock(self)) return NULL; pixels = (Uint8*)surf->pixels; switch(format->BytesPerPixel) { case 1: *((Uint8*)pixels + y * surf->pitch + x) = (Uint8)color; break; case 2: *((Uint16*)(pixels + y * surf->pitch) + x) = (Uint16)color; break; case 3: byte_buf = (Uint8*)(pixels + y * surf->pitch) + x * 3; *(byte_buf + (format->Rshift >> 3)) = rgba[0]; *(byte_buf + (format->Gshift >> 3)) = rgba[1]; *(byte_buf + (format->Bshift >> 3)) = rgba[2]; break; default: /*case 4:*/ *((Uint32*)(pixels + y * surf->pitch) + x) = color; break; } if(!PySurface_Unlock(self)) return NULL; RETURN_NONE } /*DOC*/ static char doc_surf_map_rgb[] = /*DOC*/ "Surface.map_rgb(RGBA) -> int\n" /*DOC*/ "convert RGB into a mapped color\n" /*DOC*/ "\n" /*DOC*/ "Uses the Surface format to convert RGBA into a mapped color value.\n" /*DOC*/ "\n" /*DOC*/ "This function is not as needed as normal C code using SDL. The pygame\n" /*DOC*/ "functions do not used mapped colors, so there is no need to map them.\n" /*DOC*/ ; static PyObject* surf_map_rgb(PyObject* self,PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); Uint8 rgba[4]; int color; if(!RGBAFromObj(args, rgba)) return RAISE(PyExc_TypeError, "Invalid RGBA argument"); if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); color = SDL_MapRGBA(surf->format, rgba[0], rgba[1], rgba[2], rgba[3]); return PyInt_FromLong(color); } /*DOC*/ static char doc_surf_unmap_rgb[] = /*DOC*/ "Surface.unmap_rgb(color) -> RGBA\n" /*DOC*/ "convert mapped color into RGB\n" /*DOC*/ "\n" /*DOC*/ "This function returns the RGBA components for a mapped color\n" /*DOC*/ "value. If Surface has no per-pixel alpha, alpha will be 255 (opaque).\n" /*DOC*/ "\n" /*DOC*/ "This function is not as needed as normal C code using SDL. The pygame\n" /*DOC*/ "functions do not used mapped colors, so there is no need to unmap them.\n" /*DOC*/ ; static PyObject* surf_unmap_rgb(PyObject* self,PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); Uint32 col; Uint8 r, g, b, a; if(!PyArg_ParseTuple(args, "i", &col)) return NULL; if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); SDL_GetRGBA(col,surf->format, &r, &g, &b, &a); return Py_BuildValue("(bbbb)", r, g, b, a); } /*DOC*/ static char doc_surf_lock[] = /*DOC*/ "Surface.lock() -> None\n" /*DOC*/ "locks Surface for pixel access\n" /*DOC*/ "\n" /*DOC*/ "On accelerated surfaces, it is usually required to lock the\n" /*DOC*/ "surface before you can access the pixel values. To be safe, it is\n" /*DOC*/ "always a good idea to lock the surface before entering a block of\n" /*DOC*/ "code that changes or accesses the pixel values. The surface must\n" /*DOC*/ "not be locked when performing other pygame functions on it like\n" /*DOC*/ "fill and blit.\n" /*DOC*/ "\n" /*DOC*/ "You can doublecheck to really make sure a lock is needed by\n" /*DOC*/ "calling the mustlock() member. This should not be needed, since\n" /*DOC*/ "it is usually recommended to lock anyways and work with all\n" /*DOC*/ "surface types. If the surface does not need to be locked, the\n" /*DOC*/ "operation will return quickly with minute overhead.\n" /*DOC*/ "\n" /*DOC*/ "On some platforms a necessary lock can shut off some parts of the\n" /*DOC*/ "system. This is not a problem unless you leave surfaces locked\n" /*DOC*/ "for long periouds of time. Only keep the surface locked when you\n" /*DOC*/ "need the pixel access. At the same time, it is not a good too\n" /*DOC*/ "repeatedly lock and unlock the surface inside tight loops. It is\n" /*DOC*/ "fine to leave the surface locked while needed, just don't be\n" /*DOC*/ "lazy.\n" /*DOC*/ ; static PyObject* surf_lock(PyObject* self, PyObject* args) { if(!PyArg_ParseTuple(args, "")) return NULL; if(!PySurface_Lock(self)) return NULL; RETURN_NONE } /*DOC*/ static char doc_surf_unlock[] = /*DOC*/ "Surface.unlock() -> None\n" /*DOC*/ "locks Surface for pixel access\n" /*DOC*/ "\n" /*DOC*/ "After a surface has been locked, you will need to unlock it when\n" /*DOC*/ "you are done.\n" /*DOC*/ "\n" /*DOC*/ "You can doublecheck to really make sure a lock is needed by\n" /*DOC*/ "calling the mustlock() member. This should not be needed, since\n" /*DOC*/ "it is usually recommended to lock anyways and work with all\n" /*DOC*/ "surface types. If the surface does not need to be locked, the\n" /*DOC*/ "operation will return quickly with minute overhead.\n" /*DOC*/ ; static PyObject* surf_unlock(PyObject* self, PyObject* args) { if(!PyArg_ParseTuple(args, "")) return NULL; if(!PySurface_Unlock(self)) return NULL; RETURN_NONE } /*DOC*/ static char doc_surf_mustlock[] = /*DOC*/ "Surface.mustlock() -> bool\n" /*DOC*/ "check if the surface needs locking\n" /*DOC*/ "\n" /*DOC*/ "Returns true if the surface really does need locking to gain\n" /*DOC*/ "pixel access. Usually the overhead of checking before locking\n" /*DOC*/ "outweight the overhead of just locking any surface before access.\n" /*DOC*/ ; static PyObject* surf_mustlock(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); return PyInt_FromLong(SDL_MUSTLOCK(surf) || ((PySurfaceObject*)self)->subsurface); } /*DOC*/ static char doc_surf_get_locked[] = /*DOC*/ "Surface.get_locked() -> bool\n" /*DOC*/ "check if the surface needs locking\n" /*DOC*/ "\n" /*DOC*/ "Returns true if the surface is currently locked.\n" /*DOC*/ ; static PyObject* surf_get_locked(PyObject* self, PyObject* args) { PySurfaceObject* surf = (PySurfaceObject*)self; if(!PyArg_ParseTuple(args, "")) return NULL; return PyInt_FromLong(surf->surf->pixels != NULL); } /*DOC*/ static char doc_surf_get_palette[] = /*DOC*/ "Surface.get_palette() -> [[r, g, b], ...]\n" /*DOC*/ "get the palette\n" /*DOC*/ "\n" /*DOC*/ "This will return the an array of all the color indexes in the\n" /*DOC*/ "Surface's palette.\n" /*DOC*/ ; static PyObject* surf_get_palette(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); SDL_Palette* pal = surf->format->palette; PyObject* list; int i; if(!PyArg_ParseTuple(args, "")) return NULL; if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); if(!pal) return RAISE(PyExc_SDLError, "Surface has no palette to get\n"); list = PyTuple_New(pal->ncolors); if(!list) return NULL; for(i = 0;i < pal->ncolors;i++) { PyObject* color; SDL_Color* c = &pal->colors[i]; color = Py_BuildValue("(bbb)", c->r, c->g, c->b); if(!color) { Py_DECREF(list); return NULL; } PyTuple_SET_ITEM(list, i, color); } return list; } /*DOC*/ static char doc_surf_get_palette_at[] = /*DOC*/ "Surface.get_palette_at(index) -> r, g, b\n" /*DOC*/ "get a palette entry\n" /*DOC*/ "\n" /*DOC*/ "This will retreive an individual color entry from the Surface's\n" /*DOC*/ "palette.\n" /*DOC*/ ; static PyObject* surf_get_palette_at(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); SDL_Palette* pal = surf->format->palette; SDL_Color* c; int index; if(!PyArg_ParseTuple(args, "i", &index)) return NULL; if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); if(!pal) return RAISE(PyExc_SDLError, "Surface has no palette to set\n"); if(index >= pal->ncolors || index < 0) return RAISE(PyExc_IndexError, "index out of bounds"); c = &pal->colors[index]; return Py_BuildValue("(bbb)", c->r, c->g, c->b); } /*DOC*/ static char doc_surf_set_palette[] = /*DOC*/ "Surface.set_palette([[r, g, b], ...]) -> None\n" /*DOC*/ "set the palette\n" /*DOC*/ "\n" /*DOC*/ "This will replace the entire palette with color\n" /*DOC*/ "information you provide.\n" /*DOC*/ "\n" /*DOC*/ "You can pass an incomplete list of RGB values, and\n" /*DOC*/ "this will only change the first colors in the palette.\n" /*DOC*/ ; static PyObject* surf_set_palette(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); SDL_Palette* pal = surf->format->palette; SDL_Color* colors; PyObject* list, *item; int i, len; int r, g, b; if(!PyArg_ParseTuple(args, "O", &list)) return NULL; if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); if(!PySequence_Check(list)) return RAISE(PyExc_ValueError, "Argument must be a sequence type"); if(!pal) return RAISE(PyExc_SDLError, "Surface has no palette\n"); if(!SDL_WasInit(SDL_INIT_VIDEO)) return RAISE(PyExc_SDLError, "cannot set palette without pygame.display initialized"); len = min(pal->ncolors, PySequence_Length(list)); colors = (SDL_Color*)malloc(len * sizeof(SDL_Color)); if(!colors) return NULL; for(i = 0; i < len; i++) { item = PySequence_GetItem(list, i); if(!PySequence_Check(item) || PySequence_Length(item) != 3) { Py_DECREF(item); free((char*)colors); return RAISE(PyExc_TypeError, "takes a sequence of sequence of RGB"); } if(!IntFromObjIndex(item, 0, &r) || !IntFromObjIndex(item, 1, &g) || !IntFromObjIndex(item, 2, &b)) return RAISE(PyExc_TypeError, "RGB sequence must contain numeric values"); colors[i].r = (unsigned char)r; colors[i].g = (unsigned char)g; colors[i].b = (unsigned char)b; Py_DECREF(item); } SDL_SetColors(surf, colors, 0, len); free((char*)colors); RETURN_NONE } /*DOC*/ static char doc_surf_set_palette_at[] = /*DOC*/ "Surface.set_palette_at(index, [r, g, b]) -> None\n" /*DOC*/ "set a palette entry\n" /*DOC*/ "\n" /*DOC*/ "This function sets the palette color at a specific entry.\n" /*DOC*/ ; static PyObject* surf_set_palette_at(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); SDL_Palette* pal = surf->format->palette; SDL_Color color; int index; Uint8 r, g, b; if(!PyArg_ParseTuple(args, "i(bbb)", &index, &r, &g, &b)) return NULL; if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); if(!pal) { PyErr_SetString(PyExc_SDLError, "Surface is not palettized\n"); return NULL; } if(index >= pal->ncolors || index < 0) { PyErr_SetString(PyExc_IndexError, "index out of bounds"); return NULL; } if(!SDL_WasInit(SDL_INIT_VIDEO)) return RAISE(PyExc_SDLError, "cannot set palette without pygame.display initialized"); color.r = r; color.g = g; color.b = b; SDL_SetColors(surf, &color, index, 1); RETURN_NONE } /*DOC*/ static char doc_surf_set_colorkey[] = /*DOC*/ "Surface.set_colorkey([color, [flags]]) -> None\n" /*DOC*/ "change colorkey information\n" /*DOC*/ "\n" /*DOC*/ "Set the colorkey for the surface by passing a mapped color value\n" /*DOC*/ "as the color argument. If no arguments or None is passed,\n" /*DOC*/ "colorkeying will be disabled for this surface.\n" /*DOC*/ "\n" /*DOC*/ "The color argument can be either a RGBA sequence or a mapped integer.\n" /*DOC*/ "\n" /*DOC*/ "If your image is nonchanging and will be used repeatedly, you\n" /*DOC*/ "will probably want to pass the RLEACCEL flag to the call. This\n" /*DOC*/ "will take a short time to compile your surface, and increase the\n" /*DOC*/ "blitting speed.\n" /*DOC*/ ; static PyObject* surf_set_colorkey(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); Uint32 flags = 0, color = 0; PyObject* rgba_obj = NULL, *intobj = NULL; Uint8 rgba[4]; int result, hascolor=0; if(!PyArg_ParseTuple(args, "|Oi", &rgba_obj, &flags)) return NULL; if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); if(surf->flags & SDL_OPENGL) return RAISE(PyExc_SDLError, "Cannot call on OPENGL Surfaces"); if(rgba_obj && rgba_obj!=Py_None) { if(PyNumber_Check(rgba_obj) && (intobj=PyNumber_Int(rgba_obj))) { color = (Uint32)PyInt_AsLong(intobj); Py_DECREF(intobj); } else if(RGBAFromObj(rgba_obj, rgba)) color = SDL_MapRGBA(surf->format, rgba[0], rgba[1], rgba[2], rgba[3]); else return RAISE(PyExc_TypeError, "invalid color argument"); hascolor = 1; } if(hascolor) flags |= SDL_SRCCOLORKEY; PySurface_Prep(self); result = SDL_SetColorKey(surf, flags, color); PySurface_Unprep(self); if(result == -1) return RAISE(PyExc_SDLError, SDL_GetError()); RETURN_NONE } /*DOC*/ static char doc_surf_get_colorkey[] = /*DOC*/ "Surface.get_colorkey() -> RGBA\n" /*DOC*/ "query colorkey\n" /*DOC*/ "\n" /*DOC*/ "Returns the current mapped color value being used for\n" /*DOC*/ "colorkeying. If colorkeying is not enabled for this surface, it\n" /*DOC*/ "returns None\n" /*DOC*/ ; static PyObject* surf_get_colorkey(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); Uint8 r, g, b, a; if(!PyArg_ParseTuple(args, "")) return NULL; if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); if(surf->flags & SDL_OPENGL) return RAISE(PyExc_SDLError, "Cannot call on OPENGL Surfaces"); if(!(surf->flags&SDL_SRCCOLORKEY)) RETURN_NONE SDL_GetRGBA(surf->format->colorkey, surf->format, &r, &g, &b, &a); return Py_BuildValue("(bbbb)", r, g, b, a); } /*DOC*/ static char doc_surf_set_alpha[] = /*DOC*/ "Surface.set_alpha([alpha, [flags]]) -> None\n" /*DOC*/ "change alpha information\n" /*DOC*/ "\n" /*DOC*/ "Set the overall transparency for the surface. If no alpha is\n" /*DOC*/ "passed, alpha blending is disabled for the surface. An alpha of 0\n" /*DOC*/ "is fully transparent, an alpha of 255 is fully opaque. If no\n" /*DOC*/ "arguments or None is passed, this will disable the surface alpha.\n" /*DOC*/ "\n" /*DOC*/ "If your surface has a pixel alpha channel, it will override the\n" /*DOC*/ "overall surface transparency. You'll need to change the actual\n" /*DOC*/ "pixel transparency to make changes.\n" /*DOC*/ "\n" /*DOC*/ "If your image also has pixel alpha values, or will be used repeatedly, you\n" /*DOC*/ "will probably want to pass the RLEACCEL flag to the call. This\n" /*DOC*/ "will take a short time to compile your surface, and increase the\n" /*DOC*/ "blitting speed.\n" /*DOC*/ ; static PyObject* surf_set_alpha(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); Uint32 flags = 0; PyObject* alpha_obj = NULL, *intobj=NULL; Uint8 alpha; int result, alphaval=255, hasalpha=0; if(!PyArg_ParseTuple(args, "|Oi", &alpha_obj, &flags)) return NULL; if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); if(surf->flags & SDL_OPENGL) return RAISE(PyExc_SDLError, "Cannot call on OPENGL Surfaces"); if(alpha_obj && alpha_obj!=Py_None) { if(PyNumber_Check(alpha_obj) && (intobj=PyNumber_Int(alpha_obj))) { alphaval = (int)PyInt_AsLong(intobj); Py_DECREF(intobj); } else return RAISE(PyExc_TypeError, "invalid alpha argument"); hasalpha = 1; } if(hasalpha) flags |= SDL_SRCALPHA; if(alphaval>255) alpha = 255; else if(alphaval<0) alpha = 0; else alpha = (Uint8)alphaval; PySurface_Prep(self); result = SDL_SetAlpha(surf, flags, alpha); PySurface_Unprep(self); if(result == -1) return RAISE(PyExc_SDLError, SDL_GetError()); RETURN_NONE } /*DOC*/ static char doc_surf_get_alpha[] = /*DOC*/ "Surface.get_alpha() -> alpha\n" /*DOC*/ "query alpha information\n" /*DOC*/ "\n" /*DOC*/ "Returns the current alpha value for the Surface. If transparency\n" /*DOC*/ "is disabled for the Surface, it returns None.\n" /*DOC*/ ; static PyObject* surf_get_alpha(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); if(!PyArg_ParseTuple(args, "")) return NULL; if(surf->flags & SDL_OPENGL) return RAISE(PyExc_SDLError, "Cannot call on OPENGL Surfaces"); if(surf->flags&SDL_SRCALPHA) return PyInt_FromLong(surf->format->alpha); RETURN_NONE } /*DOC*/ static char doc_surf_copy[] = /*DOC*/ "Surface.copy() -> Surface\n" /*DOC*/ "creates a new copy of a Surface\n" /*DOC*/ "\n" /*DOC*/ "Creates an exact duplicate of the Surface. The new Surface will\n" /*DOC*/ "get the same palette and surface flags as the original.\n" /*DOC*/ "\n" /*DOC*/ "If the Surface is a subsurface this will return a copy of\n" /*DOC*/ "the pixel data. The new copy will not reference pixel data.\n" /*DOC*/ ; static PyObject* surf_copy(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); PyObject* final; SDL_Surface* newsurf; if(!PyArg_ParseTuple(args, "")) return NULL; if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); if(surf->flags & SDL_OPENGL) { return RAISE(PyExc_SDLError, "Cannot copy opengl display"); } PySurface_Prep(self); newsurf = SDL_ConvertSurface(surf, surf->format, surf->flags); PySurface_Unprep(self); final = PySurface_New(newsurf); if(!final) SDL_FreeSurface(newsurf); return final; } /*DOC*/ static char doc_surf_convert[] = /*DOC*/ "Surface.convert([src_surface] OR depth, [flags] OR masks) -> Surface\n" /*DOC*/ "new copy of surface with different format\n" /*DOC*/ "\n" /*DOC*/ "Creates a new copy of the surface with the desired pixel format.\n" /*DOC*/ "Surfaces with the same pixel format will blit much faster than\n" /*DOC*/ "those with mixed formats. The pixel format of the new surface\n" /*DOC*/ "will match the format given as the argument. If no surface is\n" /*DOC*/ "given, the new surface will have the same pixel format as the\n" /*DOC*/ "current display.\n" /*DOC*/ "\n" /*DOC*/ "convert() will also accept bitsize or mask arguments like the\n" /*DOC*/ "Surface() constructor function. Either pass an integer bitsize\n" /*DOC*/ "or a sequence of color masks to specify the format of surface\n" /*DOC*/ "you would like to convert to. When used this way you may also\n" /*DOC*/ "pass an optional flags argument (whew).\n" /*DOC*/ ; static PyObject* surf_convert(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); PyObject* final; PyObject* argobject=NULL; SDL_Surface* src; SDL_Surface* newsurf; Uint32 flags=-1; if(!SDL_WasInit(SDL_INIT_VIDEO)) return RAISE(PyExc_SDLError, "cannot convert without pygame.display initialized"); if(!PyArg_ParseTuple(args, "|Oi", &argobject, &flags)) return NULL; if(surf->flags & SDL_OPENGL) { return RAISE(PyExc_SDLError, "Cannot convert opengl display"); } PySurface_Prep(self); if(argobject) { if(PySurface_Check(argobject)) { src = PySurface_AsSurface(argobject); flags = src->flags | (surf->flags & (SDL_SRCCOLORKEY|SDL_SRCALPHA)); newsurf = SDL_ConvertSurface(surf, src->format, flags); } else { int bpp; SDL_PixelFormat format; memcpy(&format, surf->format, sizeof(format)); if(IntFromObj(argobject, &bpp)) { int Rmask, Gmask, Bmask, Amask; if(flags!=-1 && flags&SDL_SRCALPHA) { switch(bpp) { case 16: Rmask = 0xF<<8; Gmask = 0xF<<4; Bmask = 0xF; Amask = 0xF<<12; break; case 32: Rmask = 0xFF<<16; Gmask = 0xFF<<8; Bmask = 0xFF; Amask = 0xFF<<24; break; default: return RAISE(PyExc_ValueError, "no standard masks exist for given bitdepth with alpha"); } } else { Amask = 0; switch(bpp) { case 8: Rmask = 0xFF>>6<<5; Gmask = 0xFF>>5<<2; Bmask = 0xFF>>6; break; case 12: Rmask = 0xFF>>4<<8; Gmask = 0xFF>>4<<4; Bmask = 0xFF>>4; break; case 15: Rmask = 0xFF>>3<<10; Gmask = 0xFF>>3<<5; Bmask = 0xFF>>3; break; case 16: Rmask = 0xFF>>3<<11; Gmask = 0xFF>>2<<5; Bmask = 0xFF>>3; break; case 24: case 32: Rmask = 0xFF << 16; Gmask = 0xFF << 8; Bmask = 0xFF; break; default: return RAISE(PyExc_ValueError, "nonstandard bit depth given"); } } format.Rmask = Rmask; format.Gmask = Gmask; format.Bmask = Bmask; format.Amask = Amask; } else if(PySequence_Check(argobject) && PySequence_Size(argobject)==4) { Uint32 mask; if(!UintFromObjIndex(argobject, 0, &format.Rmask) || !UintFromObjIndex(argobject, 1, &format.Gmask) || !UintFromObjIndex(argobject, 2, &format.Bmask) || !UintFromObjIndex(argobject, 3, &format.Amask)) { PySurface_Unprep(self); return RAISE(PyExc_ValueError, "invalid color masks given"); } mask = format.Rmask|format.Gmask|format.Bmask|format.Amask; for(bpp=0; bpp<32; ++bpp) if(!(mask>>bpp)) break; } else { PySurface_Unprep(self); return RAISE(PyExc_ValueError, "invalid argument specifying new format to convert to"); } format.BitsPerPixel = (Uint8)bpp; format.BytesPerPixel = (bpp+7)/8; if(flags == -1) flags = surf->flags; if(format.Amask) flags |= SDL_SRCALPHA; newsurf = SDL_ConvertSurface(surf, &format, flags); } } else { if(SDL_WasInit(SDL_INIT_VIDEO)) newsurf = SDL_DisplayFormat(surf); else newsurf = SDL_ConvertSurface(surf, surf->format, surf->flags); } PySurface_Unprep(self); final = PySurface_New(newsurf); if(!final) SDL_FreeSurface(newsurf); return final; } /*DOC*/ static char doc_surf_convert_alpha[] = /*DOC*/ "Surface.convert_alpha([src_surface]) -> Surface\n" /*DOC*/ "new copy of surface with different format and per pixel alpha\n" /*DOC*/ "\n" /*DOC*/ "Creates a new copy of the surface with the desired pixel format.\n" /*DOC*/ "The new surface will be in a format suited for quick blitting to\n" /*DOC*/ "the given format with per pixel alpha. If no surface is given,\n" /*DOC*/ "the new surface will be optimized for blittint to the current\n" /*DOC*/ "display.\n" /*DOC*/ "\n" /*DOC*/ "Unlike the convert() method, the pixel format for the new image\n" /*DOC*/ "will not be exactly the same as the requested source, but it will\n" /*DOC*/ "be optimized for fast alpha blitting to the destination.\n" /*DOC*/ ; static PyObject* surf_convert_alpha(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); PyObject* final; PySurfaceObject* srcsurf = NULL; SDL_Surface* newsurf, *src; if(!SDL_WasInit(SDL_INIT_VIDEO)) return RAISE(PyExc_SDLError, "cannot convert without pygame.display initialized"); if(!PyArg_ParseTuple(args, "|O!", &PySurface_Type, &srcsurf)) return NULL; PySurface_Prep(self); if(srcsurf) { /*hmm, we have to figure this out, not all depths have good support for alpha*/ src = PySurface_AsSurface(srcsurf); newsurf = SDL_DisplayFormatAlpha(surf); } else newsurf = SDL_DisplayFormatAlpha(surf); PySurface_Unprep(self); final = PySurface_New(newsurf); if(!final) SDL_FreeSurface(newsurf); return final; } /*DOC*/ static char doc_surf_set_clip[] = /*DOC*/ "Surface.set_clip([rectstyle]) -> None\n" /*DOC*/ "assign destination clipping rectangle\n" /*DOC*/ "\n" /*DOC*/ "Assigns the destination clipping rectangle for the Surface. When\n" /*DOC*/ "blit or fill operations are performed on the Surface, they are\n" /*DOC*/ "restricted to the inside of the clipping rectangle. If no\n" /*DOC*/ "rectangle is passed, the clipping region is set to the entire\n" /*DOC*/ "Surface area. The rectangle you pass will be clipped to the area of\n" /*DOC*/ "the Surface.\n" /*DOC*/ ; static PyObject* surf_set_clip(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); PyObject* item; GAME_Rect *rect=NULL, temp; SDL_Rect sdlrect; int result; if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); if(PyTuple_Size(args)) { item = PyTuple_GET_ITEM(args, 0); if(!(item == Py_None && PyTuple_Size(args) == 1)) { rect = GameRect_FromObject(args, &temp); if(!rect) return RAISE(PyExc_ValueError, "invalid rectstyle object"); sdlrect.x = rect->x; sdlrect.y = rect->y; sdlrect.h = rect->h; sdlrect.w = rect->w; } result = SDL_SetClipRect(surf, &sdlrect); } else result = SDL_SetClipRect(surf, NULL); if(result == -1) return RAISE(PyExc_SDLError, SDL_GetError()); RETURN_NONE } /*DOC*/ static char doc_surf_get_clip[] = /*DOC*/ "Surface.get_clip() -> rect\n" /*DOC*/ "query the clipping area\n" /*DOC*/ "\n" /*DOC*/ "Returns the current destination clipping area being used by the\n" /*DOC*/ "Surface. If the clipping area is not set, it will return a\n" /*DOC*/ "rectangle containing the full Surface area.\n" /*DOC*/ ; static PyObject* surf_get_clip(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); return PyRect_New(&surf->clip_rect); } /*DOC*/ static char doc_surf_fill[] = /*DOC*/ "Surface.fill(color, [rectstyle])) -> Rect\n" /*DOC*/ "fill areas of a Surface\n" /*DOC*/ "\n" /*DOC*/ "Fills the specified area of the Surface with the mapped color\n" /*DOC*/ "value. If no destination rectangle is supplied, it will fill the\n" /*DOC*/ "entire Surface.\n" /*DOC*/ "\n" /*DOC*/ "The color argument can be a RGBA sequence or a mapped color integer.\n" /*DOC*/ "\n" /*DOC*/ "The fill is subject to be clipped by the active clipping\n" /*DOC*/ "rectangle. The return value contains the actual area filled.\n" /*DOC*/ ; static PyObject* surf_fill(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); GAME_Rect *rect, temp; PyObject* r = NULL; Uint32 color; int result; PyObject* rgba_obj; Uint8 rgba[4]; SDL_Rect sdlrect; if(!PyArg_ParseTuple(args, "O|O", &rgba_obj, &r)) return NULL; if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); if(surf->flags & SDL_OPENGL) return RAISE(PyExc_SDLError, "Cannot call on OPENGL Surfaces"); if(PyInt_Check(rgba_obj)) color = (Uint32)PyInt_AsLong(rgba_obj); else if(RGBAFromObj(rgba_obj, rgba)) color = SDL_MapRGBA(surf->format, rgba[0], rgba[1], rgba[2], rgba[3]); else return RAISE(PyExc_TypeError, "invalid color argument"); if(!r) { rect = &temp; temp.x = temp.y = 0; temp.w = surf->w; temp.h = surf->h; } else if(!(rect = GameRect_FromObject(r, &temp))) return RAISE(PyExc_ValueError, "invalid rectstyle object"); /*we need a fresh copy so our Rect values don't get munged*/ if(rect != &temp) { memcpy(&temp, rect, sizeof(temp)); rect = &temp; } if(rect->w < 0 || rect->h < 0) { sdlrect.x = sdlrect.y = 0; sdlrect.w = sdlrect.h = 0; } else { sdlrect.x = rect->x; sdlrect.y = rect->y; sdlrect.w = rect->w; sdlrect.h = rect->h; PySurface_Prep(self); result = SDL_FillRect(surf, &sdlrect, color); PySurface_Unprep(self); if(result == -1) return RAISE(PyExc_SDLError, SDL_GetError()); } return PyRect_New(&sdlrect); } /*this internal blit function is accessable through the C api*/ int PySurface_Blit(PyObject *dstobj, PyObject *srcobj, SDL_Rect *dstrect, SDL_Rect *srcrect) { SDL_Surface *src = PySurface_AsSurface(srcobj); SDL_Surface *dst = PySurface_AsSurface(dstobj); SDL_Surface *subsurface = NULL; int result, suboffsetx=0, suboffsety=0; SDL_Rect orig_clip, sub_clip; int didconvert = 0; /*passthrough blits to the real surface*/ if(((PySurfaceObject*)dstobj)->subsurface) { PyObject *owner; struct SubSurface_Data *subdata; subdata = ((PySurfaceObject*)dstobj)->subsurface; owner = subdata->owner; subsurface = PySurface_AsSurface(owner); suboffsetx = subdata->offsetx; suboffsety = subdata->offsety; while(((PySurfaceObject*)owner)->subsurface) { subdata = ((PySurfaceObject*)owner)->subsurface; owner = subdata->owner; subsurface = PySurface_AsSurface(owner); suboffsetx += subdata->offsetx; suboffsety += subdata->offsety; } SDL_GetClipRect(subsurface, &orig_clip); SDL_GetClipRect(dst, &sub_clip); sub_clip.x += suboffsetx; sub_clip.y += suboffsety; SDL_SetClipRect(subsurface, &sub_clip); dstrect->x += suboffsetx; dstrect->y += suboffsety; dst = subsurface; } else { PySurface_Prep(dstobj); subsurface = NULL; } PySurface_Prep(srcobj); /* Py_BEGIN_ALLOW_THREADS */ /*can't blit alpha to 8bit, crashes SDL*/ if(dst->format->BytesPerPixel==1 && (src->format->Amask || src->flags&SDL_SRCALPHA)) { didconvert = 1; src = SDL_DisplayFormat(src); } /*see if we should handle alpha ourselves*/ if(dst->format->Amask && (dst->flags&SDL_SRCALPHA) && !(src->format->Amask && !(src->flags&SDL_SRCALPHA)) && /*special case, SDL works*/ (dst->format->BytesPerPixel == 2 || dst->format->BytesPerPixel==4)) { result = pygame_AlphaBlit(src, srcrect, dst, dstrect); } else { result = SDL_BlitSurface(src, srcrect, dst, dstrect); } if(didconvert) SDL_FreeSurface(src); /* Py_END_ALLOW_THREADS */ if(subsurface) { SDL_SetClipRect(subsurface, &orig_clip); dstrect->x -= suboffsetx; dstrect->y -= suboffsety; } else PySurface_Unprep(dstobj); PySurface_Unprep(srcobj); if(result == -1) RAISE(PyExc_SDLError, SDL_GetError()); if(result == -2) RAISE(PyExc_SDLError, "Surface was lost"); return result != 0; } /*DOC*/ static char doc_surf_blit[] = /*DOC*/ "Surface.blit(source, destpos, [sourcerect]) -> Rect\n" /*DOC*/ "copy a one Surface to another.\n" /*DOC*/ "\n" /*DOC*/ "The blitting will copy pixels from the source. It will\n" /*DOC*/ "respect any special modes like colorkeying and alpha. If hardware\n" /*DOC*/ "support is available, it will be used. The given source is the\n" /*DOC*/ "Surface to copy from. The destoffset is a 2-number-sequence that\n" /*DOC*/ "specifies where on the destination Surface the blit happens (see below).\n" /*DOC*/ "When sourcerect isn't supplied, the blit will copy the\n" /*DOC*/ "entire source surface. If you would like to copy only a portion\n" /*DOC*/ "of the source, use the sourcerect argument to control\n" /*DOC*/ "what area is copied.\n" /*DOC*/ "\n" /*DOC*/ "The blit is subject to be clipped by the active clipping\n" /*DOC*/ "rectangle. The return value contains the actual area blitted.\n" /*DOC*/ "\n" /*DOC*/ "As a shortcut, the destination position can be passed as a\n" /*DOC*/ "rectangle. If a rectangle is given, the blit will use the topleft\n" /*DOC*/ "corner of the rectangle as the blit destination position. The\n" /*DOC*/ "rectangle sizes will be ignored.\n" #if 0 /* "" */ /*DOC*/ "\n" /*DOC*/ "Blitting surfaces with pixel alphas onto an 8bit destination will\n" /*DOC*/ "not use the surface alpha values.\n" #endif /* "" */ /*DOC*/ ; static PyObject* surf_blit(PyObject* self, PyObject* args) { SDL_Surface* src, *dest = PySurface_AsSurface(self); GAME_Rect* src_rect, temp; PyObject* srcobject, *argpos, *argrect = NULL; int dx, dy, result; SDL_Rect dest_rect, sdlsrc_rect; int sx, sy; if(!PyArg_ParseTuple(args, "O!O|O", &PySurface_Type, &srcobject, &argpos, &argrect)) return NULL; src = PySurface_AsSurface(srcobject); if(!dest || !src) return RAISE(PyExc_SDLError, "display Surface quit"); if(dest->flags & SDL_OPENGL && !(dest->flags&(SDL_OPENGLBLIT&~SDL_OPENGL))) return RAISE(PyExc_SDLError, "Cannot blit to OPENGL Surfaces (OPENGLBLIT is ok)"); if((src_rect = GameRect_FromObject(argpos, &temp))) { dx = src_rect->x; dy = src_rect->y; } else if(TwoIntsFromObj(argpos, &sx, &sy)) { dx = sx; dy = sy; } else return RAISE(PyExc_TypeError, "invalid destination position for blit"); if(argrect) { if(!(src_rect = GameRect_FromObject(argrect, &temp))) return RAISE(PyExc_TypeError, "Invalid rectstyle argument"); } else { temp.x = temp.y = 0; temp.w = src->w; temp.h = src->h; src_rect = &temp; } dest_rect.x = (short)dx; dest_rect.y = (short)dy; dest_rect.w = (unsigned short)src_rect->w; dest_rect.h = (unsigned short)src_rect->h; sdlsrc_rect.x = (short)src_rect->x; sdlsrc_rect.y = (short)src_rect->y; sdlsrc_rect.w = (unsigned short)src_rect->w; sdlsrc_rect.h = (unsigned short)src_rect->h; result = PySurface_Blit(self, srcobject, &dest_rect, &sdlsrc_rect); if(result != 0) return NULL; return PyRect_New(&dest_rect); } /*DOC*/ static char doc_surf_get_flags[] = /*DOC*/ "Surface.get_flags() -> flags\n" /*DOC*/ "query the surface flags\n" /*DOC*/ "\n" /*DOC*/ "Returns the current state flags for the surface.\n" /*DOC*/ ; static PyObject* surf_get_flags(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); return PyInt_FromLong(surf->flags); } /*DOC*/ static char doc_surf_get_pitch[] = /*DOC*/ "Surface.get_pitch() -> pitch\n" /*DOC*/ "query the surface pitch\n" /*DOC*/ "\n" /*DOC*/ "The surface pitch is the number of bytes used in each\n" /*DOC*/ "scanline. This function should rarely needed, mainly for\n" /*DOC*/ "any special-case debugging.\n" /*DOC*/ ; static PyObject* surf_get_pitch(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); return PyInt_FromLong(surf->pitch); } /*DOC*/ static char doc_surf_get_size[] = /*DOC*/ "Surface.get_size() -> x, y\n" /*DOC*/ "query the surface size\n" /*DOC*/ "\n" /*DOC*/ "Returns the width and height of the Surface.\n" /*DOC*/ ; static PyObject* surf_get_size(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); return Py_BuildValue("(ii)", surf->w, surf->h); } /*DOC*/ static char doc_surf_get_width[] = /*DOC*/ "Surface.get_width() -> width\n" /*DOC*/ "query the surface width\n" /*DOC*/ "\n" /*DOC*/ "Returns the width of the Surface.\n" /*DOC*/ ; static PyObject* surf_get_width(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); return PyInt_FromLong(surf->w); } /*DOC*/ static char doc_surf_get_height[] = /*DOC*/ "Surface.get_height() -> height\n" /*DOC*/ "query the surface height\n" /*DOC*/ "\n" /*DOC*/ "Returns the height of the Surface.\n" /*DOC*/ ; static PyObject* surf_get_height(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); return PyInt_FromLong(surf->h); } /*DOC*/ static char doc_surf_get_rect[] = /*DOC*/ "Surface.get_rect(**kwargs) -> rect\n" /*DOC*/ "get a rectangle covering the entire surface\n" /*DOC*/ "\n" /*DOC*/ "Returns a new rectangle covering the entire surface.\n" /*DOC*/ "This rectangle will always start at 0, 0 with a width.\n" /*DOC*/ "and height the same size as the image.\n" /*DOC*/ "\n" /*DOC*/ "You can pass keyword argument values to this function.\n" /*DOC*/ "These named values will be applied to the attributes of\n" /*DOC*/ "the Rect before it is returned. An example would be\n" /*DOC*/ "'mysurf.get_rect(center=(100,100))' to create a rectangle\n" /*DOC*/ "for the Surface centered at a given position.\n" /*DOC*/ ; static PyObject* surf_get_rect(PyObject* self, PyObject* args, PyObject* kw) { PyObject *rect; SDL_Surface* surf = PySurface_AsSurface(self); if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); rect = PyRect_New4(0, 0, surf->w, surf->h); if(rect && kw) { PyObject *key, *value; int pos=0; while(PyDict_Next(kw, &pos, &key, &value)) { if((PyObject_SetAttr(rect, key, value) == -1)) { Py_DECREF(rect); return NULL; } } } return rect; } /*DOC*/ static char doc_surf_get_bitsize[] = /*DOC*/ "Surface.get_bitsize() -> int\n" /*DOC*/ "query size of pixel\n" /*DOC*/ "\n" /*DOC*/ "Returns the number of bits used to represent each pixel. This\n" /*DOC*/ "value may not exactly fill the number of bytes used per pixel.\n" /*DOC*/ "For example a 15 bit Surface still requires a full 2 bytes.\n" /*DOC*/ ; static PyObject* surf_get_bitsize(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); return PyInt_FromLong(surf->format->BitsPerPixel); } /*DOC*/ static char doc_surf_get_bytesize[] = /*DOC*/ "Surface.get_bytesize() -> int\n" /*DOC*/ "query size of pixel\n" /*DOC*/ "\n" /*DOC*/ "Returns the number of bytes used to store each pixel.\n" /*DOC*/ ; static PyObject* surf_get_bytesize(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); return PyInt_FromLong(surf->format->BytesPerPixel); } /*DOC*/ static char doc_surf_get_masks[] = /*DOC*/ "Surface.get_masks() -> redmask, greenmask, bluemask, alphamask\n" /*DOC*/ "get mapping bitmasks for each colorplane\n" /*DOC*/ "\n" /*DOC*/ "Returns the bitmasks for each color plane. The bitmask is used to\n" /*DOC*/ "isolate each colorplane value from a mapped color value. A value\n" /*DOC*/ "of zero means that colorplane is not used (like alpha)\n" /*DOC*/ ; static PyObject* surf_get_masks(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); return Py_BuildValue("(iiii)", surf->format->Rmask, surf->format->Gmask, surf->format->Bmask, surf->format->Amask); } /*DOC*/ static char doc_surf_get_shifts[] = /*DOC*/ "Surface.get_shifts() -> redshift, greenshift, blueshift,\n" /*DOC*/ "alphashift\n" /*DOC*/ "get mapping shifts for each colorplane\n" /*DOC*/ "\n" /*DOC*/ "Returns the bitshifts used for each color plane. The shift is\n" /*DOC*/ "determine how many bits left-shifted a colorplane value is in a\n" /*DOC*/ "mapped color value.\n" /*DOC*/ ; static PyObject* surf_get_shifts(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); return Py_BuildValue("(iiii)", surf->format->Rshift, surf->format->Gshift, surf->format->Bshift, surf->format->Ashift); } /*DOC*/ static char doc_surf_get_losses[] = /*DOC*/ "Surface.get_losses() -> redloss, greenloss, blueloss, alphaloss\n" /*DOC*/ "get mapping losses for each colorplane\n" /*DOC*/ "\n" /*DOC*/ "Returns the bitloss for each color plane. The loss is the number\n" /*DOC*/ "of bits removed for each colorplane from a full 8 bits of\n" /*DOC*/ "resolution. A value of 8 usually indicates that colorplane is not\n" /*DOC*/ "used (like the alpha)\n" /*DOC*/ ; static PyObject* surf_get_losses(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); return Py_BuildValue("(iiii)", surf->format->Rloss, surf->format->Gloss, surf->format->Bloss, surf->format->Aloss); } /*DOC*/ static char doc_surf_subsurface[] = /*DOC*/ "Surface.subsurface(rectstyle) -> Surface\n" /*DOC*/ "create a new surface that shares pixel data\n" /*DOC*/ "\n" /*DOC*/ "Creates a new surface that shares pixel data of the given surface.\n" /*DOC*/ "Note that only the pixel data is shared. Things like clipping rectangles\n" /*DOC*/ "and colorkeys will be unique for the new surface.\n" /*DOC*/ "\n" /*DOC*/ "The new subsurface will inherit the palette, colorkey, and surface alpha\n" /*DOC*/ "values from the base image.\n" /*DOC*/ "\n" /*DOC*/ "You should not use the RLEACCEL flag for parent surfaces of subsurfaces,\n" /*DOC*/ "for the most part it will work, but it will cause a lot of extra work,\n" /*DOC*/ "every time you change the subsurface, you must decode and recode the\n" /*DOC*/ "RLEACCEL data for the parent surface.\n" /*DOC*/ "\n" /*DOC*/ "As for using RLEACCEL with the subsurfaces, that will work as you'd\n" /*DOC*/ "expect, but changes the the parent Surface will not always take effect\n" /*DOC*/ "in the subsurface.\n" /*DOC*/ ; static PyObject* surf_subsurface(PyObject* self, PyObject* args) { SDL_Surface* surf = PySurface_AsSurface(self); SDL_PixelFormat* format = surf->format; GAME_Rect *rect, temp; SDL_Surface* sub; PyObject* subobj; int pixeloffset; char* startpixel; struct SubSurface_Data* data; if(!surf) return RAISE(PyExc_SDLError, "display Surface quit"); if(surf->flags & SDL_OPENGL) return RAISE(PyExc_SDLError, "Cannot call on OPENGL Surfaces"); if(!(rect = GameRect_FromObject(args, &temp))) return RAISE(PyExc_ValueError, "invalid rectstyle argument"); if(rect->x < 0 || rect-> y < 0 || rect->x + rect->w > surf->w || rect->y + rect->h > surf->h) return RAISE(PyExc_ValueError, "subsurface rectangle outside surface area"); PySurface_Lock(self); pixeloffset = rect->x * format->BytesPerPixel + rect->y * surf->pitch; startpixel = ((char*)surf->pixels) + pixeloffset; sub = SDL_CreateRGBSurfaceFrom(startpixel, rect->w, rect->h, format->BitsPerPixel, \ surf->pitch, format->Rmask, format->Gmask, format->Bmask, format->Amask); PySurface_Unlock(self); if(!sub) return RAISE(PyExc_SDLError, SDL_GetError()); /*copy the colormap if we need it*/ if(surf->format->BytesPerPixel == 1 && surf->format->palette) SDL_SetPalette(sub, SDL_LOGPAL, surf->format->palette->colors, 0, surf->format->palette->ncolors); if(surf->flags & SDL_SRCALPHA) SDL_SetAlpha(sub, surf->flags&SDL_SRCALPHA, format->alpha); if(surf->flags & SDL_SRCCOLORKEY) SDL_SetColorKey(sub, surf->flags&(SDL_SRCCOLORKEY|SDL_RLEACCEL), format->colorkey); data = PyMem_New(struct SubSurface_Data, 1); if(!data) return NULL; subobj = PySurface_New(sub); if(!subobj) { PyMem_Del(data); return NULL; } Py_INCREF(self); data->owner = self; data->pixeloffset = pixeloffset; data->offsetx = rect->x; data->offsety = rect->y; ((PySurfaceObject*)subobj)->subsurface = data; return subobj; } /*DOC*/ static char doc_surf_get_offset[] = /*DOC*/ "Surface.get_offset() -> x, y\n" /*DOC*/ "get offset of subsurface\n" /*DOC*/ "\n" /*DOC*/ "Returns the X and Y position a subsurface is positioned\n" /*DOC*/ "inside its parent. Will return 0,0 for surfaces that are\n" /*DOC*/ "not a subsurface.\n" /*DOC*/ ; static PyObject* surf_get_offset(PyObject* self, PyObject* args) { struct SubSurface_Data *subdata; subdata = ((PySurfaceObject*)self)->subsurface; if(!subdata) return Py_BuildValue("(ii)", 0, 0); return Py_BuildValue("(ii)", subdata->offsetx, subdata->offsety); } /*DOC*/ static char doc_surf_get_abs_offset[] = /*DOC*/ "Surface.get_abs_offset() -> x, y\n" /*DOC*/ "get absolute offset of subsurface\n" /*DOC*/ "\n" /*DOC*/ "Returns the absolute X and Y position a subsurface is positioned\n" /*DOC*/ "inside its top level parent. Will return 0,0 for surfaces that are\n" /*DOC*/ "not a subsurface.\n" /*DOC*/ ; static PyObject* surf_get_abs_offset(PyObject* self, PyObject* args) { struct SubSurface_Data *subdata; PyObject *owner; int offsetx, offsety; subdata = ((PySurfaceObject*)self)->subsurface; if(!subdata) return Py_BuildValue("(ii)", 0, 0); subdata = ((PySurfaceObject*)self)->subsurface; owner = subdata->owner; offsetx = subdata->offsetx; offsety = subdata->offsety; while(((PySurfaceObject*)owner)->subsurface) { subdata = ((PySurfaceObject*)owner)->subsurface; owner = subdata->owner; offsetx += subdata->offsetx; offsety += subdata->offsety; } return Py_BuildValue("(ii)", offsetx, offsety); } /*DOC*/ static char doc_surf_get_parent[] = /*DOC*/ "Surface.get_parent() -> Surface\n" /*DOC*/ "get a subsurface parent\n" /*DOC*/ "\n" /*DOC*/ "Returns the Surface that is a parent of this subsurface.\n" /*DOC*/ "Will return None if this is not a subsurface.\n" /*DOC*/ ; static PyObject* surf_get_parent(PyObject* self, PyObject* args) { struct SubSurface_Data *subdata; subdata = ((PySurfaceObject*)self)->subsurface; if(!subdata) RETURN_NONE Py_INCREF(subdata->owner); return subdata->owner; } /*DOC*/ static char doc_surf_get_abs_parent[] = /*DOC*/ "Surface.get_abs_parent() -> Surface\n" /*DOC*/ "get the toplevel surface for a subsurface\n" /*DOC*/ "\n" /*DOC*/ "Returns the top level Surface for this subsurface. If this is not\n" /*DOC*/ "a subsurface it will return a reference to itself. You will always\n" /*DOC*/ "get a valid surface from this method.\n" /*DOC*/ ; static PyObject* surf_get_abs_parent(PyObject* self, PyObject* args) { struct SubSurface_Data *subdata; PyObject *owner; subdata = ((PySurfaceObject*)self)->subsurface; if(!subdata) { Py_INCREF(self); return self; } subdata = ((PySurfaceObject*)self)->subsurface; owner = subdata->owner; while(((PySurfaceObject*)owner)->subsurface) { subdata = ((PySurfaceObject*)owner)->subsurface; owner = subdata->owner; } Py_INCREF(owner); return owner; } static struct PyMethodDef surface_methods[] = { {"get_at", surf_get_at, 1, doc_surf_get_at }, {"set_at", surf_set_at, 1, doc_surf_set_at }, {"map_rgb", surf_map_rgb, 1, doc_surf_map_rgb }, {"unmap_rgb", surf_unmap_rgb, 1, doc_surf_unmap_rgb }, {"get_palette", surf_get_palette, 1, doc_surf_get_palette }, {"get_palette_at", surf_get_palette_at,1, doc_surf_get_palette_at }, {"set_palette", surf_set_palette, 1, doc_surf_set_palette }, {"set_palette_at", surf_set_palette_at,1, doc_surf_set_palette_at }, {"lock", surf_lock, 1, doc_surf_lock }, {"unlock", surf_unlock, 1, doc_surf_unlock }, {"mustlock", surf_mustlock, 1, doc_surf_mustlock }, {"get_locked", surf_get_locked, 1, doc_surf_get_locked }, {"set_colorkey", surf_set_colorkey, 1, doc_surf_set_colorkey }, {"get_colorkey", surf_get_colorkey, 1, doc_surf_get_colorkey }, {"set_alpha", surf_set_alpha, 1, doc_surf_set_alpha }, {"get_alpha", surf_get_alpha, 1, doc_surf_get_alpha }, {"copy", surf_copy, 1, doc_surf_copy }, {"__copy__", surf_copy, 1, NULL }, {"convert", surf_convert, 1, doc_surf_convert }, {"convert_alpha", surf_convert_alpha, 1, doc_surf_convert_alpha }, {"set_clip", surf_set_clip, 1, doc_surf_set_clip }, {"get_clip", surf_get_clip, 1, doc_surf_get_clip }, {"fill", surf_fill, 1, doc_surf_fill }, {"blit", surf_blit, 1, doc_surf_blit }, {"get_flags", surf_get_flags, 1, doc_surf_get_flags }, {"get_size", surf_get_size, 1, doc_surf_get_size }, {"get_width", surf_get_width, 1, doc_surf_get_width }, {"get_height", surf_get_height, 1, doc_surf_get_height }, {"get_rect", (PyCFunction)surf_get_rect, METH_KEYWORDS, doc_surf_get_rect }, {"get_pitch", surf_get_pitch, 1, doc_surf_get_pitch }, {"get_bitsize", surf_get_bitsize, 1, doc_surf_get_bitsize }, {"get_bytesize", surf_get_bytesize, 1, doc_surf_get_bytesize }, {"get_masks", surf_get_masks, 1, doc_surf_get_masks }, {"get_shifts", surf_get_shifts, 1, doc_surf_get_shifts }, {"get_losses", surf_get_losses, 1, doc_surf_get_losses }, {"subsurface", surf_subsurface, 1, doc_surf_subsurface }, {"get_offset", surf_get_offset, 1, doc_surf_get_offset }, {"get_abs_offset", surf_get_abs_offset, 1, doc_surf_get_abs_offset }, {"get_parent", surf_get_parent, 1, doc_surf_get_parent }, {"get_abs_parent", surf_get_abs_parent, 1, doc_surf_get_abs_parent }, {NULL, NULL} }; /* surface object internals */ static void surface_cleanup(PySurfaceObject* self) { if(self->surf) { if(!(self->surf->flags&SDL_HWSURFACE) || SDL_WasInit(SDL_INIT_VIDEO)) { /*unsafe to free hardware surfaces without video init*/ /*i question SDL's ability to free a locked hardware surface*/ SDL_FreeSurface(self->surf); } self->surf = NULL; } if(self->subsurface) { Py_XDECREF(self->subsurface->owner); PyMem_Del(self->subsurface); self->subsurface = NULL; } if(self->dependency) { Py_DECREF(self->dependency); self->dependency = NULL; } } static void surface_dealloc(PyObject* self) { if(((PySurfaceObject*)self)->weakreflist) { PyObject_ClearWeakRefs(self); } surface_cleanup((PySurfaceObject*)self); self->ob_type->tp_free(self); } PyObject* surface_str(PyObject* self) { char str[1024]; SDL_Surface* surf = PySurface_AsSurface(self); const char* type; if(surf) { type = (surf->flags&SDL_HWSURFACE)?"HW":"SW"; sprintf(str, "", surf->w, surf->h, surf->format->BitsPerPixel, type); } else { strcpy(str, ""); } return PyString_FromString(str); } #if 0 /*DOC*/ static char doc_Surface_MODULE[] = /*DOC*/ "Surface objects represent a simple memory buffer of pixels.\n" /*DOC*/ "Surface objects can reside in system memory, or in special\n" /*DOC*/ "hardware memory, which can be hardware accelerated. Surfaces that\n" /*DOC*/ "are 8 bits per pixel use a colormap to represent their color\n" /*DOC*/ "values. All Surfaces with higher bits per pixel use a packed\n" /*DOC*/ "pixels to store their color values.\n" /*DOC*/ "\n" /*DOC*/ "Creating a new Surface().\n" /*DOC*/ "\n" /*DOC*/ "Surfaces can have many extra attributes like alpha planes,\n" /*DOC*/ "colorkeys, source rectangle clipping. These functions mainly\n" /*DOC*/ "effect how the Surface is blitted to other Surfaces. The blit\n" /*DOC*/ "routines will attempt to use hardware acceleration when possible,\n" /*DOC*/ "otherwise will use highly optimized software blitting methods.\n" /*DOC*/ "\n" /*DOC*/ "There is support for pixel access for the Surfaces. Pixel access\n" /*DOC*/ "on hardware surfaces is slow and not recommended. Pixels can be\n" /*DOC*/ "accessed using the get_at() and set_at() functions. These methods\n" /*DOC*/ "are fine for simple access, but will be considerably slow when\n" /*DOC*/ "doing of pixel work with them. If you plan on doing a lot of\n" /*DOC*/ "pixel level work, it is recommended to use the pygame.surfarray\n" /*DOC*/ "module, which can treat the surfaces like large multidimensional\n" /*DOC*/ "arrays (and it's quite quick).\n" /*DOC*/ ; #endif /*DOC*/ static char doc_Surface[] = /*DOC*/ "pygame.Surface(size, [flags, [Surface|depth, [masks]]]) -> Surface\n" /*DOC*/ "create a new Surface\n" /*DOC*/ "\n" /*DOC*/ "Creates a new surface object. Size is a 2-int-sequence containing\n" /*DOC*/ "width and height. Depth is the number of bits used per pixel. If\n" /*DOC*/ "omitted, depth will use the current display depth. Masks is a\n" /*DOC*/ "four item sequence containing the bitmask for r,g,b, and a. If\n" /*DOC*/ "omitted, masks will default to the usual values for the given\n" /*DOC*/ "bitdepth. Flags is a mix of the following flags: SWSURFACE,\n" /*DOC*/ "HWSURFACE, ASYNCBLIT, or SRCALPHA. (flags = 0 is the\n" /*DOC*/ "same as SWSURFACE). Depth and masks can be substituted for\n" /*DOC*/ "another surface object which will create the new surface with the\n" /*DOC*/ "same format as the given one. When using default masks, alpha\n" /*DOC*/ "will always be ignored unless you pass SRCALPHA as a flag.\n" /*DOC*/ "For a plain software surface, 0 can be used for the flag. \n" /*DOC*/ "A plain hardware surface can just use 1 for the flag.\n" /*DOC*/ ; static PyTypeObject PySurface_Type = { PyObject_HEAD_INIT(NULL) 0, /*size*/ "pygame.Surface", /*name*/ sizeof(PySurfaceObject), /*basic size*/ 0, /*itemsize*/ surface_dealloc, /*dealloc*/ 0, /*print*/ NULL, /*getattr*/ NULL, /*setattr*/ NULL, /*compare*/ surface_str, /*repr*/ NULL, /*as_number*/ NULL, /*as_sequence*/ NULL, /*as_mapping*/ (hashfunc)NULL, /*hash*/ (ternaryfunc)NULL, /*call*/ (reprfunc)NULL, /*str*/ 0, 0L,0L, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ doc_Surface, /* Documentation string */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ offsetof(PySurfaceObject, weakreflist), /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ surface_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)surface_init, /* tp_init */ 0, /* tp_alloc */ surface_new, /* tp_new */ }; static PyObject* PySurface_New(SDL_Surface* s) { PySurfaceObject* self; if(!s) return RAISE(PyExc_SDLError, SDL_GetError()); self = (PySurfaceObject *)PySurface_Type.tp_new(&PySurface_Type, NULL, NULL); if(self) { self->surf = s; } return (PyObject*)self; } static PyObject* surface_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PySurfaceObject *self; self = (PySurfaceObject *)type->tp_alloc(type, 0); if (self) { self->surf = NULL; self->subsurface = NULL; self->weakreflist = NULL; } return (PyObject *)self; } static int surface_init(PySurfaceObject *self, PyObject *args, PyObject *kwds) { Uint32 flags = 0; int width, height; PyObject *depth=NULL, *masks=NULL; int bpp; Uint32 Rmask, Gmask, Bmask, Amask; SDL_Surface* surface; SDL_PixelFormat default_format; if(!PyArg_ParseTuple(args, "(ii)|iOO", &width, &height, &flags, &depth, &masks)) return -1; if(width < 0 || height < 0) { RAISE(PyExc_SDLError, "Invalid resolution for Surface"); return -1; } surface_cleanup(self); if(depth && masks) /*all info supplied, most errorchecking needed*/ { if(PySurface_Check(depth)) return (int)RAISE(PyExc_ValueError, "cannot pass surface for depth and color masks"); if(!IntFromObj(depth, &bpp)) return (int)RAISE(PyExc_ValueError, "invalid bits per pixel depth argument"); if(!PySequence_Check(masks) || PySequence_Length(masks)!=4) return (int)RAISE(PyExc_ValueError, "masks argument must be sequence of four numbers"); if(!UintFromObjIndex(masks, 0, &Rmask) || !UintFromObjIndex(masks, 1, &Gmask) || !UintFromObjIndex(masks, 2, &Bmask) || !UintFromObjIndex(masks, 3, &Amask)) return (int)RAISE(PyExc_ValueError, "invalid mask values in masks sequence"); } else if(depth && PyNumber_Check(depth))/*use default masks*/ { if(!IntFromObj(depth, &bpp)) return (int)RAISE(PyExc_ValueError, "invalid bits per pixel depth argument"); if(flags & SDL_SRCALPHA) { switch(bpp) { case 16: Rmask = 0xF<<8; Gmask = 0xF<<4; Bmask = 0xF; Amask = 0xF<<12; break; case 32: Rmask = 0xFF<<16; Gmask = 0xFF<<8; Bmask = 0xFF; Amask = 0xFF<<24; break; default: return (int)RAISE(PyExc_ValueError, "no standard masks exist for given bitdepth with alpha"); } } else { Amask = 0; switch(bpp) { case 8: Rmask = 0xFF>>6<<5; Gmask = 0xFF>>5<<2; Bmask = 0xFF>>6; break; case 12: Rmask = 0xFF>>4<<8; Gmask = 0xFF>>4<<4; Bmask = 0xFF>>4; break; case 15: Rmask = 0xFF>>3<<10; Gmask = 0xFF>>3<<5; Bmask = 0xFF>>3; break; case 16: Rmask = 0xFF>>3<<11; Gmask = 0xFF>>2<<5; Bmask = 0xFF>>3; break; case 24: case 32: Rmask = 0xFF<<16; Gmask = 0xFF<<8; Bmask = 0xFF; break; default: return (int)RAISE(PyExc_ValueError, "nonstandard bit depth given"); } } } else /*no depth or surface*/ { SDL_PixelFormat* pix; if(depth && PySurface_Check(depth)) pix = ((PySurfaceObject*)depth)->surf->format; else if(SDL_GetVideoSurface()) pix = SDL_GetVideoSurface()->format; else if(SDL_WasInit(SDL_INIT_VIDEO)) pix = SDL_GetVideoInfo()->vfmt; else { pix = &default_format; pix->BitsPerPixel = 32; pix->Amask = 0; pix->Rmask = 0xFF0000; pix->Gmask = 0xFF00; pix->Bmask = 0xFF; } bpp = pix->BitsPerPixel; Rmask = pix->Rmask; Gmask = pix->Gmask; Bmask = pix->Bmask; Amask = pix->Amask; } surface = SDL_CreateRGBSurface(flags, width, height, bpp, Rmask, Gmask, Bmask, Amask); if(!surface) { RAISE(PyExc_SDLError, SDL_GetError()); return -1; } if(surface) { self->surf = surface; self->subsurface = NULL; } return 0; } static PyMethodDef surface_builtins[] = { { NULL, NULL } }; /*DOC*/ static char doc_pygame_surface_MODULE[] = /*DOC*/ "The surface module doesn't have much in the line of functions. It\n" /*DOC*/ "does have the Surface object, and one routine to create new\n" /*DOC*/ "surfaces, pygame.Surface().\n" /*DOC*/ ; PYGAME_EXPORT void initsurface(void) { PyObject *module, *dict, *apiobj, *lockmodule; static void* c_api[PYGAMEAPI_SURFACE_NUMSLOTS]; if (PyType_Ready(&PySurface_Type) < 0) return; /* create the module */ module = Py_InitModule3("surface", surface_builtins, doc_pygame_surface_MODULE); dict = PyModule_GetDict(module); PyDict_SetItemString(dict, "SurfaceType", (PyObject *)&PySurface_Type); PyDict_SetItemString(dict, "Surface", (PyObject *)&PySurface_Type); /* export the c api */ c_api[0] = &PySurface_Type; c_api[1] = PySurface_New; c_api[2] = PySurface_Blit; apiobj = PyCObject_FromVoidPtr(c_api, NULL); PyDict_SetItemString(dict, PYGAMEAPI_LOCAL_ENTRY, apiobj); Py_DECREF(apiobj); Py_INCREF(PySurface_Type.tp_dict); PyDict_SetItemString(dict, "_dict", PySurface_Type.tp_dict); /*imported needed apis*/ import_pygame_base(); import_pygame_rect(); /*import the surflock module manually*/ lockmodule = PyImport_ImportModule("pygame.surflock"); if(lockmodule != NULL) { PyObject *dict = PyModule_GetDict(lockmodule); PyObject *c_api = PyDict_GetItemString(dict, PYGAMEAPI_LOCAL_ENTRY); if(PyCObject_Check(c_api)) { int i; void** localptr = (void*)PyCObject_AsVoidPtr(c_api); for(i = 0; i < PYGAMEAPI_SURFLOCK_NUMSLOTS; ++i) PyGAME_C_API[i + PYGAMEAPI_SURFLOCK_FIRSTSLOT] = localptr[i]; } Py_DECREF(lockmodule); } }