How Expensive are redundant State Changes?

Macros are prone to bugs, as far as I’m concerned. Inline functions and const variables have made #define mostly obsolete, as far as I’m concerned.

But do whatever makes you happy.

  • Matt

Fair enough. Time to spend a couple of hours wrapping GL - that little portion of it which I use.

If one retains the semantics and types of the original gl* calls, I can’t see using a wrapper could be any more error prone, since it would be practically transparent to the renderer (which is in itself wrapping gl at a higher level).

– Henry

What about state objects? I’d see those as some sort of specialized display lists for setting the rendering state. I’ve read something about that in some ARB meeting notes (by the way, why aren’t the latest notes released?). I think there’s a similar notion in DirectX but I don’t know if it really is useful, especially at driver level.

By the way, I do state caching on the application side and it definitely speeds up things. Not as much on a GeForce (about 4~5% on my test scene) as on a FireGL 1000 (around 30%) but it’s still worth it.

Any answer to this question?

Is it the same (in terms of rendering performance) glDisable(GL_BLEND) that glBlendFunc(GL_ONE, GL_ZERO)?
If blending is enabled the card is always reading the framebuffer when rendering or it depends on the BlendFunc selected?

Thanks

Well, I think I have misexplained me, but you aswered me anyway, Matt. I asked wether that inline would do the same as a #define. That isn’t described in my c reference.

PLEASE just disable blending.

We absolutely detest apps that think that it’s just as good to set a feature to a mode where it is “essentially” off rather than just disabling it.

That goes for blending (ONE, ZERO), line and polygon stipple (0xFFFF and 32 0xFFFFFFFF’s), logic op (COPY), etc.

  • Matt

Thank you, Matt.

interesting discussion. thank you, mcraighead, for giving me a good explanation of why it’s so expensive to call OGL functions. never thought about all that
this might be slightly offtopic, but anyway… don’t forget glPushAttrib and glPopAttrib.
it can be very useful sometimes. i used it in a general overlay class in Java a few months ago. since the class didn’t know of any states, it would have been very inefficient (and ugly) to check for them. this is what i did instead:
glPushAttrib(GL_ENABLE_BIT); /* since we don’t want lighting, z-buffering, stencil-buffering etc. to be enabled /
glEnable(GL_TEXTURE_2D); /
we do want texturing /
glEnable(GL_BLEND); /
and blending… */
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
… draw the objects in this overlay
glPopAttrib();

actually, i’m also wondering if this could be done better?

PushAttrib and PopAttrib? Blech, no. If you care about performance, don’t use them at all, ever.

If all you need to save and restore is one enable, use IsEnabled (even though I strongly discourage the use of IsEnabled in general).

Better would be to cache the enable state on your side in the app, just like those wrappers do, so IsEnabled isn’t necessary.

Better still would be to design your app so you don’t need to save and restore state like that.

One of the biggest problems with OpenGL is that it makes it very easy to write braindead apps that use features that turn out to be really hard to implement in an efficient way. PushAttrib/PopAttrib is one example of this – I wish they would just go away. Another example is immediate mode; I consider immediate mode to be a rather poor API design choice.

  • Matt

from an old Red Book… appendix H
under OpenGL Performance Tips
“Use glPushAttrib() and glPopAttrib() to save and restore state values. Use query functions only when your application requires the state values for its own computations.”
ouch. dunno if it’s still there. or maybe i misunderstood. sigh gotta rewrite that class, hehe =)
it’s really hard to know what functions one should use and which ones to stay away from. perhaps NV could put up a “slow functions list” or something? it could be useful.

and regarding immediate mode… i think it should die die die. it is useful for total newbies since it is easy to understand, but for anything more complicated than drawing a quad, vertex arrays should be used. using glVertex* instead of arrays are probably the most common mistake among new GL programmers.

That’s bad advice. On most implementations, PushAttrib and PopAttrib are SLOW.

  • Matt

>perhaps NV could put up a “slow functions list” or something? it could be useful.

… for things like this.

