Does C# have SetViewport()? (different sized swapchain windows)

Started by
4 comments, last by Firebrand10 16 years, 11 months ago
Hello, I'm working on a level editor that uses directX to handle all of the graphics and am having a problem with the viewport of one of my swapchains. I have found numerous references to SetViewport() but it appears to only be used in C++ directX apps. I currently have two windows that are different sizes and would like to be able to share textures between the two. If someone could provide a little code example on how to use SetViewport(), if it exists, I would very much appreciate it. Else, is there any other tricks that I could use to only render a section of the backbuffer to my swapchain window?
Advertisement
From what I've seen of C#, it's probably something like Device.Viewport.*, with X, Y, Width, Height, MinZ, and MaxZ.

Isn't your swapchain created the size of your swapchain window, which should be the size you want to render?

You should just be able to grab the swapchain's backbuffer, (and your manually created identically sized Z buffer), and use SetRenderTarget, SetDepthStencilSurface to activate them. Render. Use the swapchain's present. Restore the rendertarget and depth buffer via another SetRenderTarget and SetDepthStencilSurface, render for the main window, and use the device's present. You may need to store the device's Z buffer surface before applying your own for use with your swap chain, as I don't think there is any way to get that surface back from the device once you've set another surface.
Aye, I have the swapChains setup and both the main surface and the swapchain surfaces are created from a manually created/sized backbuffer. Since one window is much smaller than the other the surface of the smaller window is all squashed up. Changing the Viewport values only seems to alter the viewable surface area in the window but the altered view is still squashed the same as it was, you just see less of the surface in the window.

I've seen a few references here and there to one of the Present() overrides that looks something like...

Present(src, dest, null);

If I were to apply a smaller dest rect and create the src rect based on the current backbuffer size would that force the window to show only a section of the backbuffer surface without deforming the surface?

What I'm starting to think is that it would probably be better to just initialize a different device for windows of different sizes and just add swapchains if I plan on duplicating a window only.
The regular device present (in C++ anyway) allows you to present to any HWND you want. It just stretchrects your backbuffer to fit the window. You can draw, Present to one window, draw more, present to another window.

Without swapchains, you can use viewports to limit the area drawn to, and pass rects to Present to avoid stretching as long as the other window is smaller than your device's back buffer.

The whole point to extra swapchains is that you get a completely seperate backbuffer with it's own size and AA settings for use with another window. It's still up to you to actually activate this other render target, and to create a matching Z buffer. You can then use the Present call in the swapchain to present this other backbuffer to it's window (or, again, any other window).

Creating multiple devices is not recommended unless you really need to draw across multiple monitors. You'll need each device to have it's own vertex buffers, index buffers, shaders, textures, etc. Basically you'll eat twice the video memory, add all sorts of complexity into your objects to keep track of multiple resource pointers for all your devices.

It's easier to try to find what's going wrong with your swapchains. The FAQ (or the useful thread sticky, if that's still there) has a link to a simple swapchain sample I made. It's C++, but as long as you can figure out the C# equivilent of each step, you should be good to go.

edit:
http://www.gamedev.net/community/forums/topic.asp?topic_id=369502
I hadn't seen that sample before but it was quite helpful. I changed my code to match but now the swapChain window isn't being rendered to for some reason. I checked through the device parameters on debug and they appear to be correct once it gets through the second renderState but nothing is showing up after the swap.Present(); Here's some of my code, I removed the exception handling so I didn't have to paste more lines then necessary.

public App()
{
graphics = new Graphics();
}

//initialize application objects
public void Initialize(Control RenderWin1, Control RenderWin2)
{
renderWin1 = RenderWin1;
renderWin2 = RenderWin2;
graphics.CreateDevice(renderWin1);

graphics.CreateSwapChain(renderWin2);
//graphics.ResetDev();

spriteObj = new SpriteObj(graphics);
spriteObj.Initialize(graphics);

graphics.D3DDevice.DeviceReset += new EventHandler(OnDeviceReset);
graphics.D3DDevice.DeviceLost += new EventHandler(OnDeviceLost);
}

//render tilespace scene
public void RenderScene1(Control RenderTarget)
{
graphics.D3DDevice.RenderState.Lighting = false;
graphics.D3DDevice.RenderState.ZBufferEnable = true;
graphics.D3DDevice.RenderState.SourceBlend = Blend.SourceAlpha;
graphics.D3DDevice.RenderState.DestinationBlend = Blend.InvSourceAlpha;

graphics.D3DDevice.SetRenderTarget(0, graphics.DevSurface);
graphics.D3DDevice.DepthStencilSurface = graphics.DevDepthSurf;
graphics.D3DDevice.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.FromArgb(255, 0, 255, 0), 1.0f, 0);
graphics.D3DDevice.BeginScene();
spriteObj.Draw();
graphics.D3DDevice.EndScene();
graphics.D3DDevice.Present();
}
//render workspace swapchain scene
public void RenderScene2(Control RenderTarget)
{
graphics.D3DDevice.RenderState.Lighting = false;
graphics.D3DDevice.RenderState.ZBufferEnable = true;
graphics.D3DDevice.RenderState.SourceBlend = Blend.SourceAlpha;
graphics.D3DDevice.RenderState.DestinationBlend = Blend.InvSourceAlpha;

Viewport view2 = new Viewport();
view2.X = 0;
view2.Y = 0;
view2.Height = RenderTarget.ClientSize.Height;
view2.Width = RenderTarget.ClientSize.Width;
view2.MinZ = 0.0f;
view2.MaxZ = 1.0f;

graphics.D3DDevice.Viewport = view2;

graphics.D3DDevice.SetRenderTarget(1, graphics.SwapSurface);
graphics.D3DDevice.DepthStencilSurface = graphics.SwapDepthSurf;
graphics.D3DDevice.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.FromArgb(255, 255, 0, 0), 1.0f, 0);
graphics.D3DDevice.BeginScene();
spriteObj.Draw();
graphics.D3DDevice.EndScene();
graphics.Swap1.Present();
}

//funct call from grapchics class to initialize swapChain
public void CreateSwapChain(Control RenderWin)
{
pParams2 = new PresentParameters();

pParams2.BackBufferCount = 1;
//pParams.BackBufferFormat = Format.A8R8G8B8;
pParams2.BackBufferHeight = RenderWin.ClientSize.Height;
pParams2.BackBufferWidth = RenderWin.ClientSize.Width;
pParams2.DeviceWindowHandle = RenderWin.Handle;
pParams2.SwapEffect = SwapEffect.Discard;
pParams2.Windowed = true;
pParams2.PresentationInterval = PresentInterval.Immediate;

swap1 = new SwapChain(dev, pParams2);
swapSurf = swap1.GetBackBuffer(0, BackBufferType.Mono);
swapDepthSurf = dev.CreateDepthStencilSurface(
RenderWin.ClientSize.Width,
RenderWin.ClientSize.Height,
DepthFormat.D16,
pParams2.MultiSample,
pParams.MultiSampleQuality,
true);

devSurf = dev.GetBackBuffer(0, 0, BackBufferType.Mono);
devDepthSurf = dev.DepthStencilSurface;
}
OK nevermind I figured it out. For some reason I had...
graphics.D3DDevice.SetRenderTarget(1, graphics.SwapSurface);
instead of
graphics.D3DDevice.SetRenderTarget(0, graphics.SwapSurface);

How that got changed I'll never know.

Thank you very very very much for your help and taking the time to reply. It is most appreciated!!!!!

This topic is closed to new replies.

Advertisement