Opengl not as portable as they say?Keyboard bug

Hey
I’ve recently came across a bug when there’s an animation on the screen and you press quickly multiple times shift and ctrl. The animation laggs. I suppose that this issue is connected somehow with sticky keys but its undoubtedly not fault of my computer. I’m using Windows XP. Here’s the sample code I’ve made for you to try this bug out (It doesn’t happen on all computers but on many does…):

#include <gl/glut.h>

void InitGL();
void Draw();
int ScrWidth = 800, ScrHeight = 450;
int Window = NULL;
int pos_x = 300;

int main(int argc, char **argv){

glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_ALPHA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(ScrWidth, ScrHeight);
glutInitWindowPosition(0, 0);
Window = glutCreateWindow("LF BY SAVAIL");

InitGL();
glutDisplayFunc(&Draw);
glutIdleFunc(&Draw);

glutMainLoop();
glutDestroyWindow(Window);
}

void InitGL(){
glViewport(0, 0, ScrWidth, ScrHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, ScrWidth, ScrHeight, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glShadeModel(GL_SMOOTH);

glClearColor(0, 0, 0, 0);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}

void Draw(){
glutSetWindow(Window);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glColor3f(1, 0.1, 0);
glBegin(GL_POLYGON);
glVertex3f(100, 100, 0);
glVertex3f(200, 200, 0);
glVertex3f(pos_x, 100, 0);
glEnd();
pos_x++;
glutSwapBuffers();
}

[push quickly shift and ctrl multiple times to cause the animation lagg]
Could I expect this bug to be repaired? I would be very grateful for any advise and reply

Is that the shortcuts to enable various accessibility features, hitting Shift/control multiple times on Windows XP ?

No, but they are called sticky keys from some reason: shift ctrl and alt also. But pressing shift+ctrl is not any shortcut. 5x Shift is a shortcut for a window with sticky keys functions but it pops up only when sticky keys function in windows is active. I have it disabled and the problem occurs.

I suppose that this issue is connected somehow with sticky keys but its undoubtedly not fault of my computer.

You’re right; it’s the fault of your code. You put your draw function in the idle callback. GLUT makes no guarantees as to how often this will be called. It makes no claims that it will be called consistently at specific intervals or not.

If you want smooth animation, you have to deal with actual timers and such. You can’t rely on the idle callback to always happen X times per second.

Could I expect this bug to be repaired?

It’s not a bug, so no.

Ok I suppose I’ve installed timers properly in my programm, but the bug still exists. I have commented all new lines with word “NEW”. I’m afraid that Opengl really doesn’t properly use sticky keys. Or maybe there is something more I could do to repair it?

#include <gl/glut.h>

void InitGL();
void Draw();
void PreDraw(int i); // NEW
int ScrWidth = 800, ScrHeight = 450;
int Window = NULL;
int pos_x = 300;

int main(int argc, char **argv){

glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_ALPHA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(ScrWidth, ScrHeight);
glutInitWindowPosition(0, 0);
Window = glutCreateWindow("LF BY SAVAIL");

InitGL();
glutDisplayFunc(&Draw);
glutTimerFunc(100, &PreDraw, 0); //NEW instead of glutIdleFunc

glutMainLoop();
glutDestroyWindow(Window);
}

void InitGL(){
glViewport(0, 0, ScrWidth, ScrHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, ScrWidth, ScrHeight, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glShadeModel(GL_SMOOTH);

glClearColor(0, 0, 0, 0);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}

void Draw(){
glutSetWindow(Window);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glColor3f(1, 0.1, 0);
glBegin(GL_POLYGON);
glVertex3f(100, 100, 0);
glVertex3f(200, 200, 0);
glVertex3f(pos_x, 100, 0);
glEnd();
pos_x++;
glutSwapBuffers();
}

void PreDraw(int i){ //NEW
glutIdleFunc(&Draw);
}

If that’s a real bug is that right place for reporting it or should I write somewhere else?

Ok I suppose I’ve installed timers properly in my programm, but the bug still exists.

No, the problem is still in your code.

First, your code is still using glutIdleFunc. You just call it a bit later. You probably meant to call glutTimerFunc in the PreDraw class, so that it would active a new timer.

More importantly, when I said “timers,” I didn’t mean using the glutTimerFunc. I meant keeping track of the time in your own code. That is, asking how much time elapsed between one rendering of the scene and the previous one. Then using that elapsed time to compute how much to move the object.

glutTimerFunc only guarantees that the function will be called at least every X milliseconds. It could wait much longer between calls, and it would still be doing the right thing. If you want smooth animation in GLUT, you need to write the proper code for it.

If you want to know what the proper code should look like, you can read this.

I’m afraid that Opengl really doesn’t properly use sticky keys.

GLUT is not OpenGL. GLUT is a cross-platform library for basic OpenGL window creation and management. OpenGL is a rendering library; it doesn’t know anything about keys, sticky or otherwise.

You also never said what version of GLUT you are using.

Thanks for answers and ur time.
But why shift + ctrl pressed quickly multiple times causes laggs in animation? It’s certainly not fault of my code? I’ll try to prepare the same programm with timer that you have mentioned and put it as soon as possible.

But why shift + ctrl pressed quickly multiple times causes laggs in animation?

Because GLUT makes no guarantees about timing. That means that 100 milliseconds can pass between function calls, or 150, or 50304 milliseconds. It could take longer because you’re pressing shift+ctrl, or because your computer has a lot of threads running, or because there’s a full moon.

The point is that your code is written based on certain assumptions about the system (namely, that it will call your rendering function at regular intervals), but the system does not provide those guarantees. The shift+ctrl thing is simply one way you have found that repeatably causes the system to behave in a way that your code doesn’t expect.

emm I can’t run some functions in the tutorial you gave me like glBindBuffer or glUseProgram. I have downloaded latest version of glut here

http://www.xmission.com/~nate/glut.html

but still can’t run these functions.

emm I can’t run some functions in the tutorial you gave me like glBindBuffer or glUseProgram.

You didn’t download and properly build the source distribution; blindly copying and pasting code from the website won’t get you anywhere without the actual source distribution. If you want to see how the whole program runs, you will need to do that.

The code of interest was the code that dealt with timing, not the actual rendering code. You have to use the timing code and adapt it for your needs.

Keep in mind that GLUT is very old. Some features may not behave as originally intended on newer OSes, especially Windows Vista and up. Consider FreeGLUT as alternative, it is mostly identical in use: http://freeglut.sourceforge.net/

I don’t quiet understand, have some difficulties with english tutorials. Did you mean that I shouldn’t use glutIdleFunc in my program? And the code that I need is the first example: Example 3.1. Computation of Position Offsets, right?
Remdul, Thanks I didn’t know about it, Im going to use Freeglut soon then.

glutIdleFunc is what your program does when it’s not doing anything else. The documentation does say that you really shouldn’t do much rendering (or much work at all) in it.

In your case, you’re pressing lots of keys together so your program is busy reading those key messages, deciding what to do with them, it might be passing them on to Windows for more work. It’s busy though, so it doesn’t call glutIdleFunc because it’s doing something else.

In fact it’s doubly-bad because the fact that you’ve set a “do this when I’m not doing anything else” function means that your scene gets drawn twice. Once as part of the normal display and again when your program is not doing anything else.

glutDisplayFunc is the one to use for drawing. This tells GLUT that “when it’s time to draw, call this function”. I see that you’re already setting it in your main, and that’s all you need to do.

So all you need to do is delete your glutIdleFunc and PreDraw stuff and you should be good.

Did you mean that I shouldn’t use glutIdleFunc in my program?

Yes. You shouldn’t use the idle function for animation purposes.

And the code that I need is the first example: Example 3.1. Computation of Position Offsets, right?

No. The code is described in the link provided. You should not be looking for code to copy into yours that will make everything work. You should be reading the explanation of how that work, so that you can adapt it to your particular program.

For example, the line, “The function glutGet(GLUT_ELAPSED_TIME) retrieves the integer time in milliseconds since the application started.” Consider the implications of a function that returns the time. And consider how the return value is used by the code in question (as explained in the text).

All animation is based on answering the question, “What do I want to have happen in the next X seconds?” The link I gave you computes a cyclical offset based on how much time has elapsed since the start of the program.

Sorry I weren’t able to wirte my own code becouse I will have lots of exams in this week and I won’t be able to spend a lot of time during the week… Therefore I would like to know clearly if its bug before the weekend ends and so I found a tutorial with prepared code that rotates a triangle with timers as you mentioned Alfonse. I suppose this code is fine and does the work it should be doing, but the bug still remains:

#include <GL/glut.h>

#define WIDTH 640
#define HEIGHT 480

#define TIMERMSECS 33

#define ROTRATE 45.0f

int startTime;
int prevTime;

static GLfloat rot = 0.0f;

static void init(int w, int h);
static void reshape(GLsizei w, GLsizei h);
static void animate(int value);
static void render();
static void key(unsigned char k, int x, int y);



int main(int argc, char** argv)
{
    glutInit(&argc, argv);
	glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize (WIDTH, HEIGHT);
    glutCreateWindow (argv[0]);

	init(WIDTH, HEIGHT);
	glutDisplayFunc(render);
	glutKeyboardFunc(key);
    glutReshapeFunc(reshape);
	glutPostRedisplay();

    glutTimerFunc(TIMERMSECS, animate, 0);

	startTime = glutGet(GLUT_ELAPSED_TIME);
	prevTime = startTime;

    glutMainLoop();

    return 0;
}

static void init(int w, int h)
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
	reshape(w, h);

	glEnable(GL_DEPTH_TEST);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}

static void animate(int value)
{
    glutTimerFunc(TIMERMSECS, animate, 0);

	int currTime = glutGet(GLUT_ELAPSED_TIME);
	int timeSincePrevFrame = currTime - prevTime;
	int elapsedTime = currTime - startTime;

	rot = (ROTRATE / 1000) * elapsedTime;	

	glutPostRedisplay();
	prevTime = currTime;
}

static void render()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glLoadIdentity();
	glTranslatef(0.0f,0.0f,-3.0f);
	glRotatef(rot, 0.0, 0.0, 1.0);

	glBegin(GL_TRIANGLES);
	glColor3f(1.0, 0.0, 0.0);
	glVertex3f(-1.0, -1.0, 0.0);
	glColor3f(0.0, 1.0, 0.0);
	glVertex3f(1.0, -1.0, 0.0);
	glColor3f(0.0, 0.0, 1.0);
	glVertex3f(0.0, 1.0, 0.0);
	glEnd();

    glutSwapBuffers();
    glFlush();
}

