
This example shows the importance of handling GL state
efficiently. The example builds a small scenegraph similar to what
would be implemented in many graphics applications. The scenegraph is 
far from being complete, efficient, or architected in the best manner
for an application. The intent is to provide a framework to try
different state handling methods.  

Usage:
  go.exe #_of_nodes

#_of_nodes defaults to 50,000 if no value is given.

the 'r' key will force a redraw
	
The code to drive the scenegraph is in state.cxx. The main() creates a 
new scenegraph, inits OpenGL, and sets up keyboard and redraw
functions. The redraw function renders the scenegraph in four
different ways, each one timed:

  - with the plainStateMgr
  - with the smartStateMgr
  - sorted with the smartStateMgr
  - sorted with the plainStateMgr

Setting state is expensive and keeping track of state is difficult. It
is generally desirable to keep your application in a known state. Next
to memory corruption errors, tracking down an errant glEnable() or
other bad piece of state is one of the worst debugging chores. The
approach that many applications take is to ensure that each "node"
(object, function, thing that renders) sets the state back to what it
was before that node was entered. This is easily done using
glPushAttrib() and glPopAttrib() or by simply churning out all the
code by hand. 

As can be seen by running this example, using glPushAttrib() and
glPopAttib() pairs isn't a very good idea. This is how plainStateMgr
works. It first call glPushAttrib() to save state, sets the state to
whatever it is told to, and then calls glPopAttrib() after the render
of the node is complete. Explicitly setting and resetting the state
instead of glPushAttrib/glPopAttrib is better, but it is still
inefficient. 

A better approach is to shadow the state in your application. This is
what smartStateMgr does. When a node needs to set the state, it can
check the shadow state to see if it actually needs to set it or if
it's already set from the prior state settings. Going one step
further, resetting the state can be done lazily by adding dirty flags
into the shadow. The shadow *should* always mirror the GL
pipeline. When resetting state, there's no reason to actually reset
it, just mark the state as "should be set" or "should not be set".

Allowing lazy state evaluation plays a big role in improving state
management even further. The nodes to be rendered can be sorted to
group all like states together. Since we're only setting state when we 
need to, the GL pipeline is very happy. Sorting does not show much of
a speedup in this example because there's very little rendering
actually happening. In non-trivial applications, sorting can be a
large impact. 

In this example the state management code only handles color and some
minimal lighting parameters. These are not the most expensive
operations, especially color. Run some tests on your particular
system. I bet you'll be surprised at the cost of setting and resetting 
some state. Also, use some of the tracing tools to look at your
application to see if things are being set redundantly. Again, you may 
be surprised what your application is actually doing. 


The scenegraph is made up of a few C++ classes found in
scenegraph.{cxx,h}

  calSceneGraph: a base class for the scene graph

  calSceneMgr  : handles most high level scene graph operations. the
                 nodes are simply stored in an array, there is no
                 notion of a node hierarchy. the build() method
                 randomly generates nodes. this is where the C++ to
                 GLUT interaction is handled.

  calNode      : the base class for a node. holds a pointer to the
                 scenegraph. contains state information which is set
                 and reset on a render. the calSceneMgr::render()
                 calls the render() method of a calNode (actually of a 
                 concrete subclass of calNode). the render() method sets 
                 state, calls the renderNode() method of the subclass
                 to invoke the true render, and then resets state. 

  calCube      :
  calSphere    : two concrete subclasses of calNode. one renders a
                 glutCube, the other a glutSphere. these both
                 implement renderNode() with the GL for rendering.

  calNodeFactory: a simple factory to generate calCube or calSphere
                  calNodes. 

  calState     : a class to hold all the state that's used in the
                 scenegraph. it was convenient to package all the
                 state into one class. in real code this would be a
                 few different classes. 

  calStateMgr  : a base class for a state manager. provides pure
                 virtual setState() and restoreState()

  plainStateMgr: a state manager that might also be called
                 'naiveStateMgr'. it used glPushAttrib() and
                 glPopAttrib() to save state between calls and always
                 sets the state regardless of the prior state.

  fancyStateMgr: this is the start of a smarter state manager. this
                 mirrors the GL state to ensure that the same state is
                 not set multiple times. the node hierarchy is flat,
                 so there's no need to store a full state stack since
                 there will never be more than one set of state to
                 keep track of. this goes through the motions of
                 working with a state stack, but it's a stack of 1.
