Commits

Nirav Patel committed e417071

new functions and improvements in mask

  • Participants
  • Parent commits eeaeedc

Comments (0)

Files changed (7)

docs/ref/index.html

 <li><a href="mask.html#pygame.mask">pygame.mask</a> - <font size=-1>pygame module for image masks.</font></li>
 <ul>
 <li><a href="mask.html#pygame.mask.from_surface">pygame.mask.from_surface</a> - <font size=-1>Returns a Mask from the given surface.</font></li>
+<li><a href="mask.html#pygame.mask.from_threshold">pygame.mask.from_threshold</a> - <font size=-1>Creates a mask by thresholding Surfaces</font></li>
 <li><a href="mask.html#pygame.mask.Mask">pygame.mask.Mask</a> - <font size=-1>pygame object for representing 2d bitmasks</font></li>
 <ul>
+<li><a href="mask.html#Mask.angle">Mask.angle</a> - <font size=-1>Returns the orientation of the pixels</font></li>
+<li><a href="mask.html#Mask.centroid">Mask.centroid</a> - <font size=-1>Returns the centroid of the pixels in a Mask</font></li>
+<li><a href="mask.html#Mask.clear">Mask.clear</a> - <font size=-1>Sets all bits to 0</font></li>
+<li><a href="mask.html#Mask.connected_component">Mask.connected_component</a> - <font size=-1>Returns a mask of a connected region of pixels.</font></li>
+<li><a href="mask.html#Mask.count">Mask.count</a> - <font size=-1>Returns the number of set pixels</font></li>
+<li><a href="mask.html#Mask.draw">Mask.draw</a> - <font size=-1>Draws a mask onto another</font></li>
+<li><a href="mask.html#Mask.erase">Mask.erase</a> - <font size=-1>Erases a mask from another</font></li>
+<li><a href="mask.html#Mask.fill">Mask.fill</a> - <font size=-1>Sets all bits to 1</font></li>
 <li><a href="mask.html#Mask.get_at">Mask.get_at</a> - <font size=-1>Returns nonzero if the bit at (x,y) is set.</font></li>
 <li><a href="mask.html#Mask.get_bounding_rects">Mask.get_bounding_rects</a> - <font size=-1>Returns a list of bounding rects of regions of set pixels.</font></li>
 <li><a href="mask.html#Mask.get_size">Mask.get_size</a> - <font size=-1>Returns the size of the mask.</font></li>
+<li><a href="mask.html#Mask.invert">Mask.invert</a> - <font size=-1>Flips the bits in a Mask</font></li>
+<li><a href="mask.html#Mask.outline">Mask.outline</a> - <font size=-1>list of points outlining an object</font></li>
 <li><a href="mask.html#Mask.overlap">Mask.overlap</a> - <font size=-1>Returns the point of intersection if the masks overlap with the given offset - or None if it does not overlap.</font></li>
 <li><a href="mask.html#Mask.overlap_area">Mask.overlap_area</a> - <font size=-1>Returns the number of overlapping 'pixels'.</font></li>
+<li><a href="mask.html#Mask.overlap_mask">Mask.overlap_mask</a> - <font size=-1>Returns a mask of the overlapping pixels</font></li>
+<li><a href="mask.html#Mask.scale">Mask.scale</a> - <font size=-1>Resizes a mask</font></li>
 <li><a href="mask.html#Mask.set_at">Mask.set_at</a> - <font size=-1>Sets the position in the mask given by x and y.</font></li>
 </ul>
 </ul>

docs/ref/mask.html

