Undo/Redo and Debug Anecdote

posted in Skipping a D
Published June 29, 2009
Advertisement
Oddly enough, undo/redo was actually rather easy to implement. WPF's routed command facility makes it a snap to wire the shortcuts and add the callbacks. The implementation is simply two stacks of an IUndoRedo interface. New actions are pushed onto the Undo stack, and the Redo stack is cleared. If an action is undone, it is popped from the undo stack and pushed onto the redo stack, and vice versa when it is redone. Custom actions can implement this interface and their Undo and Redo methods will be invoked appropriately. Currently I have a MultiPropertyChangedAction that listens to the MultiPropertyGrid and will save all the previous values of a property when it is about to change, so that it can be easily undone. That alone covers a lot of what needs to be undo-able. Other things will include spawning a new object, deleting objects, dragging an object around in the viewports, etc.

----------
EDIT: Yoink. I jinxed the side project by talking about it. Turns out SoundEffect has more limitations than I realized. Pitch shifting is constrained to +/- 1 octave, and there's no effective way to start playing from an offset within a sound. Oh well, back to the editor I guess.
----------

Since the side project has been shelved for now, I'll instead regale any readers with a humorous tale of debugging woe. While running the game and mouse-looking around, things were working great. For some reason I alt-tabbed out to look at something else, and clicked the "show desktop" button to minimize everything, including the game. After bringing the game up again, I noticed something was missing...

All of my tesseracts were gone. Empty nothingness staring back at me like the void of anxiety inside at the realization of another obscure bug. Did it freeze? Was there another race condition in my task manager? Thankfully, the FPS counter was still in the corner dutifully ticking away, so it didn't freeze. The numbers looked right, too, and went down just as they should as I pushed the key to spawn more tesseracts. It was still running, but why wasn't I seeing anything?

Being relatively new to shaders and all that jazz, I immediately suspected something was broken in my rendering code. It was going blank after a minimize, so maybe some kind of lost device situation? To test, I ran it again, and hit ctrl-alt-del to bring up the interrupt menu, which I'm pretty sure causes a lost device. Canceling and going back to the desktop, all the tesseracts were still there. They would ONLY disappear after a minimize, not for any other reason.

Even so, maybe my shader constants were getting messed up somehow. XNA claims to be able to recover most kinds of graphics assets fully after a device lost, but maybe there was some kind of bug with minimizing? I added a special key that would reset the constants to appropriate values when pressed. I ran the game, and before minimizing, I pressed the key. The display didn't change, since the values were still correct, and the console reported that the values had been set. So far, so good.

I minimize and reopen to emptiness. Crossing my fingers, I press the key. Nothing. Seething with frustration, I mash the key and fill the console output with "minimize test" but my rage was insufficient to sway the program to render once more. What the hell was wrong? Maybe I just wasn't asking it to nicely enough. RenderStates.PrettyPlease | RenderStates.WithCherry?

I start reading my Update and Draw methods again and again trying to find out what the eff was wrong. If all my shader constants and render states were fine, it had to be something else. Maybe camera updates were going wonky or something. In desperation, I completely comment out the camera code so the view can't be moved at all, and ran again. Holding my breath, I minimize and reopen, only to be met with...

A floating red tesseract.

YES. I took a quick break to relish the discovery of the problem area. Relaxed and confident, I plow into the camera code. It was obviously getting moved in such a way that you could no longer see the scene. How though? There was code to clamp the camera coordinates to reasonable values on both rotational axes, so even the most erratic movement should be fine. Perplexed, I add a line to print out the camera angles when a key is pressed. Before minimizing I get typical -180 to 180 horizontal and -90 to 90 vertical. Minimizing and reopening yet again, I push the key and still see typical values of -Infinity and NaN. Maybe next I'll- wait, what?

I don't care how high your mouse DPI is, you're not going to be scrolling to -Infinity anytime soon. Besides, my input manager will normalize the coordinates based on the client window size, so-

Oh.

Seems that when you come back from being minimized, the IsActive flag in Game becomes true a few updates before the client width and height are set back to nonzero values. Slapped an if around it and all is well. NaN is fun stuff.
0 likes 0 comments

Comments

Nobody has left a comment. You can be the first!
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement
Advertisement