glutMainLoop() not looping?

If I call glutMainLoop() at the end of main, it runs through my function called "display" once and then does absolutely nothing. In order for anything to happen so far, I have just had to put for(;;){} around all the code inside of display, this works. But now I need to add keyboard inputs, and I cant get it to work.

I have seen others have been confused with glutMainLoop, but no-one will explain it in a way that a beginner can understand. Should I be using glut keyboard functions? I can not seem to get these to work, all I want is something that will return the value of the character entered, including special characters, and ultimately need to do the same for joysticks.
You need to register callbacks that will be called when a particular event occurs, like a key being hit, the window being moved, the mouse moved, etc.

If you are using freeglut, look here:
http://freeglut.sourceforge.net/docs/api.php#WindowCallback

If you are using GLUT, look here:
https://www.opengl.org/documentation/specs/glut/spec3/node14.html

That documentation will tell you what parameters need to be accepted by your functions.

I use freeglut in my OpenGL applications, it gives the programmer more freedom over control of the application.

If you show the code you have, we could help you more and try to help you get your code working.
You don't have to. Using GLUT is fine.

freeglut isn't really a wrapper for the whole library. It's just an alternative to GLUT. You'll still use the rest of OpenGL just like you would without it.

GLUT is outdated. As far as I can see, the most recent update was 15 years ago, in 2000. The most recent release of freeglut is March 2015 (release cycles for freeglut is long) GLUT is no longer maintained, and it's license is restrictive.
I am using freeglut. Out of interest, is freeglut likely to become obsolete any time soon?

OK, I will share the code below. No one else as looked over it yet, I am not sure whether it will be of any use

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
///TODO: add comments

#include <GL/glut.h>

#include <SDL.h>

#include <SDL_keysym.h>

#include <SDL/SDL.h>

#include <iostream>

#include <string.h>

#include <cstdlib>

#include <math.h>

#include <unistd.h>

#include <stdio.h>

#include <ctype.h>

#include "kbhit.h" /* http://linux-sxs.org/programming/kbhit.html */

#include <termios.h>

#include <unistd.h>   // for read()

#define PI 3.141519265368979323846264338327950288

#include <wiringPi.h>


#define deg 180 * PI

#define CLOCKS_PER_SEC 1000000

using namespace std;

//SDL_Event event;

double m = 0;

double ti = 0;

double two = 0;

double d = 0;

//#include <conio>
double x = 0;
double y = 0;
double z = -5;

double YAW = 0;
double PITCH = 0;
double ROLL = 0;

int64_t program_count = 0;
int iter_c = 0;
int rep_count = 0;

double overtime = 0;

double fps = 10;

std::string t = "p";

void display() { ///everything looped happens in here

  for(;;){

    glClear(GL_COLOR_BUFFER_BIT);

    glColor3f(1.0, 1.0, 0.0);
    glutWireTorus(0.5, 3, 10, 10);
    glTranslated(1,0,0);
    glutWireTorus(0.5, 3, 10, 10);
    glTranslated(0,1,0);
    glutWireTorus(0.5, 3, 10, 10);
    glTranslated(1,0,0);
    glutWireTorus(0.5, 3, 10, 10);
    glTranslated(0,1,0);
    glutWireTorus(0.5, 3, 10, 10);
    glTranslated(1,0,0);

    glColor3f(1.0, 0.0, 0.0);

    glBegin(GL_LINES);
    glColor3f(1, 0, 0); glVertex3f(0, 0, 0); glVertex3f(10, 0, 0); //axis
    glColor3f(0, 1, 0); glVertex3f(0, 0, 0); glVertex3f(0, 10, 0); //axis
    glColor3f(0, 0, 1); glVertex3f(0, 0, 0); glVertex3f(0, 0, 10); //axis

    glEnd();
    glutSwapBuffers();
    /*t = getchar(); 
    if(t == "w"){
      z++;
    }
    if(t == "s"){
      z--;
    }
    if(t == "a"){
      x--;
    }
    if(t == "d"){
      x++;
    }
    if(t == "f"){
      y++;
    }
    if(t == "c"){
      y--;
    }
    if(t == "p"){
      YAW++;
    }
    if(t == "o"){
      YAW--;
    }
    if(t == "8"){
      PITCH++;
    }
    if(t == "2"){
      PITCH--;
    }
    if(t == "6"){
      ROLL++;
    }
    if(t == "4"){
      ROLL--;
    }
    if(t ==""){
      ;
    }*/

    ti = ti + 0.05;

    x = 2 * cos(ti); ///A bit of movement to evaluate fps
    y = 4 * sin(ti);

    glLoadIdentity();

    glRotatef(ROLL,0,0,1);
    glRotatef(PITCH,1,0,0);
    glRotatef(YAW,0,1,0);
    glTranslatef(x, y, z);


    std::cout << "\nYAW: " << YAW
    << "\nPITCH: " << PITCH
    << "\nROLL: " << ROLL
    << "\nx: " << x
    << "\ny: " << y
    << "\nz: " << z
    << "\novertime: " << overtime
    << "\nclock: " << CLOCKS_PER_SEC
    << "\nIterationsPerSecond: " << fps;

    overtime = 0;
    //Constant timing segment in progress--------------------------------

        //rep_count++;
        while(clock() < iter_c){
            overtime++;
        }

        if(overtime > 50){
            fps = fps + 0.0001;
        }
        if(overtime < 50){
            fps = fps - 0.0001;
        }
        if(overtime > 5000){
            fps = fps + 0.01;
        }
        if(overtime < 2){
            fps = fps - 0.1;
        }
        iter_c = iter_c + (CLOCKS_PER_SEC / fps);

    //-----------------------------------------------------------------------------------------

  }
}