-
-<html>
-<title>mask - Pygame Documentation</title>
-<body bgcolor=#aaeebb text=#000000 link=#331111 vlink=#331111>
-
-
-<table cellpadding=0 cellspacing=0 border=0 style='border: 3px solid black;' width='100%'>
-<tr>
-<td bgcolor='#c2fc20' style='padding: 6px;' align=center valign=center><a href='http://www.pygame.org/'><img src='../pygame_tiny.gif' border=0 width=200 height=60></a><br><b>pygame documentation</b></td>
-<td bgcolor='#6aee28' style='border-left: 3px solid black; padding: 6px;' align=center valign=center>
-	||&nbsp;
-	<a href=http://www.pygame.org>Pygame Home</a> &nbsp;||&nbsp;
-	<a href=../index.html>Help Contents</a> &nbsp;||
-	<a href=index.html>Reference Index</a> &nbsp;||
-	<br>&nbsp;<br>
-	
-<a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
-<a href="color.html">Color</a>&nbsp;||&nbsp;
-<a href="cursors.html">Cursors</a>&nbsp;||&nbsp;
-<a href="display.html">Display</a>&nbsp;||&nbsp;
-<a href="draw.html">Draw</a>&nbsp;||&nbsp;
-<a href="event.html">Event</a>&nbsp;||&nbsp;
-<a href="font.html">Font</a>&nbsp;||&nbsp;
-<a href="image.html">Image</a>&nbsp;||&nbsp;
-<a href="joystick.html">Joystick</a>&nbsp;||&nbsp;
-<a href="key.html">Key</a>&nbsp;||&nbsp;
-<a href="mask.html">Mask</a>&nbsp;||&nbsp;
-<a href="mixer.html">Mixer</a>&nbsp;||&nbsp;
-<a href="mouse.html">Mouse</a>&nbsp;||&nbsp;
-<a href="movie.html">Movie</a>&nbsp;||&nbsp;
-<a href="music.html">Music</a>&nbsp;||&nbsp;
-<a href="overlay.html">Overlay</a>&nbsp;||&nbsp;
-<a href="pixelarray.html">Pixelarray</a>&nbsp;||&nbsp;
-<a href="pygame.html">Pygame</a>&nbsp;||&nbsp;
-<a href="rect.html">Rect</a>&nbsp;||&nbsp;
-<a href="scrap.html">Scrap</a>&nbsp;||&nbsp;
-<a href="sndarray.html">Sndarray</a>&nbsp;||&nbsp;
-<a href="sprite.html">Sprite</a>&nbsp;||&nbsp;
-<a href="surface.html">Surface</a>&nbsp;||&nbsp;
-<a href="surfarray.html">Surfarray</a>&nbsp;||&nbsp;
-<a href="time.html">Time</a>&nbsp;||&nbsp;
-<a href="transform.html">Transform</a>
-</td></tr></table>
-<br>
-
-
-<a name="pygame.mask">
-<big><b>pygame.mask</big></b><br><ul>
-  <i>pygame module for image masks.</i><br>
-<ul><small><table>
-  <tr><td><a href="mask.html#pygame.mask.from_surface">pygame.mask.from_surface</a> - <font size=-1>Returns a Mask from the given surface.</font></td><td>Returns a Mask from the given surface.</td></tr>
-  <tr><td><a href="mask.html#pygame.mask.Mask">pygame.mask.Mask</a> - <font size=-1>pygame object for representing 2d bitmasks</font></td><td>pygame object for representing 2d bitmasks</td></tr>
-</table></small></ul>
-<p>Useful for fast pixel perfect collision detection. <tt>A</tt> Mask uses 1bit per pixel to store which parts collide. </p>
-<p>New in pygame <tt>1.8</tt>. </p>
-<!--COMMENTS:pygame.mask--> &nbsp;<br> 
-
-
-<a name="pygame.mask.from_surface">
-<big><b>pygame.mask.from_surface</big></b><br><ul>
-  <i>Returns a Mask from the given surface.</i><br>
-  <tt>pygame.mask.from_surface(Surface, threshold = 127) -> Mask</tt><br>
-<p>Makes the transparent parts of the Surface not set, and the opaque parts set. </p>
-<p>The alpha of each pixel is checked to see if it is greater than the given threshold. </p>
-<p>If the Surface is color keyed, then threshold is not used. </p>
-<!--COMMENTS:pygame.mask.from_surface--> &nbsp;<br> 
-<br></ul>
-
-
-<a name="pygame.mask.Mask">
-<big><b>pygame.mask.Mask</big></b><br><ul>
-  <i>pygame object for representing 2d bitmasks</i><br>
-  <tt>pygame.Mask((width, height): return Mask</tt><br>
-<ul><small><table>
-  <tr><td><a href="mask.html#Mask.get_size">Mask.get_size</a> - <font size=-1>Returns the size of the mask.</font></td><td>Returns the size of the mask.</td></tr>
-  <tr><td><a href="mask.html#Mask.get_at">Mask.get_at</a> - <font size=-1>Returns nonzero if the bit at (x,y) is set.</font></td><td>Returns nonzero if the bit at (x,y) is set.</td></tr>
-  <tr><td><a href="mask.html#Mask.set_at">Mask.set_at</a> - <font size=-1>Sets the position in the mask given by x and y.</font></td><td>Sets the position in the mask given by x and y.</td></tr>
-  <tr><td><a href="mask.html#Mask.overlap">Mask.overlap</a> - <font size=-1>Returns the point of intersection if the masks overlap with the given offset - or None if it does not overlap.</font></td><td>Returns the point of intersection if the masks overlap with the given offset - or None if it does not overlap.</td></tr>
-  <tr><td><a href="mask.html#Mask.overlap_area">Mask.overlap_area</a> - <font size=-1>Returns the number of overlapping 'pixels'.</font></td><td>Returns the number of overlapping 'pixels'.</td></tr>
-  <tr><td><a href="mask.html#Mask.get_bounding_rects">Mask.get_bounding_rects</a> - <font size=-1>Returns a list of bounding rects of regions of set pixels.</font></td><td>Returns a list of bounding rects of regions of set pixels.</td></tr>
-</table></small></ul>
- &nbsp;<br> 
-<!--COMMENTS:pygame.mask.Mask--> &nbsp;<br> 
-
-
-<a name="Mask.get_size">
-<big><b>Mask.get_size</big></b><br><ul>
-  <i>Returns the size of the mask.</i><br>
-  <tt>Mask.get_size() -> width,height</tt><br>
- &nbsp;<br> 
-<!--COMMENTS:Mask.get_size--> &nbsp;<br> 
-<br></ul>
-
-
-<a name="Mask.get_at">
-<big><b>Mask.get_at</big></b><br><ul>
-  <i>Returns nonzero if the bit at (x,y) is set.</i><br>
-  <tt>Mask.get_at((x,y)) -> int</tt><br>
-<p>Coordinates start at (0,0) is top left - just like Surfaces. </p>
-<!--COMMENTS:Mask.get_at--> &nbsp;<br> 
-<br></ul>
-
-
-<a name="Mask.set_at">
-<big><b>Mask.set_at</big></b><br><ul>
-  <i>Sets the position in the mask given by x and y.</i><br>
-  <tt>Mask.set_at((x,y),value)</tt><br>
- &nbsp;<br> 
-<!--COMMENTS:Mask.set_at--> &nbsp;<br> 
-<br></ul>
-
-
-<a name="Mask.overlap">
-<big><b>Mask.overlap</big></b><br><ul>
-  <i>Returns the point of intersection if the masks overlap with the given offset - or None if it does not overlap.</i><br>
-  <tt>Mask.overlap(othermask, offset) -> x,y</tt><br>
-<p>The overlap tests uses the following offsets (which may be negative): </p>
-<pre>   +----+----------..
-   |A   | yoffset
-   |  +-+----------..
-   +--|B
-   |xoffset
-   |  |
-   :  :
-</pre>
-<!--COMMENTS:Mask.overlap--> &nbsp;<br> 
-<br></ul>
-
-
-<a name="Mask.overlap_area">
-<big><b>Mask.overlap_area</big></b><br><ul>
-  <i>Returns the number of overlapping 'pixels'.</i><br>
-  <tt>Mask.overlap_area(othermask, offset) -> numpixels</tt><br>
-<p>You can see how many pixels overlap with the other mask given. This can be used to see in which direction things collide, or to see how much the two masks collide. </p>
-<!--COMMENTS:Mask.overlap_area--> &nbsp;<br> 
-<br></ul>
-
-
-<a name="Mask.get_bounding_rects">
-<big><b>Mask.get_bounding_rects</big></b><br><ul>
-  <i>Returns a list of bounding rects of regions of set pixels.</i><br>
-  <tt>Mask.get_bounding_rects() -> Rects</tt><br>
-<p>This gets a bounding rect of connected regions of set pixels. <tt>A</tt> bounding rect is one for which each of the connected pixels is inside the rect. </p>
-<!--COMMENTS:Mask.get_bounding_rects--> &nbsp;<br> 
-<br></ul>
-<br></ul>
-<br></ul>
-
-</body></html>
+
+<html>
+<title>mask - Pygame Documentation</title>
+<body bgcolor=#aaeebb text=#000000 link=#331111 vlink=#331111>
+
+
+<table cellpadding=0 cellspacing=0 border=0 style='border: 3px solid black;' width='100%'>
+<tr>
+<td bgcolor='#c2fc20' style='padding: 6px;' align=center valign=center><a href='http://www.pygame.org/'><img src='../pygame_tiny.gif' border=0 width=200 height=60></a><br><b>pygame documentation</b></td>
+<td bgcolor='#6aee28' style='border-left: 3px solid black; padding: 6px;' align=center valign=center>
+	||&nbsp;
+	<a href=http://www.pygame.org>Pygame Home</a> &nbsp;||&nbsp;
+	<a href=../index.html>Help Contents</a> &nbsp;||
+	<a href=index.html>Reference Index</a> &nbsp;||
+	<br>&nbsp;<br>
+	
+<a href="cdrom.html">Cdrom</a>&nbsp;||&nbsp;
+<a href="color.html">Color</a>&nbsp;||&nbsp;
+<a href="cursors.html">Cursors</a>&nbsp;||&nbsp;
+<a href="display.html">Display</a>&nbsp;||&nbsp;
+<a href="draw.html">Draw</a>&nbsp;||&nbsp;
+<a href="event.html">Event</a>&nbsp;||&nbsp;
+<a href="font.html">Font</a>&nbsp;||&nbsp;
+<a href="image.html">Image</a>&nbsp;||&nbsp;
+<a href="joystick.html">Joystick</a>&nbsp;||&nbsp;
+<a href="key.html">Key</a>&nbsp;||&nbsp;
+<a href="mask.html">Mask</a>&nbsp;||&nbsp;
+<a href="mixer.html">Mixer</a>&nbsp;||&nbsp;
+<a href="mouse.html">Mouse</a>&nbsp;||&nbsp;
+<a href="movie.html">Movie</a>&nbsp;||&nbsp;
+<a href="music.html">Music</a>&nbsp;||&nbsp;
+<a href="overlay.html">Overlay</a>&nbsp;||&nbsp;
+<a href="pixelarray.html">Pixelarray</a>&nbsp;||&nbsp;
+<a href="pygame.html">Pygame</a>&nbsp;||&nbsp;
+<a href="rect.html">Rect</a>&nbsp;||&nbsp;
+<a href="scrap.html">Scrap</a>&nbsp;||&nbsp;
+<a href="sndarray.html">Sndarray</a>&nbsp;||&nbsp;
+<a href="sprite.html">Sprite</a>&nbsp;||&nbsp;
+<a href="surface.html">Surface</a>&nbsp;||&nbsp;
+<a href="surfarray.html">Surfarray</a>&nbsp;||&nbsp;
+<a href="time.html">Time</a>&nbsp;||&nbsp;
+<a href="transform.html">Transform</a>
+</td></tr></table>
+<br>
+
+
+<a name="pygame.mask">
+<big><b>pygame.mask</big></b><br><ul>
+  <i>pygame module for image masks.</i><br>
+<ul><small><table>
+  <tr><td><a href="mask.html#pygame.mask.from_surface">pygame.mask.from_surface</a> - <font size=-1>Returns a Mask from the given surface.</font></td><td>Returns a Mask from the given surface.</td></tr>
+  <tr><td><a href="mask.html#pygame.mask.from_threshold">pygame.mask.from_threshold</a> - <font size=-1>Creates a mask by thresholding Surfaces</font></td><td>Creates a mask by thresholding Surfaces</td></tr>
+  <tr><td><a href="mask.html#pygame.mask.Mask">pygame.mask.Mask</a> - <font size=-1>pygame object for representing 2d bitmasks</font></td><td>pygame object for representing 2d bitmasks</td></tr>
+</table></small></ul>
+<p>Useful for fast pixel perfect collision detection. <tt>A</tt> Mask uses 1bit per pixel to store which parts collide. </p>
+<p>New in pygame <tt>1.8</tt>. </p>
+<!--COMMENTS:pygame.mask--> &nbsp;<br> 
+
+
+<a name="pygame.mask.from_surface">
+<big><b>pygame.mask.from_surface</big></b><br><ul>
+  <i>Returns a Mask from the given surface.</i><br>
+  <tt>pygame.mask.from_surface(Surface, threshold = 127) -> Mask</tt><br>
+<p>Makes the transparent parts of the Surface not set, and the opaque parts set. </p>
+<p>The alpha of each pixel is checked to see if it is greater than the given threshold. </p>
+<p>If the Surface is color keyed, then threshold is not used. </p>
+<!--COMMENTS:pygame.mask.from_surface--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="pygame.mask.from_threshold">
+<big><b>pygame.mask.from_threshold</big></b><br><ul>
+  <i>Creates a mask by thresholding Surfaces</i><br>
+  <tt>pygame.mask.from_surface(Surface, color, threshold = (0,0,0,255), othersurface = None) -> Mask</tt><br>
+<p>This is a more featureful method of getting a Mask from a Surface. If supplied with only one Surface, all pixels within the threshold of the supplied color are set in the Mask. If given the optional othersurface, all pixels in Surface that are within the threshold of the corresponding pixel in othersurface are set in the Mask. </p>
+<!--COMMENTS:pygame.mask.from_threshold--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="pygame.mask.Mask">
+<big><b>pygame.mask.Mask</big></b><br><ul>
+  <i>pygame object for representing 2d bitmasks</i><br>
+  <tt>pygame.Mask((width, height)): return Mask</tt><br>
+<ul><small><table>
+  <tr><td><a href="mask.html#Mask.get_size">Mask.get_size</a> - <font size=-1>Returns the size of the mask.</font></td><td>Returns the size of the mask.</td></tr>
+  <tr><td><a href="mask.html#Mask.get_at">Mask.get_at</a> - <font size=-1>Returns nonzero if the bit at (x,y) is set.</font></td><td>Returns nonzero if the bit at (x,y) is set.</td></tr>
+  <tr><td><a href="mask.html#Mask.set_at">Mask.set_at</a> - <font size=-1>Sets the position in the mask given by x and y.</font></td><td>Sets the position in the mask given by x and y.</td></tr>
+  <tr><td><a href="mask.html#Mask.overlap">Mask.overlap</a> - <font size=-1>Returns the point of intersection if the masks overlap with the given offset - or None if it does not overlap.</font></td><td>Returns the point of intersection if the masks overlap with the given offset - or None if it does not overlap.</td></tr>
+  <tr><td><a href="mask.html#Mask.overlap_area">Mask.overlap_area</a> - <font size=-1>Returns the number of overlapping 'pixels'.</font></td><td>Returns the number of overlapping 'pixels'.</td></tr>
+  <tr><td><a href="mask.html#Mask.overlap_mask">Mask.overlap_mask</a> - <font size=-1>Returns a mask of the overlapping pixels</font></td><td>Returns a mask of the overlapping pixels</td></tr>
+  <tr><td><a href="mask.html#Mask.fill">Mask.fill</a> - <font size=-1>Sets all bits to 1</font></td><td>Sets all bits to 1</td></tr>
+  <tr><td><a href="mask.html#Mask.clear">Mask.clear</a> - <font size=-1>Sets all bits to 0</font></td><td>Sets all bits to 0</td></tr>
+  <tr><td><a href="mask.html#Mask.invert">Mask.invert</a> - <font size=-1>Flips the bits in a Mask</font></td><td>Flips the bits in a Mask</td></tr>
+  <tr><td><a href="mask.html#Mask.scale">Mask.scale</a> - <font size=-1>Resizes a mask</font></td><td>Resizes a mask</td></tr>
+  <tr><td><a href="mask.html#Mask.draw">Mask.draw</a> - <font size=-1>Draws a mask onto another</font></td><td>Draws a mask onto another</td></tr>
+  <tr><td><a href="mask.html#Mask.erase">Mask.erase</a> - <font size=-1>Erases a mask from another</font></td><td>Erases a mask from another</td></tr>
+  <tr><td><a href="mask.html#Mask.count">Mask.count</a> - <font size=-1>Returns the number of set pixels</font></td><td>Returns the number of set pixels</td></tr>
+  <tr><td><a href="mask.html#Mask.centroid">Mask.centroid</a> - <font size=-1>Returns the centroid of the pixels in a Mask</font></td><td>Returns the centroid of the pixels in a Mask</td></tr>
+  <tr><td><a href="mask.html#Mask.angle">Mask.angle</a> - <font size=-1>Returns the orientation of the pixels</font></td><td>Returns the orientation of the pixels</td></tr>
+  <tr><td><a href="mask.html#Mask.outline">Mask.outline</a> - <font size=-1>list of points outlining an object</font></td><td>list of points outlining an object</td></tr>
+  <tr><td><a href="mask.html#Mask.connected_component">Mask.connected_component</a> - <font size=-1>Returns a mask of a connected region of pixels.</font></td><td>Returns a mask of a connected region of pixels.</td></tr>
+  <tr><td><a href="mask.html#Mask.get_bounding_rects">Mask.get_bounding_rects</a> - <font size=-1>Returns a list of bounding rects of regions of set pixels.</font></td><td>Returns a list of bounding rects of regions of set pixels.</td></tr>
+</table></small></ul>
+ &nbsp;<br> 
+<!--COMMENTS:pygame.mask.Mask--> &nbsp;<br> 
+
+
+<a name="Mask.get_size">
+<big><b>Mask.get_size</big></b><br><ul>
+  <i>Returns the size of the mask.</i><br>
+  <tt>Mask.get_size() -> width,height</tt><br>
+ &nbsp;<br> 
+<!--COMMENTS:Mask.get_size--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Mask.get_at">
+<big><b>Mask.get_at</big></b><br><ul>
+  <i>Returns nonzero if the bit at (x,y) is set.</i><br>
+  <tt>Mask.get_at((x,y)) -> int</tt><br>
+<p>Coordinates start at (0,0) is top left - just like Surfaces. </p>
+<!--COMMENTS:Mask.get_at--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Mask.set_at">
+<big><b>Mask.set_at</big></b><br><ul>
+  <i>Sets the position in the mask given by x and y.</i><br>
+  <tt>Mask.set_at((x,y),value)</tt><br>
+ &nbsp;<br> 
+<!--COMMENTS:Mask.set_at--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Mask.overlap">
+<big><b>Mask.overlap</big></b><br><ul>
+  <i>Returns the point of intersection if the masks overlap with the given offset - or None if it does not overlap.</i><br>
+  <tt>Mask.overlap(othermask, offset) -> x,y</tt><br>
+<p>The overlap tests uses the following offsets (which may be negative): </p>
+<pre>   +----+----------..
+   |A   | yoffset
+   |  +-+----------..
+   +--|B
+   |xoffset
+   |  |
+   :  :
+</pre>
+<!--COMMENTS:Mask.overlap--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Mask.overlap_area">
+<big><b>Mask.overlap_area</big></b><br><ul>
+  <i>Returns the number of overlapping 'pixels'.</i><br>
+  <tt>Mask.overlap_area(othermask, offset) -> numpixels</tt><br>
+<p>You can see how many pixels overlap with the other mask given. This can be used to see in which direction things collide, or to see how much the two masks collide. An approximate collision normal can be found by calculating the gradient of the overlap area through the finite difference. </p>
+<pre> dx = Mask.overlap_area(othermask,(x+1,y)) - Mask.overlap_area(othermask,(x-1,y))
+ dy = Mask.overlap_area(othermask,(x,y+1)) - Mask.overlap_area(othermask,(x,y-1))
+</pre>
+<!--COMMENTS:Mask.overlap_area--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Mask.overlap_mask">
+<big><b>Mask.overlap_mask</big></b><br><ul>
+  <i>Returns a mask of the overlapping pixels</i><br>
+  <tt>Mask.overlap_mask(othermask, offset) -> Mask</tt><br>
+<p>Returns a Mask the size of the original Mask containing only the overlapping pixels between Mask and othermask. </p>
+<!--COMMENTS:Mask.overlap_mask--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Mask.fill">
+<big><b>Mask.fill</big></b><br><ul>
+  <i>Sets all bits to 1</i><br>
+  <tt>Mask.fill()</tt><br>
+<p>Sets all bits in a Mask to 1. </p>
+<!--COMMENTS:Mask.fill--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Mask.clear">
+<big><b>Mask.clear</big></b><br><ul>
+  <i>Sets all bits to 0</i><br>
+  <tt>Mask.clear()</tt><br>
+<p>Sets all bits in a Mask to 0. </p>
+<!--COMMENTS:Mask.clear--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Mask.invert">
+<big><b>Mask.invert</big></b><br><ul>
+  <i>Flips the bits in a Mask</i><br>
+  <tt>Mask.invert()</tt><br>
+<p>Flips all of the bits in a Mask, so that the set pixels turn to unset pixels and the unset pixels turn to set pixels. </p>
+<!--COMMENTS:Mask.invert--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Mask.scale">
+<big><b>Mask.scale</big></b><br><ul>
+  <i>Resizes a mask</i><br>
+  <tt>Mask.scale((x, y)) -> Mask</tt><br>
+<p>Returns a new Mask of the Mask scaled to the requested size. </p>
+<!--COMMENTS:Mask.scale--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Mask.draw">
+<big><b>Mask.draw</big></b><br><ul>
+  <i>Draws a mask onto another</i><br>
+  <tt>Mask.draw(othermask, offset)</tt><br>
+<p>Performs a bitwise <tt>OR</tt>, drawing othermask onto Mask. </p>
+<!--COMMENTS:Mask.draw--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Mask.erase">
+<big><b>Mask.erase</big></b><br><ul>
+  <i>Erases a mask from another</i><br>
+  <tt>Mask.erase(othermask, offset)</tt><br>
+<p>Erases all pixels set in othermask from Mask. </p>
+<!--COMMENTS:Mask.erase--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Mask.count">
+<big><b>Mask.count</big></b><br><ul>
+  <i>Returns the number of set pixels</i><br>
+  <tt>Mask.count() -> pixels</tt><br>
+<p>Returns the number of set pixels in the Mask. </p>
+<!--COMMENTS:Mask.count--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Mask.centroid">
+<big><b>Mask.centroid</big></b><br><ul>
+  <i>Returns the centroid of the pixels in a Mask</i><br>
+  <tt>Mask.centroid() -> (x, y)</tt><br>
+<p>Finds the centroid, the center of pixel mass, of a Mask. Returns a coordinate tuple for the centroid of the Mask. In the event the Mask is empty, it will return (0,0). </p>
+<!--COMMENTS:Mask.centroid--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Mask.angle">
+<big><b>Mask.angle</big></b><br><ul>
+  <i>Returns the orientation of the pixels</i><br>
+  <tt>Mask.angle() -> theta</tt><br>
+<p>Finds the approximate orientation of the pixels in the image from -90 to 90 degrees. This works best if performed on one connected component of pixels. It will return <tt>0.0</tt> on an empty Mask. </p>
+<!--COMMENTS:Mask.angle--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Mask.outline">
+<big><b>Mask.outline</big></b><br><ul>
+  <i>list of points outlining an object</i><br>
+  <tt>Mask.outline(every = 1) -> [(x,y), (x,y) ...]</tt><br>
+<p>Returns a list of points of the outline of the first object it comes across in a Mask. For this to be useful, there should probably only be one connected component of pixels in the Mask. The every option allows you to skip pixels in the outline. For example, setting it to 10 would return a list of every 10th pixel in the outline. </p>
+<!--COMMENTS:Mask.outline--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Mask.connected_component">
+<big><b>Mask.connected_component</big></b><br><ul>
+  <i>Returns a mask of a connected region of pixels.</i><br>
+  <tt>Mask.connected_component((x,y) = None) -> Mask</tt><br>
+<p>This uses the <tt>SAUF</tt> algorithm to find a connected component in the Mask. It checks 8 point connectivity. By default, it will return the largest connected component in the image. Optionally, a coordinate pair of a pixel can be specified, and the connected component containing it will be returned. In the event the pixel at that location is not set, the returned Mask will be empty. The Mask returned is the same size as the original Mask. </p>
+<!--COMMENTS:Mask.connected_component--> &nbsp;<br> 
+<br></ul>
+
+
+<a name="Mask.get_bounding_rects">
+<big><b>Mask.get_bounding_rects</big></b><br><ul>
+  <i>Returns a list of bounding rects of regions of set pixels.</i><br>
+  <tt>Mask.get_bounding_rects() -> Rects</tt><br>
+<p>This gets a bounding rect of connected regions of set pixels. <tt>A</tt> bounding rect is one for which each of the connected pixels is inside the rect. </p>
+<!--COMMENTS:Mask.get_bounding_rects--> &nbsp;<br> 
+<br></ul>
+<br></ul>
+<br></ul>
+
+</body></html>
 #define MIN(a,b) ((a) <= (b) ? (a) : (b))
 #define MAX(a,b) ((a) >= (b) ? (a) : (b))
 
+/* The code by Gillies is slightly (1-3%) faster than the more
+   readable code below */
+#define GILLIES
+
+static INLINE unsigned int bitcount(BITMASK_W n)
+{
+  if (BITMASK_W_LEN == 32)
+    {
+#ifdef GILLIES
+/* (C) Donald W. Gillies, 1992.  All rights reserved.  You may reuse
+   this bitcount() function anywhere you please as long as you retain
+   this Copyright Notice. */
+      register unsigned long tmp;
+      return (tmp = (n) - (((n) >> 1) & 033333333333) - 
+	      (((n) >> 2) & 011111111111),
+	      tmp = ((tmp + (tmp >> 3)) & 030707070707),
+	      tmp =  (tmp + (tmp >> 6)),
+	      tmp = (tmp + (tmp >> 12) + (tmp >> 24)) & 077);
+/* End of Donald W. Gillies bitcount code */
+#else
+   /* This piece taken from Jorg Arndt's "Algorithms for Programmers" */
+    n  = ((n>>1) & 0x55555555) + (n & 0x55555555);  // 0-2 in 2 bits
+    n  = ((n>>2) & 0x33333333) + (n & 0x33333333);  // 0-4 in 4 bits
+    n  = ((n>>4) + n) & 0x0f0f0f0f;                 // 0-8 in 4 bits
+    n +=  n>> 8;                                    // 0-16 in 8 bits
+    n +=  n>>16;                                    // 0-32 in 8 bits
+    return  n & 0xff;
+#endif
+    }
+  else if (BITMASK_W_LEN == 64)
+    {
+      n  = ((n>>1) & 0x5555555555555555) + (n & 0x5555555555555555);
+      n  = ((n>>2) & 0x3333333333333333) + (n & 0x3333333333333333);
+      n  = ((n>>4) + n) & 0x0f0f0f0f0f0f0f0f;
+      n +=  n>> 8;                                    
+      n +=  n>>16;                                    
+      n +=  n>>32;
+      return  n & 0xff;
+    }
+  else
+    {
+      /* Handle non-32 or 64 bit case the slow way */
+      unsigned int nbits = 0;
+      while (n)
+	{
+	  if (n & 1)
+	    nbits++;
+	  n = n >> 1;
+	}
+      return nbits;
+    }
+}
+
 bitmask_t *bitmask_create(int w, int h)
 {
   bitmask_t *temp;
 
 void bitmask_fill(bitmask_t *m)
 {
-  int x,y;
-  for (y = 0; y < m->h; y++)
-    for (x = 0; x < m->w; x++)
-      bitmask_setbit(m, x, y);
+    int len, shift;
+    BITMASK_W *pixels, cmask, full;
+    
+    len = m->h*((m->w - 1)/BITMASK_W_LEN);
+    shift = BITMASK_W_LEN - (m->w % BITMASK_W_LEN);
+    full = ~(BITMASK_W)0;
+    cmask = (~(BITMASK_W)0) >> shift;    
+    /* fill all the pixels that aren't in the rightmost BITMASK_Ws */
+    for (pixels = m->bits; pixels < (m->bits + len); pixels++) {
+        *pixels = full;
+    }
+    /* for the rightmost BITMASK_Ws, use cmask to ensure we aren't setting
+       bits that are outside of the mask */
+    for (pixels = m->bits + len; pixels < (m->bits + len + m->h); pixels++) {
+        *pixels = cmask;
+    }
+}
+
+void bitmask_invert(bitmask_t *m)
+{
+    int len, shift;
+    BITMASK_W *pixels, cmask;
+    
+    len = m->h*((m->w - 1)/BITMASK_W_LEN);
+    shift = BITMASK_W_LEN - (m->w % BITMASK_W_LEN);
+    cmask = (~(BITMASK_W)0) >> shift;    
+    /* flip all the pixels that aren't in the rightmost BITMASK_Ws */
+    for (pixels = m->bits; pixels < (m->bits + len); pixels++) {
+        *pixels = ~(*pixels);
+    }
+    /* for the rightmost BITMASK_Ws, & with cmask to ensure we aren't setting
+       bits that are outside of the mask */
+    for (pixels = m->bits + len; pixels < (m->bits + len + m->h); pixels++) {
+        *pixels = cmask & ~(*pixels);
+    }
+}
+
+unsigned int bitmask_count(bitmask_t *m)
+{
+    BITMASK_W *pixels;
+    unsigned int tot = 0;
+    
+    for (pixels=m->bits; pixels<(m->bits+m->h*((m->w-1)/BITMASK_W_LEN + 1)); pixels++) {
+        tot += bitcount(*pixels);
+    }
+    
+    return tot;
 }
 
 int bitmask_overlap(const bitmask_t *a, const bitmask_t *b, int xoffset, int yoffset)
     }
 }
 
