3
\$\begingroup\$

Because I'm using sprite sheets instead of an individual texture per sprite, I need to pass in a Rectangle when calling Texture2D.GetData() in my collision detection for per-pixel tests. Unfortunately, without fail I get an ArgumentException percolated down from an internal method inside the Texture (not Texture2D) class.

My code for getting the texture data looks like this:

    public override Color[] GetPixelData()
    {
        Color[] data = new Color[(int)size.Product()];
        Rectangle rect = new Rectangle(hframe * (int)size.X, vframe * (int)size.Y, (int)size.X, (int)size.Y);

#if DEBUG
        if (sprite.Bounds.Contains(rect) && sprite.Format == SurfaceFormat.Color)
#endif
            sprite.GetData(0, rect, data, 0, 1);

        return data;
    }

Even with the check to ensure I'm grabbing a valid rectangle and that the texture format matches what I'm trying to get, I still get that exception, claiming "The size of the data passed in is too large or too small for this resource." Unfortunately, the debugger won't let me check the locals within the Texture.ValidateTotalSize() method where the exception originates.

Has anyone else had this problem and knows how to fix it? I'm relying on AABB testing only for now, but that doesn't really work for some of my game's entities due to odd shapes, rotation and scaling.

\$\endgroup\$
6
\$\begingroup\$

You can use Reflector to look inside Texture.ValidateTotalSize() to get an idea of what might be happening to throw the exception.

But in this case I think it's simply that:

sprite.GetData(0, rect, data, 0, 1);

should be:

sprite.GetData(0, rect, data, 0, data.Length());
\$\endgroup\$
1
  • \$\begingroup\$ That was exactly it, and I feel like such an idiot for not checking Reflector earlier to discover this. Thanks, Andrew! \$\endgroup\$ Jan 6 '11 at 6:32
0
\$\begingroup\$

The code you've posted isn't necessarily enough to figure out what's going wrong. XNA's Texture2D.GetData() method takes a Type, for instance, so you must be using some custom class. I have a guess though.

From the looks of it, the type you're using for size uses floats (or doubles; same thing for purposes of this). It's eminently possible that the problem comes from that: casting a float to an int truncates the result. Assuming size.Product() multiplies the floats together and returns the result, you could easily be getting something like:

size.X = 10.3 size.Y = 20.4

(int)size.X * (int)size.Y = 200 (int)(size.X * size.Y) = 210

Try:

Color[] data = new Color[(int)size.X * (int)size.Y];

and see what happens.

\$\endgroup\$
3
  • \$\begingroup\$ No custom classes here. Microsoft.Xna.Framework.Graphics.Texture2D, Microsoft.Xna.Framework.Color. And I'm simply using Vector2 out of laziness (no IntVector2, although I suppose Short2 sould be okay); while the values are kept in floats, they're integer values and not large enough to round do different numbers. Changing how data's number of elements is calculated changes nothing. \$\endgroup\$ Jan 6 '11 at 5:34
  • \$\begingroup\$ Also, Type with a capital T is a lot different than a generic type. GetData() doesn't take a Type; it takes in an array of a generic type derived from ValueType (i.e. a struct), where that type matches the surface format's bit size -- as Color does for my texture images (32-bit, ARGB). \$\endgroup\$ Jan 6 '11 at 5:36
  • \$\begingroup\$ Actually Point is what I should be using, and I've switched to that. Still no difference; GetData() continues to toss. \$\endgroup\$ Jan 6 '11 at 5:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.