Is there any timer callback in GLFW?

Is there any timer callback in GLFW? For example, I can set the timer interval and a callback function can be called when the interval is up in which I can do some rendering work for an animation.

There is a glfwWaitEventsTimeout function but I would not use it for precise timing such as real time frame rendering.

The usual approach is to poll time using one of the time functions such as glfwGetTime to measure the time along with vertical sync to sync to a given refresh rate.

2 Likes

glfwWaitEventsTimeout does not directly trigger a timer callback as desired. For example, any other event can cause it to return. In that case, I cannot call it again to continue waiting with the same time interval because some time has already elapsed, so I have to recalculate the timeout. Although this approach works, it is indirect and leading to more code and complexity. I think this complexity is both unnecessary and should be encapsulated in GLFW.

I am now using polling but it is a busy-waiting (using glfwPollEvents. glfwWaitEvents does not return if there is no events). I don’t like it because it keeps CPU busy. The CPU should sleep before timeout if there is no other events. I remember that Windows offers a timeout event. Why doesn’t GLFW expose a simple and easy-to-use timer callback to users? Not everyone cares about timer accuracy.

Timers bring extra complexities or limitations from platform code - like what thread they can be called, or what other glfw or opengl operations they can do, etc… It is much easier to implement them on your own.

For example:

// for each timer keep variable after how many seconds to trigger it
float time = 2.f; // two seconds

float previous = glfwGetTime();
while (running)
{
    // process platform events
    glfwPollEvents();

    // common part, do this only once
    float now = glfwGetTime();
    float delta = now - previous;
    previous = now;

    // for each timer do this
    time -= delta;
    if (time <= 0.f)
    {
        DoTheThingThatTimerTriggerNeedsToDo();
    }

    // ... rest of rendering goes here        
    glfwSwapBuffers(window);
}
1 Like

That’s why people turn to libraries like GLU and GLEW. Isn’t GLFW designed for abstracting out the underlying complexity and details?

I think it is all the more easier for GLFW to do it.

Read my second paragraph if you didn’t.

That’s why people turn to libraries like GLU and GLEW. Isn’t GLFW designed for abstracting out the underlying complexity and details?

But those abstractions usually greatly limits what you can do. Sure it will work in one usecase, but will be usless for everybody else. Or it will anyways have some limitations depending on the platform. Look at recent discussion in this forum about which thread can be used to poll evens on - main thread? any thread? thread that created window? Different OSes have different rules.

Read my second paragraph if you didn’t.

Umm, enable vsync?
And nothing prevents you to use glfwWaitEventsTimeout with value that is time left for soonest timer to fire.

So what limitation does glutTimerFunc bring about?

So some user base is more important than others? What are they? Based on what? Biological characters like gene? You Linux users might think Windows is useless, but I am also thinking Linux is rubbish.

I refer “my” words to yours? Do you know English?

What I do in order to implement a timer callback is this: (1) call a function, say timer_callback() in a thread different than main program’s thread, (2) use a sleep function within timer_callback(), (3) do what you want to be done after the sleeping time.
I use OpenMP for that, but it can be done with pthreads or whatever multithread API you want to use. Also, the application itself doesn’t have to be written in C - most of the time, I use Fortran, with custom-made GLFW bindings. A “language agnostic” sketch of the program will look like this:

  • In timer_callback():
    Start function’s thread (omp_task)
    Put new thread in sleep mode for a desired amount of time; For that, use msleep() on GNU/Linux, or nanosleep() on Windows.
    Do whatever you want to be done after the specified amount of time.
    End function’s task (omp_task)

  • In main program:
    Start an OpenMP parallel session (omp_parallel)
    Start main program’s thread (omp_single)
    …
    call timer_callback(). Since it is a custom callback you can (and usually should) pass parameters such us the time you want to pass before the function does its thing.
    …
    End main program’s thread (omp_single)
    End parallel session (omp_parallel)
    Stop program execution (this will also end timer_callback's thread, if it is still running).

The above scheme won’t keep CPU busy as the timer callback just sleeps for the desired amount of time, and awakes only when it is time to do its thing. It can also be used for whatever you want; timer_callback() can change rendering parameters for certain OpenGL structures, change the volume for a sound playing (you can actually implement a fade-in or fade-out effect), or whatever else you need to be done after a specified amount of time.

GLFW itself does not have any threading library built-in. Older versions used to have one, but not anymore, as developers felt there is no need to reinvent the wheel (see section 1.2 in GLFW’s FAQ). I believe they did well: there are very good threading libraries around, and you can pick the one that fits your needs. Furthermore, a custom callback can be more efficient than a generic one. For example, in FreeGLUT’s built-in timer callback, you essentially pass a pointer to a structure in order to make the callback function communicate with the main program, and I never liked that; on the other hand, a custom callback can be something like timer_callback(time, angle) to change the rotation angle of something rendered, or, if needed, something more complicated which passes several parameters in the callback function.
Last but not least, the callback function can sleep more than once to do more complicated things; for example, if you want to change the opacity of something from opacity_min to opacity_max in time_delta time intervals, you could use something like timer_callback(time_delta, opacity, opacity_delta, opacity_min, opacity_max); that custom callback will initially set opacity to opacity_min, then repeatedly sleep for time_delta milliseconds and add opacity_delta to opacity until it reaches opacity_max.

Strictly speaking, the approach used above is not a callback function, at least not in the sense the term “callback” is typically used. It is not a function that is called automatically when a specified amount of time passes; instead, you call the function yourself in your program, and the function itself sleeps until it is time to do something. However, the effect is the same, and you can easily implement things such as animation or whatever else it needs to be done.

P.S.: I am going to pretend I never saw things like “Linux is rubbish” in a previous thread, since not only such a statement is “rubbish” itself, but it also has nothing to do with this forum.