When I push shift and ctrl quickly multiple times the animation laggs no matter if time is controlled by my programm or not.
Earlier I had been using SDL with Opengl to create my first game. When I found this bug I thought its fault of this mix(SDL/OPENGL) but it turns out that its Opengl’s fault. In pure SDL even without timers animation doesn’t lagg to me when I try that bug.
Or maybe this code is still wrong?
Note that shift and ctrl have no functions in this program…

This is going to come to you roughly: the issue you have has NOTHING to do with OpenGL, it comes purely from using GLUT incorrectly, or from before SDL. Plenty of code is out there using SDL and GL together for animations, including games…there are even a few (very few) open source games that use freeglut… At any rate I strongly advise for you to sit down and learn how to correctly assemble an event loop with drawing in SDL… It is not hard it is quite easy…

kRogue this code above is not made by me, every tutorial code I run has the bug that I’ve mentioned, every game written in Opengl I download has this bug for me. Does this mean that no one knows how to use Glut? Even those who make tutorials? Find me a code that you think works properly and I’ll check if it has bug also or not becouse I really can’t find any.

GLUT is perfectly good for simple programs. That’s all it’s meant for. Techdemos. Tutorials. Showing you how to do something without distracting you by using the Windows API or GLX or whatever. If you try to use it outside of it’s intended purpose you can expect problems.