Incidentally, I just finished writing a little wrapper for gl (20mins coding, not as long as I thought) that caches state on the application side. With a few test runs, I saw about 70% redundancy in the state setting I was doing. I haven’t seen much of a speed up (because my app. is fill rate limited), but it makes me feel happier. The only annoying thing was putting all the multitexture state in. (Multitexture annoys me anyway, since my shader system is sufficiently general that it’s normally pretty unlikely two succesive stages can be collapsed into a single multitexture stage. Things like different alpha testing for each stage, and wanting to use the fragment colour at each stage put paid to this. Sigh)
Anyway, once that was done, it was really trivial to do.

Henry

HenryR:
I did the state wrapper too, also got 70%+ redundancy, and still got almost no performance increase in some tests because they where geometry-limited (150k+ vertices per frame), yet it increased a little bit more in scenes where I have a bunch of different objects and materials/textures.

Writing an OpenGL wrapper seems to be something like reinventing the wheel, i.e. most developers have to do this. Couldn’t this be done once and for all?

Likewise, I’d like to see a C++ wrapper that uses overloading instead of having different function names and doing things a bit smarter and more cleanly (I.e. no void-pointers and setting the type by defined varlues, etc). Also, enums should be used, as to get type safety and not plugging the wrong kind of value into a function.

While we are at it, why not skip the gl-prefix and put it all into a namespace?

I’m about to write all this myself soon, but I really think it’s something that should be offered or done already. (As an extension of course, I suspect there’s plenty of people still writing in pure-C.)

Anyway, if I get around to it, it’ll be publically available, but I feel that this is something that suits the open source principle perfectly.

Uh… got a bit off topic there, perhaps this should be put in a separate thread?

Anyway, any opinions?

I’ve used Magician (a Java OpenGL wrapper), and indeed it’s a little nicer to get rid of the suffixes. It didn’t handle state changes, though.

Maybe you could make it a little more object oriented, and call it Direct3D?

Leaving blending enabled is usually a bad idea because it may force some hardware to fetch frame buffer data.

I have implemented such a state manager and I am willing to make it available to anyone. I am posting the source code including a test program here but … Email me at Paul_H_Leopard@hotmail.com and I will send you the original project including the source code (with formatting).

// OpenGLStateManager.h

#ifndef OPENGLSTATEMANAGER_INCLUDED
#define OPENGLSTATEMANAGER_INCLUDED

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Description:
//
// Used to shadow the current OpenGL state to reduce the performance
// penalties associated with OpenGL state queries and push/pop operations.
//
// Author: Paul H. Leopard, Paul_H_Leopard@Hotmail.com
//
//-------0---------0---------0---------0---------0---------0---------0---------0

// …
// This class declaration requires knowledge of other class interfaces and/or
// declarations contained in the following header files:

// C++ Standard Library includes

#include <map>

// Win32 and OpenGL includes

#ifdef WIN32
#include <windows.h>
#endif
#include <GL/gl.h>

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/** Used to shadow the current OpenGL state to reduce the performance
penalties associated with OpenGL state queries and push/pop operations.
@author Paul H. Leopard - Paul_H_Leopard@Hotmail.com
*/
class OpenGLStateManager
{

// ____________________________________________________________________________
// Public methods.

public:

// ____________________________________________________________________________
// …
// Lifecycle methods

/** Constructor.
*/
OpenGLStateManager();

// …
// Accessor methods

/** Determine if a given state is enabled.
@param glStateId The OpenGL state to test.
@return true if the state is enabled, false otherwise.
*/
bool isEnabled(int glStateId) const;

/** Retrieve the active OpenGL matrix (GL_MODELVIEW_MATRIX,
GL_PROJECTION_MATRIX, or GL_TEXTURE_MATRIX).
@return The active OpenGL matrix (GL_MODELVIEW_MATRIX,
GL_PROJECTION_MATRIX, or GL_TEXTURE_MATRIX).
*/
int activeMatrix() const;

// …
// Manipulator methods

/** Enable or disable a given state.
@param glStateId The OpenGL state to test.
@param state true to enable the state, false to disable the state.
*/
void enable(int glStateId, bool state);

/** Enable a given state.
@invariant Invalid OpenGL state requested.
*/
void enable(int glStateId);

/** Disable a given state.
@param glStateId The OpenGL state to test.
*/
void disable(int glStateId);

/** Toggle a given state.
@param glStateId The OpenGL state to toggle.
*/
void toggleState(int glStateId);

/** Synchronize this instance with the current OpenGL state.
*/
void glSynchronize();

/** Set the active OpenGL matrix.
@param matrix The desired OpenGL matrix (GL_MODELVIEW_MATRIX,
GL_PROJECTION_MATRIX, or GL_TEXTURE_MATRIX).
*/
void setActiveMatrix(int matrix);

// …
// Operators

// ____________________________________________________________________________
// Private properties.

private:

