Commits

pygame  committed 4af4396

surfarray bugfixes
Surface constructor is smarter with SRCALPHA
surfdemo example and tutorial

  • Participants
  • Parent commits ea2f464

Comments (0)

Files changed (6)

 # BREAK = change breaks existing code
 # BUG   = fixed a bug that was crashing
 
+Mar 17, 2001
+	pygame.Surface is smarter with SRCALPHA flag
+	fixed several small bugs in surfarray [BUG]
+	new surfarray example and tutorial
+
 Mar 16, 2001
 	Fixed memory leak in Rect constructor
 	Fixed improper exception in update.display

File docs/index.html

 </li>
 <li><a href=tut/Executable.html>tut/Executable</a> - Creating a Standalone Windows Executable
 </li>
+<li><a href=tut/SurfarrayIntro.html>tut/SurfarrayIntro</a> - Introduction to the surfarray module
+</li>
 
 <hr>
 

File docs/ref/pygame.html

 
 <a name=Surface><font size=+2><b>Surface
 </b></font><br><font size=+1><tt>
-pygame.Surface(size, [flags, [depth|Surface, [masks]]]) -> Surface
+pygame.Surface(size, [flags, [Surface|depth, [masks]]]) -> Surface
 </tt></font><ul>
 Creates a new surface object. Size is a 2-int-sequence containing
 width and height. Depth is the number of bits used per pixel. If
 four item sequence containing the bitmask for r,g,b, and a. If
 omitted, masks will default to the usual values for the given
 bitdepth. Flags is a mix of the following flags: SWSURFACE,
-HWSURFACE, ASYNCBLIT, SRCCOLORKEY, or SRCALPHA. (flags = 0 is the
-same as SWSURFACE). depth and masks can be substituted for
+HWSURFACE, ASYNCBLIT, or SRCALPHA. (flags = 0 is the
+same as SWSURFACE). Depth and masks can be substituted for
 another surface object which will create the new surface with the
 same format as the given one. When using default masks, alpha
-will always be ignored. Note, if you pass SRCOLORKEY and/or
-SRCALPHA, the surface won't immediately have these features
-enabled. SDL will use these flags to help optimize the surface
-for use with the blitters. Also, for a plain software surface, 0
-can be used for the flag. A plain hardware surface can just use 1
-for the flag.
+will always be ignored unless you pass SRCALPHA as a flag.
+For a plain software surface, 0 can be used for the flag. 
+A plain hardware surface can just use 1 for the flag.
 </ul><br>&nbsp;<br>
 
 <a name=get_error><font size=+2><b>get_error

File examples/Readme.txt

     image. If you're not prepared to start working with the
     Numeric arrays, don't worry about the source for this one :]
 
+arraydemo.py - Another example filled with various surfarray
+    effects. It requires the surfarray and image modules to
+    be installed. This little demo can also make a good starting
+    point for any of your own tests with surfarray
+
 sound.py - Extremely basic testing of the mixer module. Load a
 	sound and play it. All from the command shell, no graphics.
 

File src/surface.c

 /* surface module functions */
 
     /*DOC*/ static char doc_Surface[] =
-    /*DOC*/    "pygame.Surface(size, [flags, [depth|Surface, [masks]]]) -> Surface\n"
+    /*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*/    "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, SRCCOLORKEY, or SRCALPHA. (flags = 0 is the\n"
-    /*DOC*/    "same as SWSURFACE). depth and masks can be substituted for\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. Note, if you pass SRCOLORKEY and/or\n"
-    /*DOC*/    "SRCALPHA, the surface won't immediately have these features\n"
-    /*DOC*/    "enabled. SDL will use these flags to help optimize the surface\n"
-    /*DOC*/    "for use with the blitters. Also, for a plain software surface, 0\n"
-    /*DOC*/    "can be used for the flag. A plain hardware surface can just use 1\n"
-    /*DOC*/    "for the flag.\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 PyObject* Surface(PyObject* self, PyObject* arg)
 		return NULL;
 
 	VIDEO_INIT_CHECK();
-		
+
 	if(depth && masks) /*all info supplied, most errorchecking needed*/
 	{
 		if(PySurface_Check(depth))
 	{
 		if(!ShortFromObj(depth, &bpp))
 			return RAISE(PyExc_ValueError, "invalid bits per pixel depth argument");
-		Amask = 0;
-		switch(bpp)
+		if(flags & SDL_SRCALPHA)
 		{
-		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, "no standard masks exist for given bitdepth");
+			switch(bpp)
+			{
+			case 16:
+				Rmask = 0xFF >> 3 << 11; Gmask = 0xFF >> 2 << 5; Bmask = 0xFF >> 3; Amask = 0x01 << 15; 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, "no standard masks exist for given bitdepth");
+			}
 		}
 	}
 	else /*no depth or surface*/

