Jump to content
  • Advertisement
Sign in to follow this  

Sprite masking

This topic is 3994 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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.
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);
                return sourceRect;

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]

Share this post

Link to post
Share on other sites
Well, I ended up doing the same thing for the top, bottom, left and right sides of my UI widgets. I take the overall dimension for the piece in question and divide that into pieces equal in size to the source rectangle. The right side and bottom rectangles can be trimmed effectively to fit these bounds.

Now, my code for clipping the rectangles works more appropriately. I am sure there are edge cases where you might still see a pixel worth of popping but I am not going to worry about those as any sensible GUI texture layout shouldn't suffer from this.

If anyone has a better idea, please spill it. :)


Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!