// Sets up global attributes like clear color and drawing color, and sets up
// the desired projection and modelview matrices.
void init() {

  glClearColor(0.0, 0.0, 0.0, 1.0);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(120, 4.0/3.0, 0.1, 400);

  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();

  gluLookAt(10, 10, 10, 0, 0, 0, 0, 1, 0);
}

int main(int argc, char** argv) {
  init_keyboard();
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
  glutInitWindowPosition(0, 0);
  glutInitWindowSize(800, 600);
  glutCreateWindow("ChambersFlight");
  glutDisplayFunc(display);
  init();
  glutMainLoop();

}


Furthermore, based on the torus' that are in the program, 5 of them with 10 rings and 10 segments, the program is taking 500 vertices. I get about 7 fps according to my timing code segment. If I have [b]solid[b] torus', I can only do 200 vertices and get 6 fps. What is wrong here? I am using a raspberry pi model 3. Is this what I can expect? Maybe my timing segment needs improvement, because it certainly appears smoother than 6 and 7 fps.

Last edited on
I've never personally done anything with OpenGL on the Raspberri Pi, so I can't say what you should expect, but 6-7 fps seems pretty dang low. Perhaps your timing is off. 6-7 fps would look horrible and would stutter like crazy.
You should be able to render a few models with a few hundred vertices without any issue, even on low-powered hardware.

As far as timing goes, I'd count "milliseconds per frame" and convert that to frames/second.
C++ has some nice timing libraries in the standard library in chrono: http://www.cplusplus.com/reference/chrono/

Here's a little example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <chrono>

int main(int argc, char **argv)
{
	std::chrono::time_point<std::chrono::high_resolution_clock> tp = std::chrono::high_resolution_clock::now();

	char c{ '0' };

	std::cout << "Enter c: ";
	std::cin >> c;

	std::chrono::time_point<std::chrono::high_resolution_clock> later = std::chrono::high_resolution_clock::now();

	std::chrono::milliseconds delta = std::chrono::duration_cast<std::chrono::milliseconds>(later - tp);

	std::cout << "Milliseconds to enter text: " << delta.count() << std::endl;
}

You can adjust to do whatever you need it to, it's just an example.
As for the display function, I'm not sure why you'd need to have it enclosed in an infinite loop, but your registered callbacks can't work right if you never return from your display function. You should return from it once you've finished drawing your scene.

Your display callback would only be called once from what I can see. You can call glutPostRedisplay(); at the end of your display function, and that should signal that you want your display function to be called again in the next iteration.

You can also register an idle function to be called when no event has occurred glutIdleFunc(...)


The glutIdleFunc function sets the global idle callback. Freeglut calls the idle callback when there are no inputs from the user.

Usage

void glutIdleFunc ( void (*func) ( void ) );

funcThe new global idle callback function

Description

The glutIdleFunc function specifies the function that freeglut will call to perform background processing tasks such as continuous animation when window system events are not being received. If enabled, this function is called continuously from freeglut while no events are received. The callback function has no parameters and returns no value. Freeglut does not change the current window or the current menu before invoking the idle callback; programs with multiple windows or menus must explicitly set the current window and current menu and not rely on its current setting.


If you aren't testing keyboard input or anything like that and just want your scene to be drawn as often as possible, you can call glutPostRedisplay(); at the end of your idle function. Just remember that it'll be called continuously when no events are received (which, for most applications is like 90% of the time), so timing might be important to you if you want to save cpu time / control fps.
It doesn't sound like you have to worry about multiple windows/menus or anything like that, so you can ignore that part.

And I don't see freeglut becoming obsolete any time soon. If anything, OpenGL will become obsolete as new APIs come out (like Vulkan), but for OpenGL and FreeGLUT are good to go.

Edit: Typos
Last edited on
Did not occur to me to use chrono, I will switch to that now. I think you are right about the fps, it certainly does not jump as a game running at 7 fps would, I should be able to yield the correct fps using your method.

So if I simply put glutPostRedisplay end of the function, it will loop forever.

Does this mean I have to rename my function "display()" to glutIdleFunc() and then it will work with the gl keyboard input and loop? Do I have to pass anything to glutIdleFunc?

Thankyou
@JayhawkZombie

Hi,