File src/surfarray.c

 static PyObject* pixels3d(PyObject* self, PyObject* arg)
 {
 	int dim[3];
-	PyObject* array;
+	PyObject* array, *surfobj;
 	SDL_Surface* surf;
 	char* startpixel;
 	int pixelstep;
 	const int lilendian = (SDL_BYTEORDER == SDL_LIL_ENDIAN);
 	PyObject* lifelock;
 	
-	if(!PyArg_ParseTuple(arg, "O!", &PySurface_Type, &array))
+	if(!PyArg_ParseTuple(arg, "O!", &PySurface_Type, &surfobj))
 		return NULL;
-	surf = PySurface_AsSurface(array);
+	surf = PySurface_AsSurface(surfobj);
 
 	if(surf->format->BytesPerPixel <= 2 || surf->format->BytesPerPixel > 4)
 		return RAISE(PyExc_ValueError, "unsupport bit depth for 3D reference array");
 
-	lifelock = PySurface_LockLifetime(array);
+	lifelock = PySurface_LockLifetime(surfobj);
 	if(!lifelock) return NULL;
 
 	/*must discover information about how data is packed*/
 	int types[] = {PyArray_UBYTE, PyArray_SHORT, 0, PyArray_INT};
 	int dim[3];
 	int type;
-	PyObject* array;
+	PyObject *array, *surfobj;
 	SDL_Surface* surf;
+	PyObject* lifelock;
 
-	if(!PyArg_ParseTuple(arg, "O!", &PySurface_Type, &array))
+	if(!PyArg_ParseTuple(arg, "O!", &PySurface_Type, &surfobj))
 		return NULL;
-	surf = PySurface_AsSurface(array);
+	surf = PySurface_AsSurface(surfobj);
 
 
 	if(surf->format->BytesPerPixel == 3 || surf->format->BytesPerPixel < 1 || surf->format->BytesPerPixel > 4)
 		return RAISE(PyExc_ValueError, "unsupport bit depth for 2D reference array");
 
+	lifelock = PySurface_LockLifetime(surfobj);
+	if(!lifelock) return NULL;
+
 	dim[0] = surf->w;
 	dim[1] = surf->h;
 	type = types[surf->format->BytesPerPixel-1];
 		((PyArrayObject*)array)->strides[1] = surf->pitch;
 		((PyArrayObject*)array)->strides[0] = surf->format->BytesPerPixel;
 		((PyArrayObject*)array)->flags = OWN_DIMENSIONS|OWN_STRIDES;
+		((PyArrayObject*)array)->base = lifelock;
 	}
 	return array;
 }
 static PyObject* pixels_alpha(PyObject* self, PyObject* arg)
 {
 	int dim[3];
-	PyObject* array;
+	PyObject *array, *surfobj;
+	PyObject* lifelock;
 	SDL_Surface* surf;
 	char* startpixel;
 	const int lilendian = (SDL_BYTEORDER == SDL_LIL_ENDIAN);
 
-	if(!PyArg_ParseTuple(arg, "O!", &PySurface_Type, &array))
+	if(!PyArg_ParseTuple(arg, "O!", &PySurface_Type, &surfobj))
 		return NULL;
-	surf = PySurface_AsSurface(array);
+	surf = PySurface_AsSurface(surfobj);
 
 	if(surf->format->BytesPerPixel != 4)
 		return RAISE(PyExc_ValueError, "unsupport bit depth for alpha array");
 
+	lifelock = PySurface_LockLifetime(surfobj);
+	if(!lifelock) return NULL;
+
 	/*must discover information about how data is packed*/
 	if(surf->format->Amask == 0xff<<24)
 		startpixel = ((char*)surf->pixels) + (lilendian ? 0 : 3);
 		((PyArrayObject*)array)->strides[1] = surf->pitch;
 		((PyArrayObject*)array)->strides[0] = surf->format->BytesPerPixel;
 		((PyArrayObject*)array)->flags = OWN_DIMENSIONS|OWN_STRIDES;
+		((PyArrayObject*)array)->base = lifelock;
 	}
 	return array;
 }
 {
 	int dim[2], loopy;
 	Uint8* data;
-	PyObject* array;
+	PyObject *surfobj, *array;
 	SDL_Surface* surf;
 	int stridex, stridey;
 
-	if(!PyArg_ParseTuple(arg, "O!", &PySurface_Type, &array))
+	if(!PyArg_ParseTuple(arg, "O!", &PySurface_Type, &surfobj))
 		return NULL;
-	surf = PySurface_AsSurface(array);
+	surf = PySurface_AsSurface(surfobj);
 
 	dim[0] = surf->w;
 	dim[1] = surf->h;
 
 	if(surf->format->BytesPerPixel <= 0 || surf->format->BytesPerPixel > 4)
 		return RAISE(PyExc_ValueError, "unsupport bit depth for surface array");
-
 	array = PyArray_FromDims(2, dim, PyArray_INT);
 	if(!array) return NULL;
 
 	stridex = ((PyArrayObject*)array)->strides[0];
 	stridey = ((PyArrayObject*)array)->strides[1];
 
-	if(!PySurface_Lock(array)) return NULL;
+	if(!PySurface_Lock(surfobj)) return NULL;
 
 	switch(surf->format->BytesPerPixel)
 	{
 		}break;
 	}
 
