Search code examples
c++openglgraphicsglutfreeglut

Using glutTimerFunc with glutMouseFunc


I am trying to do a little game, and in my game I have some squares and when the user click on these squares, they got highlighted. To achieve this effect I am using glutMouseFunc with glutTimerFunc.

When the user clicks on the screen I pick the pixel and identify the square I need to highlight. Once the square is identified I call glutTimerFunc. The function registred with glutTimerFunc increase the value of each component of color by 0.01 until they reach one max value defined by me, then this value goes back to a minimum value.

glutTimerFunc execute in 60 milliseconds and I get a almost smooth shine effect.

My problem is, if I click on two squares very fast, the effect starts on the first square, but don't finish, so the square remains highlighted and the second squares do the entire effect. If I click like a crazy man on every square, all of them got highlighted.

How can I make this effect of shining terminate even if I click on other square?

Here is a snippet of code

void Memoria::shineEffect(GLint value) {

    if(value == 1) {
        for(GLint i = 0; i < 3; i++) {
            if(colors[selectedSquare][i] > 0) {
                colors[selectedSquare][i] += COLOR_INCREASE;
                if(colors[selectedSquare][i] >= MAX) {
                    colors[selectedSquare][i] = MAX;
                    value = -1;
                }
            }
        }
        glutTimerFunc(FPS, timeWrapper, value);
    }
    else {
        if(value == -1) {
            for(GLint i = 0; i < 3; i++) {
                if(colors[selectedSquare][i] > 0) {
                    colors[selectedSquare][i] -= COLOR_INCREASE;
                    if(colors[selectedSquare][i] <= MIN) {
                        value = 0;
                        colors[selectedSquare][i] = MIN;
                    }
                }
            }
            glutTimerFunc(FPS, timeWrapper, value);
        }
    }
}

timeWrapper calls shineEffect if the value passed in the parameter is 1 or -1.


Solution

  • You want the shineEffect function to go through one highlight loop at least, and then stop if the highlighted item has changed. It's more a UI code design issue rather than an OpenGL or GLUT one.

    The mechanic you need to implement is pretty straightforward:

    • install once for all an updateHighlights function with glutTimerFunc: this function will be responsible of updating the highlights of all the clicked elements,
    • create a queue of elements: each time an element has been clicked, add it to the queue,

    The task performed by the updateHighLights function should be as follow:

    • if the queue contains one element, keep cycling its highlight as you already do in your program
    • if the queue contain more than one element, for each element in the queue,
      • step the highlight cycle
      • if the cycle is over, and the element is not the last one, remove the element from the queue

    Here's another perhaps more flexible take on your problem.

    The Glut event loop machinery is very simple design: there's only one hook to put your "idle work" code, so it's probably more flexible to install a function there which calls a list of others functions. That list could be then modified with a set primitive, to install or remove specific tasks to perform during idle time. This could be much more flexible than the "one function" approach of GLUT.

    For instance, you could isolate your current highlight code in one function with a struct containing the element to highlight, and have the function remove itself from the list when its element is done through a highlight cycle and isn't active anymore.

    Since you are using C++, it should be easy to bundle all these functionalities in classes:

    • one class for the list of idle tasks
    • one base class for idle tasks
    • one derived idle task class for the purpose of highlighting a square (with fields for the square and for the active status)
    • one class to keep track of the active square, so that it may be easily deactivated and replaced by the new active one. This one would be accessed by the glutMouseFunc function.