This is not a bug in GLUT. GLUT is doing what it’s doing because you told it to. In your code.

Anybody can contrive a use case that breaks something and then claim that the something has a bug. That’s exactly what you’ve just done. It’s like trying to multiply 2,147,483,642 by 2 and claiming that your CPU has a bug. It doesn’t have a bug - it’s the way things work.

I see that you’ve left out your “key” function in your most recent code. How did it ever compile? Please post your full code before looking for it to be corrected.

aww ye I missed some part of code. Here’s the full version and its not my code, its from here: here(both examples there have bugs for me)

#include <GL/glut.h>

#define WIDTH 640
#define HEIGHT 480

#define TIMERMSECS 33

#define ROTRATE 45.0f

int startTime;
int prevTime;

static GLfloat rot = 0.0f;

static void init(int w, int h);
static void reshape(GLsizei w, GLsizei h);
static void animate(int value);
static void render();
static void key(unsigned char k, int x, int y);

int main(int argc, char** argv)
{
    glutInit(&argc, argv);

	glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize (WIDTH, HEIGHT);
    glutCreateWindow (argv[0]);

	init(WIDTH, HEIGHT);
	glutDisplayFunc(render);
	glutKeyboardFunc(key);
    glutReshapeFunc(reshape);
	glutPostRedisplay();

    glutTimerFunc(TIMERMSECS, animate, 0);

	startTime = glutGet(GLUT_ELAPSED_TIME);
	prevTime = startTime;

    glutMainLoop();

    return 0;
}

