6
\$\begingroup\$

I know this may sound like an odd question but I just wanted to confirm which way it is.

Currently I am using XNA within Windows Forms (MDI) and I am just wondering about the viewport, as I have multiple forms with their own graphics device to draw with.

Now originally I just assumed the viewport was meant to be a basically a wrapper for the screen size (i.e., width and height), however I noticed it contains an X and Y. So then I was unsure if it was meant to directly represent the drawing region of the device.

Take for example the below scenario:

I have a forms with a panel which is docked within a group box, its relative position in the form is { X: 100, Y: 100, Width: 320, Height: 280 } however its absolute position on the screen would be lets say { X: 400, Y: 320, Width: 320, Height: 280 }. Then if I were to use it like I was originally assuming the panel itself which hosts the underlying handle for Xna to draw to it would be { X: 0, Y: 0, Width: 320, Height: 280 }.

So if you imagine I then start dragging the window around a bit, the relative positions do not change, but obviously the absolute one would, as you could technically drag the panel off screen.

So basically the question is, do I need to use absolute positions for my viewport and update them every time the graphics device is about to be drawn, or do I use relative positions and only update when the area is resizing? and if so is it relative to the form, or is it always going to be 0,0 for the x/y in this scenario?

\$\endgroup\$

2 Answers 2

7
\$\begingroup\$

No.

The viewport is a rectangular region on the backbuffer that determines the area in which the rasteriser draws pixels. A viewport (X,Y) of (0, 0) is always the top-left corner of the backbuffer (in XNA). You can freely move and resize it within the backbuffer.

The backbuffer is the underlying surface that the GPU is drawing to. To resize it you have to reset the graphics device. It doesn't have a position of its own - it is drawn on whatever window it is attached to, using that window's position (in this case, a panel counts as a window).

When rendering, the rasteriser takes inputs in projection space, converting vertex positions to pixel positions within the viewport. The position (-1, -1) in projection space is in the bottom-left of the viewport, and (1, 1) is in the top-right. To transform the 3D vertices in your world into projection space, you use a projection matrix.

(SpriteBatch's default projection matrix lets it take input coordinates in client space within the viewport.)

Here are some references about the various things that determine display size and about projection space.

\$\endgroup\$
0
3
\$\begingroup\$

Taken directly from the Winforms Series samples, here's the relevant bit of code related to your question. There was also a bit of commentary in there that might be useful.

void BeginDraw()
{
    // ... other code handling device resetting

    // Many GraphicsDeviceControl instances can be sharing the same
    // GraphicsDevice. The device backbuffer will be resized to fit the
    // largest of these controls. But what if we are currently drawing
    // a smaller control? To avoid unwanted stretching, we set the
    // viewport to only use the top left portion of the full backbuffer.

    Viewport viewport = new Viewport();
    viewport.X = 0;
    viewport.Y = 0;
    viewport.Width = ClientSize.Width;
    viewport.Height = ClientSize.Height;
    viewport.MinDepth = 0;
    viewport.MaxDepth = 1;
    GraphicsDevice.Viewport = viewport;

    // ...
}

In short, they never change the Viewport X and Y anywhere on the code and it still works in the scenario you described.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .