Original Post
Hola: Is there an easy way to mask a sprite in XNA? Right now, when a sprite goes off screen I am trying to clip it (to make controls adhere to the bounds of their parent control). This works for the destination rect as I can effectively clip the destination to it's parent using intersection. However, the source rectangle needs to update also (by the percentage that the dest was clipped). This amounts to a fairly complicated bit of code (see below) and suffers greatly from rounding errors. For instance, I move a 100 unit control 1.5 units off to the left so that there are not 98.5 units remaining visible. I would similarly have to cut that 1.5% off of the left edge of the source rect in order for it to render properly. However, being a rectangle and dealing with ints that 1.5% (1.5 pixels) becomes 2 whole pixels which causes some popping of the texture when I move the control. Now I am investigating if there is a simple way to CLIP a rectangle against another rectangle before it is drawn? The source for how I am currently doing this is below, in case someone spots a flaw in my logic. TIA, Webby EDIT * Fixed something in the code (transposed an X with a Y), unrelated to original proglem. [Edited by - WebsiteWill on August 12, 2007 11:47:08 AM]
private Rectangle GetClippedSourceSpriteAgainstDestinationAndParent(Rectangle sourceRect, Rectangle originalDestinationRect, Rectangle clippedDestination)
{
if (_parentControl != null)
{
Rectangle parentRect = _parentControl.ControlRectangle.Rect;
int originalRectMinX = originalDestinationRect.X;
int originalRectMinY = originalDestinationRect.Y;
int originalRectMaxX = originalDestinationRect.X + originalDestinationRect.Width;
int originalRectMaxY = originalDestinationRect.Y + originalDestinationRect.Height;
int parentRectMinX = parentRect.X;
int parentRectMinY = parentRect.Y;
int parentRectMaxX = parentRect.X + parentRect.Width;
int parentRectMaxY = parentRect.Y + parentRect.Height;
bool clippingLeft = originalRectMinX < parentRectMinX;
bool clippingRight = originalRectMaxX > parentRectMaxX;
bool clippingTop = originalRectMinY < parentRectMinY;
bool clippingBottom = originalRectMaxY > parentRectMaxY;
int amountClippedFromLeft = (parentRectMinX - originalRectMinX) > 0 ? parentRectMinX - originalRectMinX : 0 ;
int amountClippedFromRight = (originalRectMaxX - parentRectMaxX) > 0 ? originalRectMaxX - parentRectMaxX : 0;
int amountClippedFromTop = (parentRectMinY - originalRectMinY) > 0 ? parentRectMinY - originalRectMinY : 0;
int amountClippedFromBottom = (originalRectMaxY - parentRectMaxY) > 0 ? originalRectMaxY - parentRectMaxY : 0;
float percentClippedFromLeft = originalDestinationRect.Width != 0 ? (float)amountClippedFromLeft / (float)originalDestinationRect.Width : 0;
float percentClippedFromRight = originalDestinationRect.Width != 0 ? (float)amountClippedFromRight / (float)originalDestinationRect.Width : 0;
float percentClippedFromTop = originalDestinationRect.Height != 0 ? (float)amountClippedFromTop / (float)originalDestinationRect.Height : 0;
float percentClippedFromBottom = originalDestinationRect.Height != 0 ? (float)amountClippedFromBottom / (float)originalDestinationRect.Height : 0;
int newSourceRectMinX = sourceRect.X + (int)((float)(sourceRect.Width * (float)percentClippedFromLeft));
int newSourceRectMinY = sourceRect.Y + (int)((float)(sourceRect.Height * (float)percentClippedFromTop));
int newSourceRectMaxX = (sourceRect.X + sourceRect.Width) - (int)((float)(sourceRect.Width * (float)percentClippedFromRight));
int newSourceRectMaxY = (sourceRect.X + sourceRect.Height) - (int)((float)(sourceRect.Height * (float)percentClippedFromBottom));
return new Rectangle(newSourceRectMinX, newSourceRectMinY, newSourceRectMaxX - newSourceRectMinX, newSourceRectMaxY - newSourceRectMinY);
}
else
{
return sourceRect;
}
}