-	if(!PySurface_Unlock(array)) return NULL;
+	if(!PySurface_Unlock(surfobj)) return NULL;
 	return array;
 }
 
 {
 	int dim[3], loopy;
 	Uint8* data;
-	PyObject* array;
+	PyObject *array, *surfobj;
 	SDL_Surface* surf;
 	SDL_PixelFormat* format;
 	int Rmask, Gmask, Bmask, Rshift, Gshift, Bshift;
 	int stridex, stridey;
 	SDL_Color* palette;
 
-	if(!PyArg_ParseTuple(arg, "O!", &PySurface_Type, &array))
+	if(!PyArg_ParseTuple(arg, "O!", &PySurface_Type, &surfobj))
 		return NULL;
-	surf = PySurface_AsSurface(array);
+	surf = PySurface_AsSurface(surfobj);
 
 	format = surf->format;
 	dim[0] = surf->w;
 	stridex = ((PyArrayObject*)array)->strides[0];
 	stridey = ((PyArrayObject*)array)->strides[1];
 
-	if(!PySurface_Lock(array)) return NULL;
+	if(!PySurface_Lock(surfobj)) return NULL;
 	
 	switch(surf->format->BytesPerPixel)
 	{
 	case 1:
 		if(!format->palette)
 		{
-			if(!PySurface_Unlock(array)) return NULL;
+			if(!PySurface_Unlock(surfobj)) return NULL;
 			return RAISE(PyExc_RuntimeError, "8bit surface has no palette");
 		}
 		palette = format->palette->colors;
 		}break;
 	}
 
-	if(!PySurface_Unlock(array)) return NULL;
+	if(!PySurface_Unlock(surfobj)) return NULL;
 	return array;
 }
 
 	int dim[2], loopy;
 	Uint8* data;
 	Uint32 color;
-	PyObject* array;
+	PyObject *array, *surfobj;
 	SDL_Surface* surf;
 	int stridex, stridey;
 	int Ashift, Amask, Aloss;
 
-	if(!PyArg_ParseTuple(arg, "O!", &PySurface_Type, &array))
+	if(!PyArg_ParseTuple(arg, "O!", &PySurface_Type, &surfobj))
 		return NULL;
-	surf = PySurface_AsSurface(array);
+	surf = PySurface_AsSurface(surfobj);
 
 	dim[0] = surf->w;
 	dim[1] = surf->h;
 	stridex = ((PyArrayObject*)array)->strides[0];
 	stridey = ((PyArrayObject*)array)->strides[1];
 
-	if(!PySurface_Lock(array)) return NULL;
+	if(!PySurface_Lock(surfobj)) return NULL;
 
 	switch(surf->format->BytesPerPixel)
 	{
 		}break;
 	}
 
-	if(!PySurface_Unlock(array)) return NULL;
+	if(!PySurface_Unlock(surfobj)) return NULL;
 	return array;
 }
 
 	int dim[2], loopy;
 	Uint8* data;
 	Uint32 color, colorkey;
-	PyObject* array;
+	PyObject *array, *surfobj;
 	SDL_Surface* surf;
 	int stridex, stridey;
 
-	if(!PyArg_ParseTuple(arg, "O!", &PySurface_Type, &array))
+	if(!PyArg_ParseTuple(arg, "O!", &PySurface_Type, &surfobj))
 		return NULL;
-	surf = PySurface_AsSurface(array);
+	surf = PySurface_AsSurface(surfobj);
 
 	dim[0] = surf->w;
 	dim[1] = surf->h;
 	stridex = ((PyArrayObject*)array)->strides[0];
 	stridey = ((PyArrayObject*)array)->strides[1];
 
-	if(!PySurface_Lock(array)) return NULL;
+	if(!PySurface_Lock(surfobj)) return NULL;
 
 	switch(surf->format->BytesPerPixel)
 	{
 		}break;
 	}
 