-/* The code by Gillies is slightly (1-3%) faster than the more
-   readable code below */
-#define GILLIES
-
-static INLINE unsigned int bitcount(BITMASK_W n)
-{
-  if (BITMASK_W_LEN == 32)
-    {
-#ifdef GILLIES
-/* (C) Donald W. Gillies, 1992.  All rights reserved.  You may reuse
-   this bitcount() function anywhere you please as long as you retain
-   this Copyright Notice. */
-      register unsigned long tmp;
-      return (tmp = (n) - (((n) >> 1) & 033333333333) - 
-	      (((n) >> 2) & 011111111111),
-	      tmp = ((tmp + (tmp >> 3)) & 030707070707),
-	      tmp =  (tmp + (tmp >> 6)),
-	      tmp = (tmp + (tmp >> 12) + (tmp >> 24)) & 077);
-/* End of Donald W. Gillies bitcount code */
-#else
-   /* This piece taken from Jorg Arndt's "Algorithms for Programmers" */
-    n  = ((n>>1) & 0x55555555) + (n & 0x55555555);  // 0-2 in 2 bits
-    n  = ((n>>2) & 0x33333333) + (n & 0x33333333);  // 0-4 in 4 bits
-    n  = ((n>>4) + n) & 0x0f0f0f0f;                 // 0-8 in 4 bits
-    n +=  n>> 8;                                    // 0-16 in 8 bits
-    n +=  n>>16;                                    // 0-32 in 8 bits
-    return  n & 0xff;
-#endif
-    }
-  else if (BITMASK_W_LEN == 64)
-    {
-      n  = ((n>>1) & 0x5555555555555555) + (n & 0x5555555555555555);
-      n  = ((n>>2) & 0x3333333333333333) + (n & 0x3333333333333333);
-      n  = ((n>>4) + n) & 0x0f0f0f0f0f0f0f0f;
-      n +=  n>> 8;                                    
-      n +=  n>>16;                                    
-      n +=  n>>32;
-      return  n & 0xff;
-    }
-  else
-    {
-      /* Handle non-32 or 64 bit case the slow way */
-      unsigned int nbits = 0;
-      while (n)
-	{
-	  if (n & 1)
-	    nbits++;
-	  n = n >> 1;
-	}
-      return nbits;
-    }
-}
-
 int bitmask_overlap_area(const bitmask_t *a, const bitmask_t *b, int xoffset, int yoffset)
 {
   const BITMASK_W *a_entry,*a_end, *b_entry, *ap,*bp;
     }
 }
 