	/// Shadow of the OpenGL enabled states
	mutable std::map&lt;int,bool&gt; m_EnableMap;

	/// Lazy initialization indicator.
	mutable bool m_Initialized;

	/// Currently active OpenGL matrix.
	mutable int m_CurrentMatrix;

}; // class OpenGLStateManager

// ____________________________________________________________________________
// Inlined methods.

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Enable a given state.

inline void OpenGLStateManager::enable(int glStateId)
{
enable(glStateId,true);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Disable a given state.

inline void OpenGLStateManager::disable(int glStateId)
{
enable(glStateId,false);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Toggle a given state.

inline void OpenGLStateManager::toggleState(int glStateId)
{
if (isEnabled(glStateId))
{
disable(glStateId);
}
else
{
enable(glStateId);
}
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Retrieve the active OpenGL matrix (GL_MODELVIEW_MATRIX,
// GL_PROJECTION_MATRIX, or GL_TEXTURE_MATRIX).

inline int OpenGLStateManager::activeMatrix() const
{
return m_CurrentMatrix;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Retrieve the active OpenGL matrix (GL_MODELVIEW_MATRIX,
// GL_PROJECTION_MATRIX, or GL_TEXTURE_MATRIX).

inline void OpenGLStateManager::setActiveMatrix(int matrix)
{
if (m_CurrentMatrix!=matrix)
{
glMatrixMode(matrix);
m_CurrentMatrix = matrix;
}
}

#endif // OPENGLSTATEMANAGER_INCLUDED

// EOF: OpenGLStateManager.h

// OpenGLStateManager.cpp

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Description:
//
// Used to shadow the current OpenGL state to reduce the performance
// penalties associated with OpenGL state queries and push/pop operations.
//
// Author: Paul H. Leopard, Paul_H_Leopard@Hotmail.com
//
//-------0---------0---------0---------0---------0---------0---------0---------0

// ==================================================================== Includes

// C++ Standard Library includes includes

#include <string>

// Local includes

#include “OpenGLStateManager.h”

// ============================================================= End of includes

// Imply namespaces

using namespace std;

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constructor.

OpenGLStateManager::OpenGLStateManager()
: m_Initialized(false),
m_CurrentMatrix(GL_MODELVIEW_MATRIX)
{
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Enable or disable a given state.

void OpenGLStateManager::enable(int glStateId, bool state)
{
if (!m_Initialized)
{
glSynchronize();
m_Initialized = true;
}

if (state!=m_EnableMap[glStateId])
{
	m_EnableMap[glStateId] = state;
	if (state)
	{
		glEnable(glStateId);
	}
	else
	{
		glDisable(glStateId);
	}
}

}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Determine if a given state is enabled.

bool OpenGLStateManager::isEnabled(int glStateId) const
{
bool ret(false);

map&lt;int,bool&gt;::iterator it = m_EnableMap.find(glStateId);
if (it==m_EnableMap.end())
{
	int state = glIsEnabled(glStateId);
	if (state==GL_TRUE)
	{
		ret = m_EnableMap[glStateId] = true;
	}
	else if (state==GL_FALSE)
	{
		ret = m_EnableMap[glStateId] = false;
	}
	else
	{
		throw string("Attempted to query OpenGL for an unknown state");
	}
}
else
{
	ret = (*it).second;
}

return ret;

}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Synchronize this instance with the current OpenGL state.

void OpenGLStateManager::glSynchronize()
{
// Synch the current matrix.
glGetIntegerv(GL_MATRIX_MODE,&m_CurrentMatrix);

// Synch the enable/disable states
m_EnableMap[GL_FOG] = (glIsEnabled(GL_FOG))?true:false;
m_EnableMap[GL_LIGHTING] = (glIsEnabled(GL_LIGHTING))?true:false;
m_EnableMap[GL_TEXTURE_1D] = (glIsEnabled(GL_TEXTURE_1D))?true:false;
m_EnableMap[GL_TEXTURE_2D] = (glIsEnabled(GL_TEXTURE_2D))?true:false;
m_EnableMap[GL_LINE_STIPPLE] = (glIsEnabled(GL_LINE_STIPPLE))?true:false;
m_EnableMap[GL_POLYGON_STIPPLE] = (glIsEnabled(GL_POLYGON_STIPPLE))?true:false;
m_EnableMap[GL_CULL_FACE] = (glIsEnabled(GL_CULL_FACE))?true:false;
m_EnableMap[GL_ALPHA_TEST] = (glIsEnabled(GL_ALPHA_TEST))?true:false;
m_EnableMap[GL_BLEND] = (glIsEnabled(GL_BLEND))?true:false;
m_EnableMap[GL_INDEX_LOGIC_OP] = (glIsEnabled(GL_INDEX_LOGIC_OP))?true:false;
m_EnableMap[GL_COLOR_LOGIC_OP] = (glIsEnabled(GL_COLOR_LOGIC_OP))?true:false;
m_EnableMap[GL_DITHER] = (glIsEnabled(GL_DITHER))?true:false;
m_EnableMap[GL_STENCIL_TEST] = (glIsEnabled(GL_STENCIL_TEST))?true:false;
m_EnableMap[GL_DEPTH_TEST] = (glIsEnabled(GL_DEPTH_TEST))?true:false;
m_EnableMap[GL_CLIP_PLANE0] = (glIsEnabled(GL_CLIP_PLANE0))?true:false;
m_EnableMap[GL_CLIP_PLANE1] = (glIsEnabled(GL_CLIP_PLANE1))?true:false;
m_EnableMap[GL_CLIP_PLANE2] = (glIsEnabled(GL_CLIP_PLANE2))?true:false;
m_EnableMap[GL_CLIP_PLANE3] = (glIsEnabled(GL_CLIP_PLANE3))?true:false;
m_EnableMap[GL_CLIP_PLANE4] = (glIsEnabled(GL_CLIP_PLANE4))?true:false;
m_EnableMap[GL_CLIP_PLANE5] = (glIsEnabled(GL_CLIP_PLANE5))?true:false;
m_EnableMap[GL_LIGHT0] = (glIsEnabled(GL_LIGHT0))?true:false;
m_EnableMap[GL_LIGHT1] = (glIsEnabled(GL_LIGHT1))?true:false;
m_EnableMap[GL_LIGHT2] = (glIsEnabled(GL_LIGHT2))?true:false;
m_EnableMap[GL_LIGHT3] = (glIsEnabled(GL_LIGHT3))?true:false;
m_EnableMap[GL_LIGHT4] = (glIsEnabled(GL_LIGHT4))?true:false;
m_EnableMap[GL_LIGHT5] = (glIsEnabled(GL_LIGHT5))?true:false;
m_EnableMap[GL_LIGHT6] = (glIsEnabled(GL_LIGHT6))?true:false;
m_EnableMap[GL_LIGHT7] = (glIsEnabled(GL_LIGHT7))?true:false;
m_EnableMap[GL_TEXTURE_GEN_S] = (glIsEnabled(GL_TEXTURE_GEN_S))?true:false;
m_EnableMap[GL_TEXTURE_GEN_T] = (glIsEnabled(GL_TEXTURE_GEN_T))?true:false;
m_EnableMap[GL_TEXTURE_GEN_R] = (glIsEnabled(GL_TEXTURE_GEN_R))?true:false;
m_EnableMap[GL_TEXTURE_GEN_Q] = (glIsEnabled(GL_TEXTURE_GEN_Q))?true:false;
m_EnableMap[GL_MAP1_VERTEX_3] = (glIsEnabled(GL_MAP1_VERTEX_3))?true:false;
m_EnableMap[GL_MAP1_VERTEX_4] = (glIsEnabled(GL_MAP1_VERTEX_4))?true:false;
m_EnableMap[GL_MAP1_COLOR_4] = (glIsEnabled(GL_MAP1_COLOR_4))?true:false;
m_EnableMap[GL_MAP1_INDEX] = (glIsEnabled(GL_MAP1_INDEX))?true:false;
m_EnableMap[GL_MAP1_NORMAL] = (glIsEnabled(GL_MAP1_NORMAL))?true:false;
m_EnableMap[GL_MAP1_TEXTURE_COORD_1] = (glIsEnabled(GL_MAP1_TEXTURE_COORD_1))?true:false;
m_EnableMap[GL_MAP1_TEXTURE_COORD_2] = (glIsEnabled(GL_MAP1_TEXTURE_COORD_2))?true:false;
m_EnableMap[GL_MAP1_TEXTURE_COORD_3] = (glIsEnabled(GL_MAP1_TEXTURE_COORD_3))?true:false;
m_EnableMap[GL_MAP1_TEXTURE_COORD_4] = (glIsEnabled(GL_MAP1_TEXTURE_COORD_4))?true:false;
m_EnableMap[GL_MAP2_VERTEX_3] = (glIsEnabled(GL_MAP2_VERTEX_3))?true:false;
m_EnableMap[GL_MAP2_VERTEX_4] = (glIsEnabled(GL_MAP2_VERTEX_4))?true:false;
m_EnableMap[GL_MAP2_COLOR_4] = (glIsEnabled(GL_MAP2_COLOR_4))?true:false;
m_EnableMap[GL_MAP2_INDEX] = (glIsEnabled(GL_MAP2_INDEX))?true:false;
m_EnableMap[GL_MAP2_NORMAL] = (glIsEnabled(GL_MAP2_NORMAL))?true:false;
m_EnableMap[GL_MAP2_TEXTURE_COORD_1] = (glIsEnabled(GL_MAP2_TEXTURE_COORD_1))?true:false;
m_EnableMap[GL_MAP2_TEXTURE_COORD_2] = (glIsEnabled(GL_MAP2_TEXTURE_COORD_2))?true:false;
m_EnableMap[GL_MAP2_TEXTURE_COORD_3] = (glIsEnabled(GL_MAP2_TEXTURE_COORD_3))?true:false;
m_EnableMap[GL_MAP2_TEXTURE_COORD_4] = (glIsEnabled(GL_MAP2_TEXTURE_COORD_4))?true:false;
m_EnableMap[GL_POINT_SMOOTH] = (glIsEnabled(GL_POINT_SMOOTH))?true:false;
m_EnableMap[GL_LINE_SMOOTH] = (glIsEnabled(GL_LINE_SMOOTH))?true:false;
m_EnableMap[GL_POLYGON_SMOOTH] = (glIsEnabled(GL_POLYGON_SMOOTH))?true:false;
m_EnableMap[GL_SCISSOR_TEST] = (glIsEnabled(GL_SCISSOR_TEST))?true:false;
m_EnableMap[GL_COLOR_MATERIAL] = (glIsEnabled(GL_COLOR_MATERIAL))?true:false;
m_EnableMap[GL_NORMALIZE] = (glIsEnabled(GL_NORMALIZE))?true:false;
m_EnableMap[GL_AUTO_NORMAL] = (glIsEnabled(GL_AUTO_NORMAL))?true:false;
m_EnableMap[GL_VERTEX_ARRAY] = (glIsEnabled(GL_VERTEX_ARRAY))?true:false;
m_EnableMap[GL_NORMAL_ARRAY] = (glIsEnabled(GL_NORMAL_ARRAY))?true:false;
m_EnableMap[GL_COLOR_ARRAY] = (glIsEnabled(GL_COLOR_ARRAY))?true:false;
m_EnableMap[GL_INDEX_ARRAY] = (glIsEnabled(GL_INDEX_ARRAY))?true:false;
m_EnableMap[GL_TEXTURE_COORD_ARRAY] = (glIsEnabled(GL_TEXTURE_COORD_ARRAY))?true:false;
m_EnableMap[GL_EDGE_FLAG_ARRAY] = (glIsEnabled(GL_EDGE_FLAG_ARRAY))?true:false;
m_EnableMap[GL_POLYGON_OFFSET_POINT] = (glIsEnabled(GL_POLYGON_OFFSET_POINT))?true:false;
m_EnableMap[GL_POLYGON_OFFSET_LINE] = (glIsEnabled(GL_POLYGON_OFFSET_LINE))?true:false;
m_EnableMap[GL_POLYGON_OFFSET_FILL] = (glIsEnabled(GL_POLYGON_OFFSET_FILL))?true:false;

}

// EOF: OpenGLStateManager.cpp

// main.cpp

#include <GL/glut.h>
#include <cstdio>
#include <cmath>
#include <iostream>

using namespace std;

#include “OpenGLStateManager.h”

OpenGLStateManager StateMgr;

GLfloat ambientLight[] = { 0.1f, 0.1f, 0.1f, 1.0f };
GLfloat diffuseLight[] = { .5f, 0.5f, 0.5f, 1.0f };
GLfloat specular[] = { 1.0f, 1.0f, 1.0f, 1.0f};
GLfloat lightPos[] = { .0f, .0f, 1.8f, 1.0f };
GLfloat specref[] = { 1.0f, 1.0f, 1.0f, 1.0f };

void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glutSolidIcosahedron();
glutSwapBuffers();
}

void idle()
{
glutPostRedisplay();
}

void visible(int vis)
{
if (vis == GLUT_VISIBLE)
{
glutIdleFunc(idle);
}
else
{
glutIdleFunc(NULL);
}
}

void Key(unsigned char key, int x, int y)
{
switch (key)
{
case 27: //ESC key exits
exit(0);
break;

	case 'a':				// 'a' key rotates
		glRotatef(3.0,0.0,0.0,1.0);
		glRotatef(3.0,1.0,0.0,0.0);
	break;

	case 'l':
		StateMgr.toggleState(GL_LIGHTING);
	break;

	case 'c':
		StateMgr.toggleState(GL_CULL_FACE);
	break;

}

}

int main(int argc, char **argv)
{
glutInitWindowSize(512,512);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutCreateWindow(“Glut Keyboard”);
glutKeyboardFunc(Key);
glutDisplayFunc(display);
glutVisibilityFunc(visible);

cerr &lt;&lt; "Commands :

";
cerr << " a - Rotate angle
";
cerr << " l - Toggle lighting
";
cerr << " d - Toggle depth test
";
cerr << " c - Toggle culling
";
cerr << " m - Toggle color materials
";

StateMgr.glSynchronize();
StateMgr.enable(GL_DEPTH_TEST);
StateMgr.enable(GL_CULL_FACE);
StateMgr.enable(GL_LIGHTING);
StateMgr.enable(GL_COLOR_MATERIAL);

glFrontFace(GL_CCW);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f );

// Light 0
glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLight);
glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLight);
glLightfv(GL_LIGHT0,GL_SPECULAR,specular);
glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
glEnable(GL_LIGHT0);

// Material properties
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);  //this is default
glColor3f(1.0f, .3f, .7f);

// Specular, Shiny
glMaterialfv(GL_FRONT, GL_SPECULAR,specref);
glMateriali(GL_FRONT,GL_SHININESS,128);

glutMainLoop();
return 0;             

}

[This message has been edited by pleopard (edited 05-24-2001).]

I s’pose I don’t need to mention this, but don’t forget to resynchronize after you call a display list, unless you know it doesn’t change state…

Got bit by that a few times.

So Matt, would it be of value for me to add shadowing to the above class for colors (as in glColor3fv())?

Rephrased : Does glColor3fv() and its related functions suffer from the same performance problem? Would it help to shadow the current color?