Renderstate corruption - Big problem

Apr 2, 2011 at 7:54 PM

Hey there. So basically, I have a game engine that runs perfectly fine with shados, lighting, multiple models and cameras up until I try and add a HUD. I think that the problem is when I add an object to the screen while it is drawing, I'm not sure on this though. But, recently I have tried to add a text element and debug graphs to the scene, during initialization way before any drawing is done.

 

The error is:

World matrix, camera or render state stack corruption detected during method call (Xen.Application :: Void OnDraw(Xen.DrawState))

 

Is there any way to fix this error, or to "go around" it? Try and catch don't work, because the actual game closes. Whenever I get this error, it always calls to the main class' game.run call.

 

        static void Main(string[] args)
        {
            Engine game = new Engine("Play test");
            game.Run(); //Here is where the error points to, so it's hard to pin-point the cause
            game.Shutdown();
        }

Coordinator
Apr 2, 2011 at 10:02 PM

Hi. This error isn't very well written, but what it means is that at some point you are Pushing the stack without popping it. So when the target completes rendering, the stack isn't empty (corrupt probably isn't the best word).

This could happen if you did:

 

state.RenderState.Push()

if (something) return;

state.Pop()

 

Potentially the state doesn't get popped, and the stack gets messed up. This is what the 'using' style is for, if you do:

using (state.RenderState.Push())
{

  ....
}

 

Pop will always get called for you, no matter what.
Internally the DrawTarget makes a copy of the draw list before it starts drawing - so adding something mid-draw won't have any affect until the following frame.

 

Apr 3, 2011 at 3:35 PM
Edited Apr 3, 2011 at 3:40 PM

Perfect reply. Thanks. I'm going to try and implement the using statement, now that I know the cause. One thing I'm not sure about is the using(state.RenderState.Push()), as RenderState has no Push method. I am using Xen 2.0 with XNA 3.1, not sure if that is why. Here is my main draw method:

        protected override void Draw(DrawState state)
        {
            if (hasInitialised)
            {
                if (IS_CLIENT) client.Run();
                isDrawing = true;
                try
                {
                    //Update window title
                    this.Window.Title = "Running for: " + Math.Round(state.TotalTimeSeconds) + " seconds";
                    this.Window.Title = this.Window.Title + " " + string.Format("{0} FPS", state.ApproximateFrameRate);
                    this.Window.Title = this.Window.Title + " " + string.Format("{0} Entities", entityCount);

                    if (Settings.DEVELOPER)
                    {
                        this.Window.Title = this.Window.Title + " [DEVELOPER]";
                    }

                    if (!pauseDraw)
                    {
                        //set a global light collection (that all models will use)
                         state.PushDrawFlag(new MaterialLightCollection.LightCollectionFlag(Lighting.GetList());

                         //draw the shadow map texture first,
                         drawShadowDepth.Draw(state);

                         //apply the blur filter to the shadow texture
                         shadowDepthBlurFilter.Draw(state);
                         
                         //draw the scene to the screen
                         drawToScreen.Draw(state);

                         //reset the flag
                         state.PopDrawFlag<MaterialLightCollection.LightCollectionFlag>();

                    }
                }
                catch
                {

                }
                isDrawing = false;
            }
        }

Also, I love your speedy replies and work on Xen. I rarely see projects that have active discussions like Xen :)