+/* Makes a mask of the overlap of two other masks */
+void bitmask_overlap_mask(const bitmask_t *a, const bitmask_t *b, bitmask_t *c, int xoffset, int yoffset)
+{
+  const BITMASK_W *a_entry,*a_end, *ap;
+  const BITMASK_W *b_entry, *b_end, *bp;
+  BITMASK_W *c_entry, *c_end, *cp;
+  int shift,rshift,i,astripes,bstripes;
+  
+  if ((xoffset >= a->w) || (yoffset >= a->h) || (yoffset <= - b->h)) 
+      return;
+  
+  if (xoffset >= 0) 
+    {
+      if (yoffset >= 0)
+	{
+	  a_entry = a->bits + a->h*(xoffset/BITMASK_W_LEN) + yoffset;
+	  c_entry = c->bits + c->h*(xoffset/BITMASK_W_LEN) + yoffset;
+	  a_end = a_entry + MIN(b->h,a->h - yoffset);
+	  b_entry = b->bits;
+	}
+      else
+	{
+	  a_entry = a->bits + a->h*(xoffset/BITMASK_W_LEN);
+	  c_entry = c->bits + c->h*(xoffset/BITMASK_W_LEN);
+	  a_end = a_entry + MIN(b->h + yoffset,a->h);
+	  b_entry = b->bits - yoffset;
+	}
+      shift = xoffset & BITMASK_W_MASK;
+      if (shift)
+	{
+	  rshift = BITMASK_W_LEN - shift;
+	  astripes = (a->w - 1)/BITMASK_W_LEN - xoffset/BITMASK_W_LEN;
+	  bstripes = (b->w - 1)/BITMASK_W_LEN + 1;
+	  if (bstripes > astripes) /* zig-zag .. zig*/
+	    {
+	      for (i=0;i<astripes;i++)
+		{
+		  for (ap = a_entry,bp = b_entry,cp = c_entry;ap < a_end;ap++,bp++,cp++)
+		    *cp = *ap & (*bp << shift);
+		  a_entry += a->h;
+		  c_entry += c->h;
+		  a_end += a->h;
+		  for (ap = a_entry,bp = b_entry,cp = c_entry;ap < a_end;ap++,bp++,cp++)
+		    *cp = *ap & (*bp >> rshift);
+		  b_entry += b->h;
+		}
+	      for (ap = a_entry,bp = b_entry,cp = c_entry;ap < a_end;ap++,bp++,cp++)
+		*cp = *ap & (*bp << shift);
+	    }
+	  else /* zig-zag */
+	    {
+	      for (i=0;i<bstripes;i++)
+		{
+		  for (ap = a_entry,bp = b_entry,cp = c_entry;ap < a_end;ap++,bp++,cp++)
+		    *cp = *ap & (*bp << shift);
+		  a_entry += a->h;
+		  c_entry += c->h;
+		  a_end += a->h;
+		  for (ap = a_entry,bp = b_entry,cp = c_entry;ap < a_end;ap++,bp++,cp++)
+		    *cp = *ap & (*bp >> rshift);
+		  b_entry += b->h;
+		}
+	    }
+	}
+      else /* xoffset is a multiple of the stripe width, 
+	      and the above routines won't work. */
+	{
+	  astripes = (MIN(b->w,a->w - xoffset) - 1)/BITMASK_W_LEN + 1;
+	  for (i=0;i<astripes;i++)
+	    {
+	      for (ap = a_entry,bp = b_entry,cp = c_entry;ap < a_end;ap++,bp++,cp++)
+		{
+		  *cp = *ap & *bp;
+		}
+	      a_entry += a->h;
+	      c_entry += c->h;
+	      a_end += a->h;
+	      b_entry += b->h;
+	    }
+	}
+    }
+  else  
+    {
+      xoffset *= -1;
+      yoffset *= -1;
+
+      if (yoffset >= 0)
+	{
+	  b_entry = b->bits + b->h*(xoffset/BITMASK_W_LEN) + yoffset;
+	  b_end = b_entry + MIN(a->h,b->h - yoffset);
+	  a_entry = a->bits;
+	  c_entry = c->bits;
+	}
+      else
+	{
+	  b_entry = b->bits + b->h*(xoffset/BITMASK_W_LEN);
+	  b_end = b_entry + MIN(a->h + yoffset,b->h);
+	  a_entry = a->bits - yoffset;
+	  c_entry = c->bits - yoffset;
+	}
+      shift = xoffset & BITMASK_W_MASK;
+      if (shift)
+	{
+	  rshift = BITMASK_W_LEN - shift;
+	  astripes = (b->w - 1)/BITMASK_W_LEN - xoffset/BITMASK_W_LEN;
+	  bstripes = (a->w - 1)/BITMASK_W_LEN + 1;
+	  if (bstripes > astripes) /* zig-zag .. zig*/
+	    {
+	      for (i=0;i<astripes;i++)
+		{
+		  for (bp = b_entry,ap = a_entry,cp = c_entry;bp < b_end;bp++,ap++,cp++)
+		    *cp = *ap & (*bp >> shift);
+		  b_entry += b->h;
+		  b_end += b->h;
+		  for (bp = b_entry,ap = a_entry,cp = c_entry;bp < b_end;bp++,ap++,cp++)
+		    *cp = *ap & (*bp <<rshift); 
+		  a_entry += a->h;
+		  c_entry += c->h;
+		}
+	      for (bp = b_entry,ap = a_entry,cp = c_entry;bp < b_end;bp++,ap++,cp++)
+		*cp = *ap & (*bp >> shift);
+	    }
+	  else /* zig-zag */
+	    {
+	      for (i=0;i<bstripes;i++)
+		{
+		  for (bp = b_entry,ap = a_entry,cp = c_entry;bp < b_end;bp++,ap++,cp++)
+		    *cp = *ap & (*bp >> shift);
+		  b_entry += b->h;
+		  b_end += b->h;
+		  for (bp = b_entry,ap = a_entry,cp = c_entry;bp < b_end;bp++,ap++,cp++)
+		    *cp = *ap & (*bp << rshift);
+		  a_entry += a->h;
+		  c_entry += c->h;
+		}
+	    }
+	}
+      else /* xoffset is a multiple of the stripe width, and the above routines won't work. */
+	{
+	  astripes = (MIN(a->w,b->w - xoffset) - 1)/BITMASK_W_LEN + 1;
+	  for (i=0;i<astripes;i++)
+	    {
+	      for (bp = b_entry,ap = a_entry,cp = c_entry;bp < b_end;bp++,ap++,cp++)
+		{
+		  *cp = *ap & *bp;
+		}
+	      b_entry += b->h;
+	      b_end += b->h;
+	      a_entry += a->h;
+	      c_entry += c->h;
+	    }
+	}
+      xoffset *= -1;
+      yoffset *= -1;
+    }	
+  /* Zero out bits outside the mask rectangle (to the right), if there
+   is a chance we were drawing there. */
+  if (xoffset + b->w > c->w)
+    {
+      BITMASK_W edgemask;
+      int n = c->w/BITMASK_W_LEN;
+      shift = (n + 1)*BITMASK_W_LEN - c->w;
+      edgemask = (~(BITMASK_W)0) >> shift;
+      c_end = c->bits + n*c->h + MIN(c->h,b->h + yoffset);
+      for (cp = c->bits + n*c->h + MAX(yoffset,0);cp<c_end;cp++)
+	*cp &= edgemask;
+    }
+}
+
 /* Draws mask b onto mask a (bitwise OR) */
 void bitmask_draw(bitmask_t *a, const bitmask_t *b, int xoffset, int yoffset)
 {
 /* Sets all bits in the mask */
 void bitmask_fill(bitmask_t *m);
 
+/* Flips all bits in the mask */
+void bitmask_invert(bitmask_t *m);
+
+/* Counts the bits in the mask */
+unsigned int bitmask_count(bitmask_t *m);
+
 /* Returns nonzero if the bit at (x,y) is set.  Coordinates start at
    (0,0) */
 static INLINE int bitmask_getbit(const bitmask_t *m, int x, int y) 
 /* Returns the number of overlapping 'pixels' */
 int bitmask_overlap_area(const bitmask_t *a, const bitmask_t *b, int xoffset, int yoffset);
 
-
+/* Fills a mask with the overlap of two other masks. A bitwise AND. */
+void bitmask_overlap_mask (const bitmask_t *a, const bitmask_t *b, bitmask_t *c, int xoffset, int yoffset);
 
 /* Draws mask b onto mask a (bitwise OR). Can be used to compose large
    (game background?) mask from several submasks, which may speed up
 #include "pygamedocs.h"
 #include "structmember.h"
 #include "bitmask.h"
+#include <math.h>
 
 
 typedef struct {
     return PyInt_FromLong(val);
 }
 
-/*
-def maskFromSurface(surface, threshold = 127):
-    mask = pygame.Mask(surface.get_size())
-    key = surface.get_colorkey()
-    if key:
-        for y in range(surface.get_height()):
-            for x in range(surface.get_width()):
-                if surface.get_at((x+0.1,y+0.1)) != key:
-                    mask.set_at((x,y),1)
-    else:
-        for y in range(surface.get_height()):
-            for x in range (surface.get_width()):
-                if surface.get_at((x,y))[3] > threshold:
-                    mask.set_at((x,y),1)
-    return mask
-*/
+static PyObject* mask_overlap_mask(PyObject* self, PyObject* args)
+{
+    int x, y;
+    bitmask_t *mask = PyMask_AsBitmap(self);
+    bitmask_t *output = bitmask_create(mask->w, mask->h);
+    bitmask_t *othermask;
+    PyObject *maskobj;
+    PyMaskObject *maskobj2 = PyObject_New(PyMaskObject, &PyMask_Type);
 
+    if(!PyArg_ParseTuple(args, "O!(ii)", &PyMask_Type, &maskobj, &x, &y)) {
+        return NULL;
+    }
+    othermask = PyMask_AsBitmap(maskobj);
+    
+    bitmask_overlap_mask(mask, othermask, output, x, y);
+    
+    if(maskobj2)
+        maskobj2->mask = output;
 
+    return (PyObject*)maskobj2;
+}
 
+static PyObject* mask_fill(PyObject* self, PyObject* args)
+{
+    bitmask_t *mask = PyMask_AsBitmap(self);
+    
+    bitmask_fill(mask);
+        
+    Py_RETURN_NONE;
+}
+
+static PyObject* mask_clear(PyObject* self, PyObject* args)
+{
+    bitmask_t *mask = PyMask_AsBitmap(self);
+    
+    bitmask_clear(mask);
+        
+    Py_RETURN_NONE;
+}
+
+static PyObject* mask_invert(PyObject* self, PyObject* args)
+{
+    bitmask_t *mask = PyMask_AsBitmap(self);
+    
+    bitmask_invert(mask);
+        
+    Py_RETURN_NONE;
+}
+
+static PyObject* mask_scale(PyObject* self, PyObject* args)
+{
+    int x, y;
+    bitmask_t *input = PyMask_AsBitmap(self);
+    bitmask_t *output;
+    PyMaskObject *maskobj = PyObject_New(PyMaskObject, &PyMask_Type);
+    
+    if(!PyArg_ParseTuple(args, "(ii)", &x, &y)) {
+        return NULL;
+    }
+
+    output = bitmask_scale(input, x, y);
+    
+    if(maskobj)
+        maskobj->mask = output;
+
+    return (PyObject*)maskobj;
+}
+
+static PyObject* mask_draw(PyObject* self, PyObject* args)
+{
+    bitmask_t *mask = PyMask_AsBitmap(self);
+    bitmask_t *othermask;
+    PyObject *maskobj;
+    int x, y;
+
+    if(!PyArg_ParseTuple(args, "O!(ii)", &PyMask_Type, &maskobj, &x, &y)) {
+        return NULL;
+    }
+    othermask = PyMask_AsBitmap(maskobj);
+
+    bitmask_draw(mask, othermask, x, y);
+    
+    Py_RETURN_NONE;
+}
+
+static PyObject* mask_erase(PyObject* self, PyObject* args)
+{
+    bitmask_t *mask = PyMask_AsBitmap(self);
+    bitmask_t *othermask;
+    PyObject *maskobj;
+    int x, y;
+
+    if(!PyArg_ParseTuple(args, "O!(ii)", &PyMask_Type, &maskobj, &x, &y)) {
+        return NULL;
+    }
+    othermask = PyMask_AsBitmap(maskobj);
+
+    bitmask_erase(mask, othermask, x, y);
+    
+    Py_RETURN_NONE;
+}
+
+static PyObject* mask_count(PyObject* self, PyObject* args)
+{
+    bitmask_t *m = PyMask_AsBitmap(self);
+    
+    return PyInt_FromLong(bitmask_count(m));
+}
+
+static PyObject* mask_centroid(PyObject* self, PyObject* args)
+{
+    bitmask_t *mask = PyMask_AsBitmap(self);
+    int x, y;
+    long int m10, m01, m00;
+
+    m10 = m01 = m00 = 0;
+    
+    for (x = 0; x < mask->w; x++) {
+        for (y = 0; y < mask->h; y++) {
+            if (bitmask_getbit(mask, x, y)) {
+               m10 += x;
+               m01 += y;
+               m00++;
+            }
+        }
+    }
+    
+    if (m00) {
+        return Py_BuildValue ("(OO)", PyInt_FromLong(m10/m00),
+                              PyInt_FromLong(m01/m00));
+    } else {
+        return Py_BuildValue ("(OO)", PyInt_FromLong(0), PyInt_FromLong(0));
+    }
+}
+
+static PyObject* mask_angle(PyObject* self, PyObject* args)
+{
+    bitmask_t *mask = PyMask_AsBitmap(self);
+    int x, y, xc, yc;
+    long int m10, m01, m00, m20, m02, m11;
+    double theta;
+
+    m10 = m01 = m00 = m20 = m02 = m11 = 0;
+    
+    for (x = 0; x < mask->w; x++) {
+        for (y = 0; y < mask->h; y++) {
+            if (bitmask_getbit(mask, x, y)) {
+               m10 += x;
+               m20 += x*x;
+               m11 += x*y;
+               m02 += y*y;
+               m01 += y;
+               m00++;
+            }
+        }
+    }
+    
+    if (m00) {
+        xc = m10/m00;
+        yc = m01/m00;
+        theta = -90.0*atan2(2*(m11/m00 - xc*yc),(m20/m00 - xc*xc)-(m02/m00 - yc*yc))/M_PIl;
+        return Py_BuildValue ("O", PyFloat_FromDouble(theta));
+    } else {
+        return Py_BuildValue ("O", PyFloat_FromDouble(0));
+    }
+}
+
+static PyObject* mask_outline(PyObject* self, PyObject* args)
+{
+    bitmask_t* c = PyMask_AsBitmap(self);
+    bitmask_t* m = bitmask_create(c->w + 2, c->h + 2); 
+    PyObject* plist;
+    int x, y, every, e, firstx, firsty, secx, secy, currx, curry, nextx, nexty, n;
+    int a[14], b[14];
+    a[0] = a[1] = a[7] = a[8] = a[9] = b[1] = b[2] = b[3] = b[9] = b[10] = b[11]= 1;
+    a[2] = a[6] = a[10] = b[4] = b[0] = b[12] = b[8] = 0;
+    a[3] = a[4] = a[5] = a[11] = a[12] = a[13] = b[5] = b[6] = b[7] = b[13] = -1;
+    
+    plist = NULL;
+    plist = PyList_New (0);
+    if (!plist)
+        return NULL;
+        
+    every = 1;
+    n = firstx = firsty = secx = x = 0;
+
+    if(!PyArg_ParseTuple(args, "|i", &every)) {
+        return NULL;
+    }
+    
+    /* by copying to a new, larger mask, we avoid having to check if we are at
+       a border pixel every time.  */
+    bitmask_draw(m, c, 1, 1);
+    
+    e = every;
+    
+    /* find the first set pixel in the mask */
+    for (y = 1; y < m->h-1; y++) {
+        for (x = 1; x < m->w-1; x++) {
+            if (bitmask_getbit(m, x, y)) {
+                 firstx = x;
+                 firsty = y;
+                 PyList_Append(plist, Py_BuildValue("(ii)", x-1, y-1));
+                 break;
+            }
+        }
+        if (bitmask_getbit(m, x, y))
+            break;
+    }
+    
+    
+    
+    /* covers the mask having zero pixels or only the final pixel */
+    if ((x == m->w-1) && (y == m->h-1)) {
+        bitmask_free(m);
+        return plist;
+    }        
+    
+    /* check just the first pixel for neighbors */
+    for (n = 0;n < 8;n++) {
+        if (bitmask_getbit(m, x+a[n], y+b[n])) {
+            currx = secx = x+a[n];
+            curry = secy = y+b[n];
+            e--;
+            if (!e) {
+                e = every;
+                PyList_Append(plist, Py_BuildValue("(ii)", secx-1, secy-1));
+            }
+            break;
+        }
+    }       
+    
+    /* if there are no neighbors, return */
+    if (!secx) {
+        bitmask_free(m);
+        return plist;
+    }
+    
+    /* the outline tracing loop */
+    for (;;) {
+        /* look around the pixel, it has to have a neighbor */
+        for (n = (n + 6) & 7;;n++) {
+            if (bitmask_getbit(m, currx+a[n], curry+b[n])) {
+                nextx = currx+a[n];
+                nexty = curry+b[n];
+                e--;
+                if (!e) {
+                    e = every;
+                    PyList_Append(plist, Py_BuildValue("(ii)", nextx-1, nexty-1));
+                }
+                break;
+            }
+        }   
+        /* if we are back at the first pixel, and the next one will be the
+           second one we visited, we are done */
+        if ((curry == firsty && currx == firstx) && (secx == nextx && secy == nexty)) {
+            break;
+        }
+
+        curry = nexty;
+        currx = nextx;
+    }
+    
+    bitmask_free(m);
+    
+    return plist;
+}
 
 static PyObject* mask_from_surface(PyObject* self, PyObject* args)
 {
     PyObject* surfobj;
     PyMaskObject *maskobj;
 
-    int x, y, threshold;
+    int x, y, threshold, ashift, usethresh;
     Uint8 *pixels;
 
     SDL_PixelFormat *format;
-    Uint32 color;
+    Uint32 color, amask;
     Uint8 *pix;
-    Uint8 r, g, b, a;
+    Uint8 a;
 
     /* set threshold as 127 default argument. */
     threshold = 127;
     /* lock the surface, release the GIL. */
     PySurface_Lock (surfobj);
 
-
-
     Py_BEGIN_ALLOW_THREADS;
 
-
-
     /* get the size from the surface, and create the mask. */
     mask = bitmask_create(surf->w, surf->h);
 
          */
         return NULL; /*RAISE(PyExc_Error, "cannot create bitmask");*/
     }
-    
 
-
-    /* TODO: this is the slow, but easy to code way.  Could make the loop 
-     *         just increment a pointer depending on the format & duff unroll.
-     *         It's faster than in python anyhow.
-     */
     pixels = (Uint8 *) surf->pixels;
     format = surf->format;
+    amask = format->Amask;
+    ashift = format->Ashift;
+    usethresh = !(surf->flags & SDL_SRCCOLORKEY);
 
     for(y=0; y < surf->h; y++) {
+        pixels = surf->pixels + y*surf->pitch;
         for(x=0; x < surf->w; x++) {
             /* Get the color.  TODO: should use an inline helper 
              *   function for this common function. */
             switch (format->BytesPerPixel)
             {
                 case 1:
-                    color = (Uint32)*((Uint8 *) pixels + y * surf->pitch + x);
+                    color = (Uint32)*((Uint8 *) pixels);
+                    pixels++;
                     break;
                 case 2:
-                    color = (Uint32)*((Uint16 *) (pixels + y * surf->pitch) + x);
+                    color = (Uint32)*((Uint16 *) pixels);
+                    pixels += 2;
                     break;
                 case 3:
-                    pix = ((Uint8 *) (pixels + y * surf->pitch) + x * 3);
+                    pix = ((Uint8 *) pixels);
+                    pixels += 3;
                 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
                     color = (pix[0]) + (pix[1] << 8) + (pix[2] << 16);
                 #else
                 #endif
                     break;
                 default:                  /* case 4: */
-                    color = *((Uint32 *) (pixels + y * surf->pitch) + x);
+                    color = *((Uint32 *) pixels);
+                    pixels += 4;
                     break;
             }
 
 
-            if (!(surf->flags & SDL_SRCCOLORKEY)) {
-
-                SDL_GetRGBA (color, format, &r, &g, &b, &a);
-
+            if (usethresh) {
+                a = (color & amask) >> ashift;
                 /* no colorkey, so we check the threshold of the alpha */
                 if (a > threshold) {
                     bitmask_setbit(mask, x, y);
         }
     }
 
-
     Py_END_ALLOW_THREADS;
 
     /* unlock the surface, release the GIL.
     return (PyObject*)maskobj;
 }
 
+void bitmask_threshold (bitmask_t *m, SDL_Surface *surf, SDL_Surface *surf2, 
+                        Uint32 color,  Uint32 threshold)
+{
+    int x, y, rshift, gshift, bshift, rshift2, gshift2, bshift2;
+    Uint8 *pixels, *pixels2;
+    SDL_PixelFormat *format, *format2;
+    Uint32 the_color, the_color2, rmask, gmask, bmask, rmask2, gmask2, bmask2;
+    Uint8 *pix;
+    Uint8 r, g, b, a;
+    Uint8 tr, tg, tb, ta;
 
+    pixels = (Uint8 *) surf->pixels;
+    format = surf->format;
+    rmask = format->Rmask;
+    gmask = format->Gmask;
+    bmask = format->Bmask;
+    rshift = format->Rshift;
+    gshift = format->Gshift;
+    bshift = format->Bshift;
 
-/*
-
-def get_bounding_boxes(surf):
-    """
-    """
-    width, height = surf.get_width(), surf.get_height()
-
-    regions = []
-
-    # used pixels is Rects[y][x]
-    used_pixels = []
-    for y in xrange(height):
-        widthones = []
-        for x in xrange(width):
-            widthones.append(None)
-        used_pixels.append(widthones)
-
-
-    for y in xrange(height):
-        for x in xrange(width):
-            c = surf.get_at((x, y))
-            # if the pixel has been set.
-            if c[0]:
-                if not used_pixels[y][x]:
-                    used_pixels[y][x] = pygame.Rect(x,y,1,1)
-                    regions.append( used_pixels[y][x] )
-
-                aregion = used_pixels[y][x] 
-
-                # check other directions, clockwise.  mark a pixel as used if it is.
-                for dx, dy in [(0,-1), (1,-1), (1,0), (1,1), (0,1), (-1,1), (-1,0), (-1,-1)]:
-                    try:
-                        ax, ay = x+dx, y+dy
-                        if surf.get_at((ax,ay))[0]:
-                            if not used_pixels[ay][ax]:
-                                aregion.union_ip( pygame.Rect(ax,ay, 1, 1) )
-                            used_pixels[ay][ax] = aregion
-                    except:
-                        pass
-
-
-    return regions
-*/
-
-
-/* returns an array of regions in regions. */
-
-static GAME_Rect* get_bounding_rects(bitmask_t *mask, int *num_bounding_boxes) {
-
-    int x, y, p, i, width, height;
-    GAME_Rect **used_pixels;
-    GAME_Rect *a_used_pixels;
-    GAME_Rect *direction_used_pixels;
-    GAME_Rect *regions;
-
-    GAME_Rect *aregion, *the_regions;
-    int num_regions;
-    int nx, ny, nh, nw, ay, ax;
-    int directions[8][2];
-
-
-    /* for dx, dy in [(0,-1), (1,-1), (1,0), (1,1), (0,1), (-1,1), (-1,0), (-1,-1)]:
-     */
-
-    directions[0][0] = 0; directions[0][1] = -1;
-    directions[1][0] = 1; directions[1][1] = -1;
-    directions[2][0] = 1; directions[2][1] = 0;
-    directions[3][0] = 1; directions[3][1] = 1;
-    directions[4][0] = 0; directions[4][1] = 1;
-    directions[5][0] = -1; directions[5][1] = 1;
-    directions[6][0] = -1; directions[6][1] = 0;
-    directions[7][0] = -1; directions[7][1] = -1;
-
-
-
-    num_regions = 0;
-
-    height = mask->h;
-    width = mask->w;
-
-
-    /* used_pixels are pointers to rects held in the regions array.  */
-    used_pixels = (GAME_Rect**) malloc(sizeof(GAME_Rect*) * height * width);
-
-
-    for(y=0; y < height; y++) {
-        for(x=0; x < width; x++) {
-            /* used_pixels[y][x] = (GAME_Rect*)NULL; */
-            *((GAME_Rect **) (used_pixels + y * width) + x) = NULL;
-        }
+    if(surf2) {
+        format2 = surf2->format;
+        rmask2 = format2->Rmask;
+        gmask2 = format2->Gmask;
+        bmask2 = format2->Bmask;
+        rshift2 = format2->Rshift;
+        gshift2 = format2->Gshift;
+        bshift2 = format2->Bshift;
+        pixels2 = (Uint8 *) surf2->pixels;
+    } else { /* make gcc stop complaining */
+        rmask2 = gmask2 = bmask2 = 0;
+        rshift2 = gshift2 = bshift2 = 0;
+        format2 = NULL;
+        pixels2 = NULL;
     }
 
-    regions = (GAME_Rect*) malloc(sizeof(GAME_Rect) * height * width);
+    SDL_GetRGBA (color, format, &r, &g, &b, &a);
+    SDL_GetRGBA (threshold, format, &tr, &tg, &tb, &ta);
 
-    the_regions = regions;
+    for(y=0; y < surf->h; y++) {
+        pixels = surf->pixels + y*surf->pitch;
+        if (surf2) {
+            pixels2 = surf2->pixels + y*surf2->pitch;
+        }
+        for(x=0; x < surf->w; x++) {
+            /* the_color = surf->get_at(x,y) */
+            switch (format->BytesPerPixel)
+            {
+            case 1:
+                the_color = (Uint32)*((Uint8 *) pixels);
+                pixels++;
+                break;
+            case 2:
+                the_color = (Uint32)*((Uint16 *) pixels);
+                pixels += 2;
+                break;
+            case 3:
+                pix = ((Uint8 *) pixels);
+                pixels += 3;
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+                the_color = (pix[0]) + (pix[1] << 8) + (pix[2] << 16);
+#else
+                the_color = (pix[2]) + (pix[1] << 8) + (pix[0] << 16);
+#endif
+                break;
+            default:                  /* case 4: */
+                the_color = *((Uint32 *) pixels);
+                pixels += 4;
+                break;
+            }
 
-    for(y=0; y < height; y++) {
-        for(x=0; x < width; x++) {
-            p = bitmask_getbit(mask, x, y);
-
-            if(p) {
-                /* a_used_pixels is the pointer used_pixels[y][x].  */
-                a_used_pixels = *((GAME_Rect **) (used_pixels + y * width) + x);
-
-                /*
-                if not used_pixels[y][x]:
-                    used_pixels[y][x] = pygame.Rect(x,y,1,1)
-                    regions.append( used_pixels[y][x] )
-
-                aregion = used_pixels[y][x] 
-
-                */
-                
-
-                if( !a_used_pixels ) {
-                    /* Add the pixels as a rect on the_regions */
-                    the_regions[num_regions].x = x;
-                    the_regions[num_regions].y = y;
-                    the_regions[num_regions].w = 1;
-                    the_regions[num_regions].h = 1;
-                    a_used_pixels = the_regions + num_regions;
-                    num_regions++;
-
+            if (surf2) {
+                switch (format2->BytesPerPixel) {
+                    case 1:
+                        the_color2 = (Uint32)*((Uint8 *) pixels2);
+                        pixels2++;
+                        break;
+                    case 2:
+                        the_color2 = (Uint32)*((Uint16 *) pixels2);
+                        pixels2 += 2;
+                        break;
+                    case 3:
+                        pix = ((Uint8 *) pixels2);
+                        pixels2 += 3;
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+                        the_color2 = (pix[0]) + (pix[1] << 8) + (pix[2] << 16);
+#else
+                        the_color2 = (pix[2]) + (pix[1] << 8) + (pix[0] << 16);
+#endif
+                        break;
+                    default:                  /* case 4: */
+                        the_color2 = *((Uint32 *) pixels2);
+                        pixels2 += 4;
+                        break;
+                }              
+                if ((abs(((the_color2 & rmask2) >> rshift2) - ((the_color & rmask) >> rshift)) < tr) & 
+                    (abs(((the_color2 & gmask2) >> gshift2) - ((the_color & gmask) >> gshift)) < tg) & 
+                    (abs(((the_color2 & bmask2) >> bshift2) - ((the_color & bmask) >> bshift)) < tb)) {
+                    /* this pixel is within the threshold of othersurface. */
+                    bitmask_setbit(m, x, y);
                 }
-                aregion = a_used_pixels;
-
-                /* check other directions, clockwise.  mark a pixel as used if it is.  */
-
-                for(i=0; i < 8; i++) {
-
-                    ax = directions[i][0] + x;
-                    ay = directions[i][1] + y;
-                    
-                    /* if we are within the bounds of the mask, check it. */
-                    
-                    if(ax >=0 && ax < width && ay < height && ay >= 0) {
-                        
-                        
-                        /* printf("ax, ay: %d,%d\n", ax, ay);
-                        */
-
-                        if(bitmask_getbit(mask, ax, ay)) {
-                            /*
-                            if not used_pixels[ay][ax]:
-                                aregion.union_ip( pygame.Rect(ax,ay, 1, 1) )
-                            */
-                            direction_used_pixels = *((GAME_Rect **) (used_pixels + ay * width) + ax);
-                            if (!direction_used_pixels) {
-                                nx = MIN (aregion->x, ax);
-                                ny = MIN (aregion->y, ay);
-                                nw = MAX (aregion->x + aregion->w, ax + 1) - nx;
-                                nh = MAX (aregion->y + aregion->h, ay + 1) - ny;
-                                
-                                aregion->x = nx;
-                                aregion->y = ny;
-                                aregion->w = nw;
-                                aregion->h = nh;
-                            }
-                            /* used_pixels[ay][ax] = aregion */
-                            *((GAME_Rect **) (used_pixels + ay * width) + ax) = aregion;
-                        }
-                    }
-
-                }
-
-
-
+            } else if ((abs(((the_color & rmask) >> rshift) - r) < tr) & 
+                       (abs(((the_color & gmask) >> gshift) - g) < tg) & 
+                       (abs(((the_color & bmask) >> bshift) - b) < tb)) {
+                /* this pixel is within the threshold of the color. */
+                bitmask_setbit(m, x, y);
             }
         }
     }
-
-
-    *num_bounding_boxes = num_regions;
-
-
-    free(used_pixels);
-
-
-    return regions;
 }
 
+static PyObject* mask_from_threshold(PyObject* self, PyObject* args)
+{
+    PyObject *surfobj, *surfobj2;
+    PyMaskObject *maskobj;
+    bitmask_t* m;
+    SDL_Surface* surf, *surf2;
+    int bpp;
+    PyObject *rgba_obj_color, *rgba_obj_threshold;
+    Uint8 rgba_color[4];
+    Uint8 rgba_threshold[4];
+    Uint32 color;
+    Uint32 color_threshold;
+
+    surf2 = surf = NULL;
+    surfobj2 = NULL;
+    rgba_obj_threshold = NULL;
+    rgba_threshold[0] = 0; rgba_threshold[1] = 0; rgba_threshold[2] = 0; rgba_threshold[4] = 255;
+
+    if (!PyArg_ParseTuple (args, "O!O|OO!", &PySurface_Type, &surfobj,
+                           &rgba_obj_color,  &rgba_obj_threshold,
+                           &PySurface_Type, &surfobj2))
+        return NULL;
+
+    surf = PySurface_AsSurface (surfobj);
+    if(surfobj2) {
+        surf2 = PySurface_AsSurface (surfobj2);
+    }
+
+    if (PyInt_Check (rgba_obj_color)) {
+        color = (Uint32) PyInt_AsLong (rgba_obj_color);
+    } else if (PyLong_Check (rgba_obj_color)) {
+        color = (Uint32) PyLong_AsUnsignedLong (rgba_obj_color);
+    } else if (RGBAFromColorObj (rgba_obj_color, rgba_color)) {
+        color = SDL_MapRGBA (surf->format, rgba_color[0], rgba_color[1],
+            rgba_color[2], rgba_color[3]);
+    } else {
+        return RAISE (PyExc_TypeError, "invalid color argument");
+    }
+
+    if(rgba_obj_threshold) {
+        if (PyInt_Check (rgba_obj_threshold))
+            color_threshold = (Uint32) PyInt_AsLong (rgba_obj_threshold);
+        else if (PyLong_Check (rgba_obj_threshold))
+            color_threshold = (Uint32) PyLong_AsUnsignedLong
+                (rgba_obj_threshold);
+        else if (RGBAFromColorObj (rgba_obj_threshold, rgba_threshold))
+            color_threshold = SDL_MapRGBA (surf->format, rgba_threshold[0], rgba_threshold[1], rgba_threshold[2], rgba_threshold[3]);
+        else
+            return RAISE (PyExc_TypeError, "invalid threshold argument");
+    } else {
+        color_threshold = SDL_MapRGBA (surf->format, rgba_threshold[0], rgba_threshold[1], rgba_threshold[2], rgba_threshold[3]);
+    }
+
+    bpp = surf->format->BytesPerPixel;
+    m = bitmask_create(surf->w, surf->h);
+	
+    PySurface_Lock(surfobj);
+    if(surfobj2) {
+        PySurface_Lock(surfobj2);
+    }
+    
+    Py_BEGIN_ALLOW_THREADS;
+    bitmask_threshold (m, surf, surf2, color,  color_threshold);
+    Py_END_ALLOW_THREADS;
+
+    PySurface_Unlock(surfobj);
+    if(surfobj2) {
+        PySurface_Unlock(surfobj2);
+    }
+
+    maskobj = PyObject_New(PyMaskObject, &PyMask_Type);
+    if(maskobj)
+        maskobj->mask = m;
+
+    return (PyObject*)maskobj;
+}
+
+/* the initial labelling phase of the connected components algorithm */
+unsigned int cc_label(bitmask_t *input, unsigned int* image, unsigned int* ufind, unsigned int* largest)
+{
+    unsigned int *buf;
+    unsigned int x, y, w, h, root, aroot, croot, temp, label;
+    
+    label = 0;
+    w = input->w;
+    h = input->h;
+
+    ufind[0] = 0;
+    buf = image;
+
+    /* special case for first pixel */
+    if(bitmask_getbit(input, 0, 0)) { /* process for a new connected comp: */
+        label++;              /* create a new label */
+        *buf = label;         /* give the pixel the label */
+        ufind[label] = label; /* put the label in the equivalence array */
+        largest[label] = 1;   /* the label has 1 pixel associated with it */
+    } else {
+        *buf = 0;
+    }
+    buf++;
+    /* special case for first row */
+    for(x = 1; x < w; x++) {
+        if (bitmask_getbit(input, x, 0)) {
+            if (*(buf-1)) {                    /* d label */
+                *buf = *(buf-1);
+            } else {                           /* create label */
+                label++;
+                *buf = label;
+                ufind[label] = label;
+                largest[label] = 0;
+            }
+            largest[*buf]++;
+        } else {
+            *buf = 0;
+        }
+        buf++;
+    }
+    /* the rest of the image */
+    for(y = 1; y < h; y++) {
+        /* first pixel of the row */
+        if (bitmask_getbit(input, 0, y)) {
+            if (*(buf-w)) {                    /* b label */
+                *buf = *(buf-w);
+            } else if (*(buf-w+1)) {           /* c label */
+                *buf = *(buf-w+1);
+            } else {                           /* create label */
+                label++;
+                *buf = label;
+                ufind[label] = label;
+                largest[label] = 0;
+            }
+            largest[*buf]++;
+        } else {
+            *buf = 0;
+        }
+        buf++;
+        /* middle pixels of the row */
+        for(x = 1; x < (w-1); x++) {
+            if (bitmask_getbit(input, x, y)) {
+                if (*(buf-w)) {                /* b label */
+                    *buf = *(buf-w);
+                } else if (*(buf-w+1)) {       /* c branch of tree */
+                    if (*(buf-w-1)) {                      /* union(c, a) */
+                        croot = root = *(buf-w+1);
+                        while (ufind[root] < root) {       /* find root */
+                            root = ufind[root];
+                        }
+                        if (croot != *(buf-w-1)) {
+                            temp = aroot = *(buf-w-1);
+                            while (ufind[aroot] < aroot) { /* find root */
+                                aroot = ufind[aroot];
+                            }
+                            if (root > aroot) {
+                                root = aroot;
+                            }
+                            while (ufind[temp] > root) {   /* set root */
+                                aroot = ufind[temp];
+                                ufind[temp] = root;
+                                temp = aroot;
+                            }
+                        }
+                        while (ufind[croot] > root) {      /* set root */
+                            temp = ufind[croot];
+                            ufind[croot] = root;
+                            croot = temp;
+                        }
+                        *buf = root;
+                    } else if (*(buf-1)) {                 /* union(c, d) */
+                        croot = root = *(buf-w+1);
+                        while (ufind[root] < root) {       /* find root */
+                            root = ufind[root];
+                        }
+                        if (croot != *(buf-1)) {
+                            temp = aroot = *(buf-1);
+                            while (ufind[aroot] < aroot) { /* find root */
+                                aroot = ufind[aroot];
+                            }
+                            if (root > aroot) {
+                                root = aroot;
+                            }
+                            while (ufind[temp] > root) {   /* set root */
+                                aroot = ufind[temp];
+                                ufind[temp] = root;
+                                temp = aroot;
+                            }
+                        }
+                        while (ufind[croot] > root) {      /* set root */
+                            temp = ufind[croot];
+                            ufind[croot] = root;
+                            croot = temp;
+                        }
+                        *buf = root;
+                    } else {                   /* c label */
+                        *buf = *(buf-w+1);
+                    }
+                } else if (*(buf-w-1)) {       /* a label */
+                    *buf = *(buf-w-1);
+                } else if (*(buf-1)) {         /* d label */
+                    *buf = *(buf-1);
+                } else {                       /* create label */
+                    label++;
+                    *buf = label;
+                    ufind[label] = label;
+                    largest[label] = 0;
+                }
+                largest[*buf]++;
+            } else {
+                *buf = 0;
+            }
+            buf++;
+        }
+        /* last pixel of the row, if its not also the first pixel of the row */
+        if (w > 1) {
+            if (bitmask_getbit(input, x, y)) {
+                if (*(buf-w)) {                /* b label */
+                    *buf = *(buf-w);
+                } else if (*(buf-w-1)) {       /* a label */
+                    *buf = *(buf-w-1);
+                } else if (*(buf-1)) {         /* d label */
+                    *buf = *(buf-1);
+                } else {                       /* create label */
+                    label++;
+                    *buf = label;
+                    ufind[label] = label;
+                    largest[label] = 0;
+                }
+                largest[*buf]++;
+            } else {
+                *buf = 0;
+            }
+            buf++;
+        }
+    }
+    
+    return label;
+}
+
+/* Connected component labeling based on the SAUF algorithm by Kesheng Wu,
+   Ekow Otoo, and Kenji Suzuki.  The algorithm is best explained by their paper,
+   "Two Strategies to Speed up Connected Component Labeling Algorithms", but in
+   summary, it is a very efficient two pass method for 8-connected components.
+   It uses a decision tree to minimize the number of neighbors that need to be
+   checked.  It stores equivalence information in an array based union-find.
+   This implementation also has a final step of finding bounding boxes. */
+static GAME_Rect* get_bounding_rects(bitmask_t *input, int *num_bounding_boxes)
+{
+    unsigned int *image, *ufind, *largest, *buf;
+    unsigned int x, y, w, h, temp, label, relabel;
+    GAME_Rect* rects;
+    
+    label = 0;
+    w = input->w;
+    h = input->h;
+
+    /* a temporary image to assign labels to each bit of the mask */
+    image = (unsigned int *) malloc(sizeof(int)*w*h);
+    /* allocate enough space for the maximum possible connected components */
+    /* the union-find array. see wikipedia for info on union find */
+    ufind = (unsigned int *) malloc(sizeof(int)*(w/2 + 1)*(h/2 + 1));
+    largest = (unsigned int *) malloc(sizeof(int)*(w/2 + 1)*(h/2 + 1));
+    
+    /* do the initial labelling */
+    label = cc_label(input, image, ufind, largest);
+
+    relabel = 0;
+    /* flatten and relabel the union-find equivalence array */
+    for (x = 1; x <= label; x++) {
+         if (ufind[x] < x) {             /* is it a union find root? */
+             ufind[x] = ufind[ufind[x]]; /* relabel it to its root */
+         } else {                 /* its a root */
+             relabel++;                      
+             ufind[x] = relabel;  /* assign the lowest label available */
+         }
+    }
+
+    *num_bounding_boxes = relabel;
+    /* the bounding rects, need enough space for the number of labels */
+    rects = (GAME_Rect *) malloc(sizeof(GAME_Rect) * (relabel + 1));
+    for (temp = 0; temp <= relabel; temp++) {
+        rects[temp].h = 0;        /* so we know if its a new rect or not */
+    }
+    
+    /* find the bounding rect of each connected component */
+    buf = image;
+    for (y = 0; y < h; y++) {
+        for (x = 0; x < w; x++) {
+            if (ufind[*buf]) {         /* if the pixel is part of a component */
+                if (rects[ufind[*buf]].h) {   /* the component has a rect */
+                    temp = rects[ufind[*buf]].x;
+                    rects[ufind[*buf]].x = MIN(x, temp);
+                    rects[ufind[*buf]].y = MIN(y, rects[ufind[*buf]].y);
+                    rects[ufind[*buf]].w = MAX(rects[ufind[*buf]].w + temp, x + 1) - rects[ufind[*buf]].x;
+                    rects[ufind[*buf]].h = MAX(rects[ufind[*buf]].h, y - rects[ufind[*buf]].y + 1);
+                } else {                      /* otherwise, start the rect */
+                    rects[ufind[*buf]].x = x;
+                    rects[ufind[*buf]].y = y;
+                    rects[ufind[*buf]].w = 1;
+                    rects[ufind[*buf]].h = 1;
+                }
+            }
+            buf++;
+        }
+    }
+    
+    free(image);
+    free(ufind);
+
+    return rects;
+}
 
 static PyObject* mask_get_bounding_rects(PyObject* self, PyObject* args)
 {
     GAME_Rect *aregion;
     int num_bounding_boxes, i;
     PyObject* ret;
-
     PyObject* rect;
 
-
-
     bitmask_t *mask = PyMask_AsBitmap(self);
 
-
     ret = NULL;
     num_bounding_boxes = 0;
 
-
-    if(!PyArg_ParseTuple(args, ""))
-        return NULL;
-
     ret = PyList_New (0);
     if (!ret)
         return NULL;
 
-
     Py_BEGIN_ALLOW_THREADS;
 
     regions = get_bounding_rects(mask, &num_bounding_boxes);
 
     Py_END_ALLOW_THREADS;
 
-
-    /* printf("num_bounding_boxes:%d\n", num_bounding_boxes); */
-
-
     /* build a list of rects to return.  */
-    for(i=0; i < num_bounding_boxes; i++) {
+    for(i=1; i <= num_bounding_boxes; i++) {
         aregion = regions + i;
-        /* printf("aregion x,y,w,h:%d,%d,%d,%d\n", aregion->x, aregion->y, aregion->w, aregion->h);
-        */
-
         rect = PyRect_New4 ( aregion->x, aregion->y, aregion->w, aregion->h );
         PyList_Append (ret, rect);
         Py_DECREF (rect);
 
     free(regions);
 
-
     return ret;
 }
 
 
+/* Connected component labeling based on the SAUF algorithm by Kesheng Wu,
+   Ekow Otoo, and Kenji Suzuki.  The algorithm is best explained by their paper,
+   "Two Strategies to Speed up Connected Component Labeling Algorithms", but in
+   summary, it is a very efficient two pass method for 8-connected components.
+   It uses a decision tree to minimize the number of neighbors that need to be
+   checked.  It stores equivalence information in an array based union-find.
+   This implementation also tracks the number of pixels in each label, finding 
+   the biggest one while flattening the union-find equivalence array.  It then 
+   writes an output mask containing only the largest connected component. */
+void largest_connected_comp(bitmask_t* input, bitmask_t* output, int ccx, int ccy)
+{
+    unsigned int *image, *ufind, *largest, *buf;
+    unsigned int max, x, y, w, h, label;
+    
+    w = input->w;
+    h = input->h;
+
+    /* a temporary image to assign labels to each bit of the mask */
+    image = (unsigned int *) malloc(sizeof(int)*w*h);
+    /* allocate enough space for the maximum possible connected components */
+    /* the union-find array. see wikipedia for info on union find */
+    ufind = (unsigned int *) malloc(sizeof(int)*(w/2 + 1)*(h/2 + 1));
+    /* an array to track the number of pixels associated with each label */
+    largest = (unsigned int *) malloc(sizeof(int)*(w/2 + 1)*(h/2 + 1));
+    
+    /* do the initial labelling */
+    label = cc_label(input, image, ufind, largest);
+
+    max = 1;
+    /* flatten the union-find equivalence array */
+    for (x = 2; x <= label; x++) {
+         if (ufind[x] != x) {                 /* is it a union find root? */
+             largest[ufind[x]] += largest[x]; /* add its pixels to its root */
+             ufind[x] = ufind[ufind[x]];      /* relabel it to its root */
+         }
+         if (largest[ufind[x]] > largest[max]) { /* is it the new biggest? */
+             max = ufind[x];
+         }
+    }
+    
+    /* write out the final image */
+    buf = image;
+    if (ccx >= 0)
+        max = ufind[*(buf+ccy*w+ccx)];
+    for (y = 0; y < h; y++) {
+        for (x = 0; x < w; x++) {
+            if (ufind[*buf] == max) {         /* if the label is the max one */
+                bitmask_setbit(output, x, y); /* set the bit in the mask */
+            }
+            buf++;
+        }
+    }
+    
+    free(image);
+    free(ufind);
+    free(largest);
+}
+
+static PyObject* mask_connected_component(PyObject* self, PyObject* args)
+{
+    bitmask_t *input = PyMask_AsBitmap(self);
+    bitmask_t *output = bitmask_create(input->w, input->h);
+    PyMaskObject *maskobj = PyObject_New(PyMaskObject, &PyMask_Type);   
+    int x, y;
+    
+    x = -1;
+
+    if(!PyArg_ParseTuple(args, "|(ii)", &x, &y)) {
+        return NULL;
+    }    
+
+    if (x == -1 || bitmask_getbit(input, x, y))
+        largest_connected_comp(input, output, x, y);
+    
+    if(maskobj)
+        maskobj->mask = output;
+
+    return (PyObject*)maskobj;
+}
 
 
 static PyMethodDef maskobj_builtins[] =
     { "get_at", mask_get_at, METH_VARARGS, DOC_MASKGETAT },
     { "set_at", mask_set_at, METH_VARARGS, DOC_MASKSETAT },
     { "overlap", mask_overlap, METH_VARARGS, DOC_MASKOVERLAP },
-    { "overlap_area", mask_overlap_area, METH_VARARGS,
-      DOC_MASKOVERLAPAREA },
-    { "get_bounding_rects", mask_get_bounding_rects, METH_VARARGS,
+    { "overlap_area", mask_overlap_area, METH_VARARGS, DOC_MASKOVERLAPAREA },
+    { "overlap_mask", mask_overlap_mask, METH_VARARGS, DOC_MASKOVERLAPMASK },
+    { "fill", mask_fill, METH_NOARGS, DOC_MASKFILL },
+    { "clear", mask_clear, METH_NOARGS, DOC_MASKCLEAR },
+    { "invert", mask_invert, METH_NOARGS, DOC_MASKINVERT },
+    { "scale", mask_scale, METH_VARARGS, DOC_MASKSCALE },
+    { "draw", mask_draw, METH_VARARGS, DOC_MASKDRAW },
+    { "erase", mask_erase, METH_VARARGS, DOC_MASKERASE },
+    { "count", mask_count, METH_NOARGS, DOC_MASKCOUNT },
+    { "centroid", mask_centroid, METH_NOARGS, DOC_MASKCENTROID },
+    { "angle", mask_angle, METH_NOARGS, DOC_MASKANGLE },
+    { "outline", mask_outline, METH_VARARGS, DOC_MASKOUTLINE },
+    { "connected_component", mask_connected_component, METH_VARARGS,
+      DOC_MASKCONNECTEDCOMPONENT },
+    { "get_bounding_rects", mask_get_bounding_rects, METH_NOARGS,
       DOC_MASKGETBOUNDINGRECTS },
 
     { NULL, NULL, 0, NULL }
     { "Mask", Mask, METH_VARARGS, DOC_PYGAMEMASKMASK },
     { "from_surface", mask_from_surface, METH_VARARGS,
       DOC_PYGAMEMASKFROMSURFACE},
+    { "from_threshold", mask_from_threshold, METH_VARARGS,
+      DOC_PYGAMEMASKFROMTHRESHOLD},
     { NULL, NULL, 0, NULL }
 };
 
   dict = PyModule_GetDict(module);
   PyDict_SetItemString(dict, "MaskType", (PyObject *)&PyMask_Type);
   import_pygame_base ();
+  import_pygame_color ();
   import_pygame_surface ();
   import_pygame_rect ();
 }
 If the Surface is color keyed, then threshold is not used.
 <END>
 
+from_threshold
+Creates a mask by thresholding Surfaces
+pygame.mask.from_surface(Surface, color, threshold = (0,0,0,255), othersurface = None) -> Mask
+
+This is a more featureful method of getting a Mask from a Surface.  If supplied
+with only one Surface, all pixels within the threshold of the supplied color are
+set in the Mask. If given the optional othersurface, all pixels in Surface that
+are within the threshold of the corresponding pixel in othersurface are set in
+the Mask.
+<END>
+
 Mask
 pygame object for representing 2d bitmasks
-pygame.Mask((width, height): return Mask
+pygame.Mask((width, height)): return Mask
 <SECTION>
 
 get_size
 
 You can see how many pixels overlap with the other mask given.  This can
 be used to see in which direction things collide, or to see how much the
-two masks collide.
+two masks collide.  An approximate collision normal can be found by calculating
+the gradient of the overlap area through the finite difference.
+
+ dx = Mask.overlap_area(othermask,(x+1,y)) - Mask.overlap_area(othermask,(x-1,y))
+ dy = Mask.overlap_area(othermask,(x,y+1)) - Mask.overlap_area(othermask,(x,y-1))
+<END>
+
+overlap_mask
+Returns a mask of the overlapping pixels
+Mask.overlap_mask(othermask, offset) -> Mask
+
+Returns a Mask the size of the original Mask containing only the overlapping
+pixels between Mask and othermask.
+<END>
+
+fill
+Sets all bits to 1
+Mask.fill()
+
+Sets all bits in a Mask to 1.
+<END>
+
+clear
+Sets all bits to 0
+Mask.clear()
+
+Sets all bits in a Mask to 0.
+<END>
+
+invert
+Flips the bits in a Mask
+Mask.invert()
+
+Flips all of the bits in a Mask, so that the set pixels turn to unset pixels and
+the unset pixels turn to set pixels.
+<END>
+
+scale
+Resizes a mask
+Mask.scale((x, y)) -> Mask
+
+Returns a new Mask of the Mask scaled to the requested size.
+<END>
+
+draw
+Draws a mask onto another
+Mask.draw(othermask, offset)
+
+Performs a bitwise OR, drawing othermask onto Mask.
+<END>
+
+erase
+Erases a mask from another
+Mask.erase(othermask, offset)
+
+Erases all pixels set in othermask from Mask.
+<END>
+
+count
+Returns the number of set pixels
+Mask.count() -> pixels
+
+Returns the number of set pixels in the Mask.
+<END>
+
+centroid
+Returns the centroid of the pixels in a Mask
+Mask.centroid() -> (x, y)
+
+Finds the centroid, the center of pixel mass, of a Mask.  Returns a coordinate
+tuple for the centroid of the Mask. In the event the Mask is empty, it will
+return (0,0).
+<END>
+
+angle
+Returns the orientation of the pixels
+Mask.angle() -> theta
+
+Finds the approximate orientation of the pixels in the image from -90 to 90
+degrees.  This works best if performed on one connected component of pixels.  It
+will return 0.0 on an empty Mask.
+<END>
+
+outline
+list of points outlining an object
+Mask.outline(every = 1) -> [(x,y), (x,y) ...]
+
+Returns a list of points of the outline of the first object it comes across in a
+Mask.  For this to be useful, there should probably only be one connected
+component of pixels in the Mask.  The every option allows you to skip pixels in
+the outline.  For example, setting it to 10 would return a list of every 10th
+pixel in the outline.
+<END>
+
+connected_component
+Returns a mask of a connected region of pixels.
+Mask.connected_component((x,y) = None) -> Mask
+
+This uses the SAUF algorithm to find a connected component in the
+Mask. It checks 8 point connectivity.  By default, it will return the largest
+connected component in the image.  Optionally, a coordinate pair of a pixel can
+be specified, and the connected component containing it will be returned.  In
+the event the pixel at that location is not set, the returned Mask will be
+empty.  The Mask returned is the same size as the original Mask.
 <END>
 
 get_bounding_rects
 
 #define DOC_PYGAMEMASKFROMSURFACE "pygame.mask.from_surface(Surface, threshold = 127) -> Mask\nReturns a Mask from the given surface."
 
-#define DOC_PYGAMEMASKMASK "pygame.Mask((width, height): return Mask\npygame object for representing 2d bitmasks"
+#define DOC_PYGAMEMASKFROMTHRESHOLD "pygame.mask.from_surface(Surface, color, threshold = (0,0,0,255), othersurface = None) -> Mask\nCreates a mask by thresholding Surfaces"
+
+#define DOC_PYGAMEMASKMASK "pygame.Mask((width, height)): return Mask\npygame object for representing 2d bitmasks"
 
 #define DOC_MASKGETSIZE "Mask.get_size() -> width,height\nReturns the size of the mask."
 
 
 #define DOC_MASKOVERLAPAREA "Mask.overlap_area(othermask, offset) -> numpixels\nReturns the number of overlapping 'pixels'."
 
+#define DOC_MASKOVERLAPMASK "Mask.overlap_mask(othermask, offset) -> Mask\nReturns a mask of the overlapping pixels"
+
+#define DOC_MASKFILL "Mask.fill()\nSets all bits to 1"
+
+#define DOC_MASKCLEAR "Mask.clear()\nSets all bits to 0"
+
+#define DOC_MASKINVERT "Mask.invert()\nFlips the bits in a Mask"
+
+#define DOC_MASKSCALE "Mask.scale((x, y)) -> Mask\nResizes a mask"
+
+#define DOC_MASKDRAW "Mask.draw(othermask, offset)\nDraws a mask onto another"
+
+#define DOC_MASKERASE "Mask.erase(othermask, offset)\nErases a mask from another"
+
+#define DOC_MASKCOUNT "Mask.count() -> pixels\nReturns the number of set pixels"
+
+#define DOC_MASKCENTROID "Mask.centroid() -> (x, y)\nReturns the centroid of the pixels in a Mask"
+
+#define DOC_MASKANGLE "Mask.angle() -> theta\nReturns the orientation of the pixels"
+
+#define DOC_MASKOUTLINE "Mask.outline(every = 1) -> [(x,y), (x,y) ...]\nlist of points outlining an object"
+
+#define DOC_MASKCONNECTEDCOMPONENT "Mask.connected_component((x,y) = None) -> Mask\nReturns a mask of a connected region of pixels."
+
 #define DOC_MASKGETBOUNDINGRECTS "Mask.get_bounding_rects() -> Rects\nReturns a list of bounding rects of regions of set pixels."
 
 #define DOC_PYGAMEMIXER "pygame module for loading and playing sounds"