# SpriteBatch.Draw() rectangle is different from destinationRectangle passed in

When I ask SpriteBatch to draw a rectangle as within the following method :

    public static void DrawSolidRectangle(Rectangle rectangle, Color color)
{
// the output from this is shown in the screenshot
System.Console.WriteLine(rectangle.ToString());
spriteBatch.Draw(pixel, rectangle, color);
}


I am getting different sized rectangles to the rectangles I am providing. This is an issue I am having after resizing the window. As you can see in the screenshots, the difference in width of the two rectangles is only 2 pixels and there is an offset of 1 pixel, while the two gray rectangular draw results clearly have greater than a 3 pixel difference in width.

screen shot of issue http://users.tpg.com.au/gavinw77//SpriteBatchIssue.jpg

Does anyone know what's going on ? Is this a known issue with SpriteBatch or the BackBuffer after resizing or what ?

• How you calc your rectangle? if you resize you changes your backbuffer... – Blau Sep 24 '11 at 7:49
• You are sure that is only off by a 2-3 pixels (looks like more to me visually as opposed to numerically) and that you are updating the size of your backbuffer and render target so that its not shrinking them down to fit to whatever the size of the window is now? – James Sep 24 '11 at 9:15
• Note that normally the back buffer will only grow and never shrink*, maybe this is the issue. Do you use ViewPort.Width or BackBuffer.Width to calculate the sizes? (*= I didn't look this up, but I can recall reading it) – Roy T. Sep 24 '11 at 19:51

You may need to update some viewport config so the framework/dx updates your projection transform attributes (it seems to be working with the older view/projection matrix). I don't know how XNA works, but DirectX works that way, with normalized screen coords, which are subject to pipeline transforms. If the view/projection transform is not updated to match your new window size, the image enlarges to sides proportional to the size change, instead of keeping absolute "pixel coordinates" (because normalized coords are relative to window size).

ID3DXSprite behaves this way at least (it seems to build matrices from viewport sizes, or swapchain sizes, not sure which one), and I believe SpriteBatch is no different in this situation, so you will have to find out how to make XNA properly apply it's screen-to-normalized-to-screen-cord transforms. This is because either the DX pipeline expects normalized coords (emulates sprites with 3d vertices and shaders) or the GPU expects to work with normalized coords, or both, instead of raw pixel coordinates.

• I think this is in the right direction. Because mostly my controls are resizing with my window, but sometimes they resize incorrectly. Occasionally i see this result: !image . That looks to me as though the spriteBatch or device is not being reconstruct properly after a resize. – Gavin Williams Sep 24 '11 at 10:40
• I added GDM.PreferredBackBufferWidth = presentationRegion.Width; GDM.PreferredBackBufferHeight = presentationRegion.Height; to Window.ClientSizeChanged() because i noticed that my backbuffer wasnt changing. I was only doing presentationRegion = GDM.GraphicsDevice.PresentationParameters.Bounds; but i still get the problem. One thing i notice is that if i drag the window over to the other monitor, so i guess the device is recreated, the layout is correct. So if there was some way to force device recreation on resize ! – Gavin Williams Sep 24 '11 at 11:01
• If SpriteBatch allows overriding the transform (which in ID3DXSprite is D3DXSPRITE_OBJECTSPACE flag on Begin(flags) and then SetTransform(Matrix)) then you could build the proper view/projection matrix yourself from your screen size. The matrix job would be transforming sprite vertices (defined in pixel screen coords) to normalized screen coordinates. – Pablo Ariel Sep 24 '11 at 11:05
• It could be an issue when resetting the device, some resource not being updated properly. I don't know how XNA manages that, but on D3D device resets there are resources that must be reloaded in different ways (such as swapchain and viewports, if you rely on DX pipeline matrices), XNA should take care about that I guess, so I would first look into the game code, perhaps there is something you should manually set on the device or something on window resize events. – Pablo Ariel Sep 24 '11 at 11:17

When you resize, the backbuffer changes... so you have to recalc your control sizes...

in the game class you can subscribe to this event to recalc your controls:

   this.Window.ClientSizeChanged+= Recalc;


if you are recalculating the difference maybe due the float precission lost when you convert to int.

• True, in fact that was the problem at first, and i thought I'd fixed it by sorting out the int to float rounding issues. But the problem persists. I am subscribing to the ClientSizeChanged event [code] // Event manager that responds to the window size being changed private static void Window_ClientSizeChanged(object sender, EventArgs e) { presentationRegion = GDM.GraphicsDevice.PresentationParameters.Bounds;[code] – Gavin Williams Sep 24 '11 at 8:12
• And the values for the destination rects are the final values after scaling calculations have already been performed, and most notably, the values as seen in the screen shots are those passed to the spritebatch, which by that stage represent absolute window space ordinates. ps. sorry for the [code] block above, im trying to get to grips with the confines of the Add Comment tool. – Gavin Williams Sep 24 '11 at 8:25

Well, this is both funny and painful because of how much time I spent trying to resolve this issue. The corruption might have been a clue. I loaded up the program tonight and the issue is non-existent now. It turned out to be a driver issue, because I have just installed the AMD Catalyst 11.10 Preview driver and haven't touched the re-sizing code. That makes sense. :)

I still haven't resolved this issue, although I also haven't fully absorbed Pablo's suggestions. That goes a bit beyond my level perhaps. I'm starting to think though, that it's not any issue with my code, and that the spriteBatch or device simply isn't doing it's job at resizing as I expect it should be (I see that Pablo was saying this basically). To demonstrate that my back-buffer, client bounds and viewport are all in sync immediately before the spriteBatch draw call, I am outputting the width values to the window title.

Here is a screenshot of how the window looks at startup. This is the good result. screenshot showing good result http://users.tpg.com.au/gavinw77//Issue_good.JPG Here is a screenshot of how the window looks after a few re-size's, I bring it back to the original width of 800 to emphasize the difference. This is not desirable. screenshot showing bad result http://users.tpg.com.au/gavinw77//Issue_bad.JPG

Clearly the rectangle that the spritebatch is drawing in the second example is larger than 792 pixels, as it clearly consumes the entire client bounds.

Here's the code that gather's the info and sends the spriteBatch draw call

game.Window.Title =      "spriteBatch.gd.pp.BackBufferWidth="+spriteBatch.GraphicsDevice.PresentationParameters.BackBufferWidth.ToString();
game.Window.Title += " | windows.ClientBounds= " + game.Window.ClientBounds.Width;
game.Window.Title += " | Viewport.Width" + spriteBatch.GraphicsDevice.Viewport.Width;
game.Window.Title += " | sb draw rect=" + rectangle.Width;

spriteBatch.Draw(pixel, rectangle, color);


I just feel like either I'm doing something fundamentally wrong with my resize handling to cause it to glitch out like that, or else xna is glitching out, I simply cant locate any problem in code. As the numbers above demonstrate, everything actually looks ok. I have two different frames, both with back-buffers of 800, both with window client bounds of 800, both rendering a rectangle of 792, but they are different !