Managed DX: OnPaint Problem

Started by
2 comments, last by DmGoober 19 years, 6 months ago
I'm writing a game that has multiple views of the 3D Game World. Because of this, I have multiple devices, each associated with different System.Windows.Forms.Panel objects (ie, my devices are not tied to the Form, they are tied to panels.) I've created a new class, RenderPanel, that flags each Panel's style as: AllPaintingInWmPaint, Opaque, and UserPaint. My OnPaint override renders everything then calls Invalidate(), so that OnPaint is called again pretty much immediately. Unfortunately, whenever I Invalidate() my RenderPanel, OTHER controls in the same form stop rendering (the desktop shows through where these other controls should be.) My RenderPanels render everything fine, but nobody else works correctly. If I comment out the "Invalidate()" call on my panel, everything works fine (except that my panel's OnPaint is not called every frame.) It doesn't seem like Invalidating my panel should have any effect on any other controls that happen to be in the same Form... Any suggestions? Thanks in advance.
Alexander "DmGoober" Jhinalexjh@online.microsoft.com[Warning! This email account is not attended. All comments are the opinions of an individual employee and are not representative of Microsoft Corporation.]
Advertisement
Here's a simpler explanation:
public class TestPanel : Panel	{		public TestPanel()		{			//Setup the panel to paint in WMPaint.			this.Setstyle(Controlstyles.AllPaintingInWmPaint |				Controlstyles.Opaque |				Controlstyles.UserPaint, 				true);		}		protected override void OnPaint(PaintEventArgs e)		{						Invalidate(false);   //DEBUG Only!		}	}


Add this panel to a form and all other controls will stop rendering correctly.
Alexander "DmGoober" Jhinalexjh@online.microsoft.com[Warning! This email account is not attended. All comments are the opinions of an individual employee and are not representative of Microsoft Corporation.]
Hmmm this is tricky, but I think I know what's going on.

Tom Miller's 'OnPaint' game loop is the best game loop for MDX engines as far as I know - so you're right to use it, but unfortunately when you're rendering to multiple controls it complicated things.

Think about rendering to a single control for a start. Usually, the OnPaint/this.Invalidate cycle is the actual game loop that keeps the game running and paced. Having everything based on this loop is fine in this case, because there's only one and it paces everything else.

However if you create controls that are rendering, each with their own gameloop this causes problems. Consider the startup procedure for them:
Your fist control is initialized, recieves an OnPaint call, paints itself and then this.Invalidate() is called. Instantly, OnPaint is called again, and the process is repeated.

So when does the second control ever get round to rendering? It doesn't - because the first control is still busy running around in its own loop.

The solution (I think) would be to take the emphasis of the render/invalidate loop off from being a gameloop and being more of a 'render'loop instead.

There could be two options here:
1. Have your own custom gameloop outside the controls that invalidates each control when necessary (so the OnPaint method does not invalidate the control)
2. Have each control exist in a thread of its own.

I'd choose option 1, since working with threads unecessarily is dangerous.
Thanks Martaver! That was my first design (having a main render loop that "touches" each RenderPanel to tell it to refresh). I was hoping I could get away with the main form not knowing anything about Rendering Panels (ie having each render panel be self contained, with the main loop knowing nothing about it) but I guess that won't work because the Render Panels end up acting selfishly.

Now of course, the problem is that my main render loop is going to hog all of the CPU time from the non-custom controls! =) In other words:

OnEachTick
{
Invalidate Render Panel 1
Invalidate Render Panel 2
...
}

Will share CPU time amongst the Render Panels, but the other controls are still going to be CPU starved...

Maybe this is one of the cases where it's best to go back to the dreaded Application.DoEvents() model...

(Though I suppose:
OnEachTick
{
Invalidate Render Panel 1
Invalidate Form and Children
}

will also do the trick, but that will needlessly redraw all of the other controls every tick...
Alexander "DmGoober" Jhinalexjh@online.microsoft.com[Warning! This email account is not attended. All comments are the opinions of an individual employee and are not representative of Microsoft Corporation.]

This topic is closed to new replies.

Advertisement