static void init(int w, int h)
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
	reshape(w, h);

	glEnable(GL_DEPTH_TEST);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}

static void reshape(GLsizei w, GLsizei h)
{

    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

	gluPerspective(45.0f,(GLfloat)w/(GLfloat)h,0.1f,100.0f);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

}

static void animate(int value)
{
    glutTimerFunc(TIMERMSECS, animate, 0);

	int currTime = glutGet(GLUT_ELAPSED_TIME);
	int timeSincePrevFrame = currTime - prevTime;
	int elapsedTime = currTime - startTime;

	rot = (ROTRATE / 1000) * elapsedTime;
	glutPostRedisplay();

	prevTime = currTime;
}

static void render()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glLoadIdentity();
	glTranslatef(0.0f,0.0f,-3.0f);
	glRotatef(rot, 0.0, 0.0, 1.0);

	glBegin(GL_TRIANGLES);
	glColor3f(1.0, 0.0, 0.0);
	glVertex3f(-1.0, -1.0, 0.0);
	glColor3f(0.0, 1.0, 0.0);
	glVertex3f(1.0, -1.0, 0.0);
	glColor3f(0.0, 0.0, 1.0);
	glVertex3f(0.0, 1.0, 0.0);
	glEnd();

    glutSwapBuffers();
    glFlush();
}

static void key(unsigned char k, int x, int y)
{
	switch (k) {
	case 27:
		exit(0);
		break;

	default:
		return;
	}

	glutPostRedisplay();
}

It’s the glutPostRedisplay in the key function this time. What this means is that every time a key is hit the screen is redrawn. Maybe that was required by the original code, I don’t know, but it doesn’t sound like good practice to me. Better to take a log of keystrokes and deal with them in the idlefunc. And by “deal with them” I mean just update any parameters they should change, not redraw the screen! The standard display func will handle that just fine.