std::chrono::high_resolution_clock is not the right clock to use (it's a wall clock) for timing the cpu - use std::clock instead. As I understand it, the reason a wall clock is no good, is that if some other thread (an unrelated OS thing) does something, then that will be included in the time as well.

http://en.cppreference.com/w/cpp/chrono/c/clock
@TheIdeasMan

Thanks, you're right. I wasn't aware of that. Thank you for pointing that out.

Isn't timing fun?! :D

But wouldn't it also be important if we wanted to measure total time passed independent of the application? std::clock states it measures time used by the program, but time outside the application could be important to the program if animations, etc are real-time. More so like if 60 seconds passed in real time, but less time passed in the process, the animations would be slower than expected. I imagine std::clock would be good for timing algorithms, but perhaps not animations?

---------------------------------------------------------------------------------------------------------------
You should be able to remove the loop around the code in your display function, and just call glutPostRedisplay() at the end of your display function. It will set a flag to signify that you wish for your display function to be called again in the next iteration of the main loop after all events have been processed.

glutIdleFunc doesn't take any parameters, nor does it return anything. Just bind it like you would any other callback
http://freeglut.sourceforge.net/docs/api.php#GlobalCallback
1
2
3
4
5
6
7
8
9
10
11
void my_idle_callback() //No params
{
    //......
}
...
void setup()
{
    //....
    glutIdleFunc(my_idle_callback);
    //....
}


Some people will have the idle callback and the display callback bound to the same function, which is OK for scenes that don't take too long to render or interactive applications, but can be problematic if your scene takes a while to render. A few hundred vertices is peanuts to OpenGL, so it shouldn't present an issue for you.

A better approach would be to just call glutPostRedisplay(); at the end of your idle function (which should be different from the display function). For complex applications, your event handling and rendering should be decoupled to avoid blocking the each other.
You'll want to be able to have events processed as quickly as possible after they're added to the queue, and that could be hindered if your scene rendering is being called constantly.
For the display func, you still shouldn't need to have that code inside a loop. Just render and return.

Your idle function could do stuff like update the state/update animation states/etc based on timing, but not actually render anything. After it's all been updated, call glutPostRedisplay to signal that you want to be rendered again and your display function will be called.

But you should do one or the other - meaning, either call glutPostRedisplay at the end of the display function or at the end of the idle function. I'd personally do it from the end of the idle function, it'll play nicely with GLUT's event-driven way of doing things.

---------------------------------------------------------------------------------------------------------------
With all that being said, I've also used GLFW, and my largest projects have used GLFW. It's most recent release was just 3 days ago. It also supports Vulkan, and I'm currently using it in porting my projects to Vulkan.

I might recommend trying to learn to use GLFW. freeGLUT manages event loops on its own, and that's only interrupted by calling your registered callbacks. GLFW gives the programmer much more control.
-----------------------
Also just keep in mind that freeglut (and GLFW for that matter as well) are C-based, so binding to a class method is a little more complicated than the way you're doing it now.
JayhawkZombie wrote:
I imagine std::clock would be good for timing algorithms, but perhaps not animations?


I imagine the trouble would be that one could get different results each time the program is executed. For example, my OS does an update each day - if some of that is done by the same core as the program / animation being timed, then the time will be longer. It may well be something like the actual time taken, but it doesn't mean much if the program is executed again when there is less other activity going on - so the time reported is much less. Keep in mind there are hundreds of process happening at any one time - my system is running 247 of them at the moment - which ones are actually doing something, and when? The program being run a third time might yield yet another wildly different elapsed time. So in short, timing is only meaningful if one can get consistent results.

One thing though - looking at the documentation with regard to if there are multiple threads in the program - the example had 2 threads, the total was for both of them, and it was about twice as long as the wall clock. That makes sense, but keeping in mind the previous paragraph. I suppose that one could try to time individual threads.

Any way it sounds as though things are well at your end - Regards :+)
Interesting to think about. If the application has many threads, one may not want to include time spent in the other thread if it isn't important to the task in the other thread.

Hmm. I'd think measuring the length of time since the last call to whatever function it was that was doing the updating would best be done using std::chrono::high_resolution_clock so that time spent in other threads wasn't included but it did include the amount of time it's been in real time, including time outside the program's execution. Well, that's what I've done before.
Like "Oh, it's been so many ms since the last time this function was called, that's how much I should update my animations by", since work done on the same core as the program would cause more time to pass between that program executing and my animations may need to progress further than they would under the light load. I suppose that time difference may not be that noticeable under light loads, but under heavy loads it could be significant.

I've only done some timing for animations using high_resolution_clock, so I don't know how using std::clock would affect that.

Maybe which one to use depends on whether you'd like to include real-world time passed or just time spent inside the program? And, of course, whether to include time spent in all threads separately.
Like "Oh, it's been so many ms since the last time this function was called, that's how much I should update my animations by", since work done on the same core as the program would cause more time to pass between that program executing and my animations may need to progress further than they would under the light load.


Ah, I see what you are saying. I keep thinking about it in terms of "how much time it did take?" for algorithm efficiency - but I can see that could be wrong in the context you explained :+) - Cheers !
Topic archived. No new replies allowed.