Direct3D and an MDI interface

J

Jon Rea

I have an MDI application that has multiple different "modular documents".
Each document can own multiple MDI windows that are managaed by a manager
class that uses the singleton pattern and holds a link to the MDI container.

Currently some of these MDI windows implement a simple 3D view using the
CSGL openGL graphics wrapper.

I want to have a play with direct3D. I have downloaded the SDK and all the
samples and these are working, however all the tutorials use the following.

All source code is taken unmodified from the Direct3D SDK Tutorial 1 ... I
just would like help applying this to my prog ....

Main()
{
using (CreateDevice frm = new CreateDevice())
{
if (!frm.InitializeGraphics()) // Initialize Direct3D
{
MessageBox.Show("Could not initialize Direct3D. This
tutorial will exit.");
return;
}
frm.Show();

// While the form is still valid, render and process
messages
while(frm.Created)
{
frm.Render();
Application.DoEvents();
}
}
}
}

The render function performs the maths for changing the scene per frame ...

public CreateDevice()
{
// Set the initial size of our form
this.ClientSize = new System.Drawing.Size(400,300);
// And it's caption
this.Text = "D3D Tutorial 01: CreateDevice";
// Load our icon from the resources of the .exe
this.Icon = new Icon(this.GetType(), "directx.ico");
}

public bool InitializeGraphics()
{
try
{
// Now let's setup our D3D stuff
PresentParameters presentParams = new PresentParameters();
presentParams.Windowed=true;
presentParams.SwapEffect = SwapEffect.Discard;
device = new Device(0, DeviceType.Hardware, this,
CreateFlags.SoftwareVertexProcessing, presentParams);
return true;
}
catch (DirectXException)
{
return false;
}
}
private void Render()
{
if (device == null)
return;

//Clear the backbuffer to a blue color
device.Clear(ClearFlags.Target, System.Drawing.Color.Blue, 1.0f, 0);
//Begin the scene
device.BeginScene();

// Rendering of scene objects can happen here

//End the scene
device.EndScene();
device.Present();
}
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
this.Render(); // Render on painting
}

Now for my question .....

As my MDI prog can have multiple 3D view windows, what is the best way to
implement each form rendering itself (ive tried having a thread running
render with a wait statement, but i dont like this solution), i.e.
triggering a paint event when there is free CPU time. I dont want to have to
implement a messy loop from the main document manager class (remembering
that each "Document" can own multiple MDI windows) to trawl through each of
the child documents and call render if the child is a 3D window.

Many thanks for any help
Jon Rea
 
S

Stephan Rose

I too have multiple MDI windows, all using Direct3D.

However, I have no need to realtime updates, so OnPaint is more than
sufficient for me as the only time I need to redraw is if a command is
being executed (CAD application).

First off, what you definitely do NOT want to do is create a device
per MDI Child. This is a bad thing....

Here's how I do it:

Create device, 1 backbuffer sized large enough to cover any reasonable
screen resolution (I suppose I could detect the current resolution and
use that instead..but I'm lazy). Present flags include Lockable
backbuffer so I can use GDI+ for text rendering, and Swapeffect set to
copy.

Then, for each client..whenever it needs to redraw..call Invalidate
for the form..and in the on paint...draw my stuff...Then to present, I
specify the mdi child windows' client rectangle as a source and
destination rectangle, and also specify the handle to the child window
that I'm currently rendering into..and that's it.

Now my application is a 2D application...so I'm just using the 3D
hardware to accelerate my 2D aspects (constructiong all elements out
of triangles, etc. Far faster than GDI+) and all my coordinates are
already transformed and in screen space.

However, if you have a real 3D scene, with untransformed coordinates,
in this case...you would not want to use SwapEffect.Copy, nor would
you want to use the source/destination rectangle parameters of Present
because you'd only get to see a portion of your scene. In that
case...you'd want swap effect discard, and simply just specify the
handle of the current child window you want to render into.

So...either method, depending on your needs..should solve your
problem.

Now if you have any realtime 3D animations to show....in that
case..you'd want to create a seperate thread from the mdi child window
that handles the render task and updates the viewing area as needed.
You could either call invalidate and handle the redraw from OnPaint,
or just simply call the render function..the call to present will
update the view no matter if it's called from within the paint message
or not.

You want to avoid using the while(frm.created)(DoEvents) loop....

Remember...the tutorial samples are made for simplicity and to be as
barebone as possible..but they may not necessarily be the best
implementation (that while loop being one thing not to do in a real
app).

Stephan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top