-	if(!PySurface_Lock(array)) return NULL;
+	if(!PySurface_Lock(surfobj)) return NULL;
 	return array;
 }
 
 		stridez = array->strides[1];
 		sizex = 1;
 		sizey = array->dimensions[0];
+		break;
 #if 1 /*kinda like a scalar here, use normal map_rgb*/
 	case 1: /*single color*/
 		dims[0] = 1;
 		stridez = array->strides[0];
 		sizex = 1;
 		sizey = 1;
+		break;
 #endif
 	default:
 		return RAISE(PyExc_ValueError, "unsupported array shape");
 }
 
 
+#if 0
+/* not really fast enough to warrant this */
+    /*DOC*/ static char XXX_clamp_array[] =
+    /*DOC*/    "pygame.surfarray.clamp_array(array3d, min=0, max=255) -> None\n"
+    /*DOC*/    "will clamp all integer values in an array between 0 and 255\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "Given an array of integer values, this will make sure\n"
+    /*DOC*/    "no values are outside the range between 0 and 255.\n"
+    /*DOC*/    "This will modify the array in-place.\n"
+    /*DOC*/    "\n"
+    /*DOC*/    "You can specify the minimum and maximum values for clamping,\n"
+    /*DOC*/    "but they default to 0 and 255, which is most useful.\n"
+    /*DOC*/ ;
+
+PyObject* clamp_array(PyObject* self, PyObject* arg)
+{
+	PyObject *arrayobj;
+	PyArrayObject* array;
+	int loopx, loopy, loopz;
+	int stridex, stridey, stridez, sizex, sizey, sizez;
+	int minval = 0, maxval = 255;
+
+	if(!PyArg_ParseTuple(arg, "O!|ii", &PyArray_Type, &arrayobj, &minval, &maxval))
+		return NULL;
+	array = (PyArrayObject*)arrayobj;
+
+	switch(array->nd)
+	{
+	case 3:
+		stridex = array->strides[0];
+		stridey = array->strides[1];
+		stridez = array->strides[2];
+		sizex = array->dimensions[0];
+		sizey = array->dimensions[1];
+		sizez = array->dimensions[2];
+		break;
+	case 2:
+		stridex = 0;
+		stridey = array->strides[0];
+		stridez = array->strides[1];
+		sizex = 1;
+		sizey = array->dimensions[0];
+		sizez = array->dimensions[1];
+		break;
+	case 1:
+		stridex = 0;
+		stridey = 0;
+		stridez = array->strides[0];
+		sizex = 1;
+		sizey = 1;
+		sizez = array->dimensions[0];
+		break;
+	default:
+		return RAISE(PyExc_ValueError, "unsupported dimensions for array");
+	}
+
+
+	switch(array->descr->elsize)
+	{
+	case sizeof(char):
+		for(loopx = 0; loopx < sizex; ++loopx)
+		{
+			char* col = array->data + stridex * loopx;
+			for(loopy = 0; loopy < sizey; ++loopy)
+			{
+				char* row = col + stridey * loopy;
+				for(loopz = 0; loopz < sizez; ++loopz)
+				{
+					char* data = (char*)row;
+					if(*data < minval) *data = minval;
+					else if(*data > maxval) *data = maxval;
+					row += sizez;
+				}
+			}
+		}break;
+	case sizeof(short):
+		for(loopx = 0; loopx < sizex; ++loopx)
+		{
+			char* col = array->data + stridex * loopx;
+			for(loopy = 0; loopy < sizey; ++loopy)
+			{
+				char* row = col + stridey * loopy;
+				for(loopz = 0; loopz < sizez; ++loopz)
+				{
+					short* data = (short*)row;
+					if(*data < minval) *data = minval;
+					else if(*data > maxval) *data = maxval;
+					row += sizez;
+				}
+			}
+		}break;
+	case sizeof(int):
+		for(loopx = 0; loopx < sizex; ++loopx)
+		{
+			char* col = array->data + stridex * loopx;
+			for(loopy = 0; loopy < sizey; ++loopy)
+			{
+				char* row = col + stridey * loopy;
+				for(loopz = 0; loopz < sizez; ++loopz)
+				{
+					int* data = (int*)row;
+					if(*data < minval) *data = minval;
+					else if(*data > maxval) *data = maxval;
+					row += sizez;
+				}
+			}
+		}break;
+	}
+
+	RETURN_NONE
+}
+#endif
+
+
 
 
 /*macros used to blit arrays*/
 	{ "map_array", map_array, 1, doc_map_array },
 /*	{ "unmap_array", unmap_array, 1, doc_unmap_array },*/
 	{ "blit_array", blit_array, 1, doc_blit_array },
+/*	{ "clamp_array", clamp_array, 1, doc_clamp_array }, too slow*/
 
 	{ NULL, NULL }
 };