Search code examples
c++event-handlingredrawfltk

force FLTK to redraw without event Handles


I'm using Fltk to render openGL graphs. currently I'm debugging a global array which is sorted by a heapsort function. My purpose is to see after each swap of elements in the heapsort function a graphical swap of elements. but I don't want to catch an event from FLTK event_handle for every time i need to redraw after I swapped and waiting at breakpoint. (the heapsort function and the opengl render part are running in 2 different threads (if that doesn't has to go without saying)). So the first try I had was to use:

Fl::add_timeout(1.0, MyRedrawCallback, (void *)&myWindow);

Fl::run();

void MyRedrawCallback(void *myWindow)

{

    MyWindow *pMyWindow;

    pMyWindow = (MyWindow *) myWindow;
    pMyWindow->redraw();
    Fl::repeat_timeout(1.0, MyRedrawCallback, (void *)&pMyWindow);
}

But every Time the callback is called the 2nd time i get an "Access violation reading"

I'm suggesting that FL::run starts a different thread so maybe the first time is still in same thread so the address of redraw is still usable but after that I'm in a different thread and the function at address is not that what I'm expecting?!

But I already took a different way because I wasn't sure i cant even use the timeout on this way. So i was looking for a way to get an event that's eq to "set amount of time passed" or "nothing is happening for..." but there isn't such a handle I'm right?

Finally is there a way to let FLTK execute commands even outside the eventloop? or is there another way to solve my problem?


Solution

  • Please take a look at the following example, taken from here: http://seriss.com/people/erco/fltk/#OpenGlInterp

    #include <FL/Fl.H>
    #include <FL/Fl_Gl_Window.H>
    #include <FL/gl.h>
    #include <math.h>
    
    //
    // Demonstrate interpolating shapes
    // erco 06/10/05
    //
    
    class Playback : public Fl_Gl_Window {
        int frame;
        // Linear interpolation between two values based on 'frac' (0.0=a, 1.0=b)
        float Linterp(float frac, float a, float b) {
            return( a + ( frac * (b - a) ));
        }
        // Sinusoidal easein/easeout interpolation between two values based on 'frac' (0.0=a, 1.0=b)
        float SinInterp(float frac, float a, float b) {
            float pi = 3.14159;
            frac = (sin(pi/2 + frac*pi ) + 1.0 ) / 2.0;     // 0 ~ 1 -> 0 ~ 1
            return(Linterp(frac,a,b));
        }
        // DRAW SIMPLE SHAPE INTERPOLATION
        //     Interpolation is based on the current frame number
        //
        void DrawShape(int frame) {
            // Calculate a fraction that represents the frame# being shown
            float frac = ( frame % 48 ) / 48.0 * 2;
            if ( frac > 1.0 ) frac = 2.0-frac;      // saw tooth wave:  "/\/\/\"
    
            static float a_xy[9][2] = {
                { -.5, -1. }, { 0.0, -.5 }, { -.5, -1. }, { 0.0, -.5 },
                { 0.0, 0.0 },
                { 0.0, -.5 }, { +.5, -1. }, { 0.0, -.5 }, { +.5, -1. },
            };
            static float b_xy[9][2] = {
                { -.25, -1. }, { -.50, -.75 }, { -.75, -1.0 }, { -.50, -.75 },
                { 0.0, 0.0 },
                { +.50, -.75 }, { +.75, -1.0 }, { +.50, -.75 }, { +.25, -1.0 }
            };
            // Linterp a and b to form new shape c
            float c_xy[9][2];
            for ( int i=0; i<9; i++ )
                for ( int xy=0; xy<2; xy++ )
                    c_xy[i][xy] = SinInterp(frac, a_xy[i][xy], b_xy[i][xy]);
            // Draw shape
            glColor3f(1.0, 1.0, 1.0);
            glBegin(GL_LINE_STRIP);
            for ( int i=0; i<9; i++ )
                glVertex2f(c_xy[i][0], c_xy[i][1]);
            glEnd();
        }
        // DRAW THE WIDGET
        //    Each time we're called, assume
        //
        void draw() {
            if (!valid()) {
                valid(1);
                glLoadIdentity();
                glViewport(0,0,w(),h());
            }
            glClear(GL_COLOR_BUFFER_BIT);
            // Draw shape 4x, rotated at 90 degree positions
            glPushMatrix();
                DrawShape(frame); glRotatef(90.0, 0, 0, 1);
                DrawShape(frame); glRotatef(90.0, 0, 0, 1);
                DrawShape(frame); glRotatef(90.0, 0, 0, 1);
                DrawShape(frame);
            glPopMatrix();
            // Advance frame counter
            ++frame;
        }
        // 24 FPS TIMER CALLBACK
        //     Called 24x per second to redraw the widget
        //
        static void Timer_CB(void *userdata) {
            Playback *pb = (Playback*)userdata;
            pb->redraw();
            Fl::repeat_timeout(1.0/24.0, Timer_CB, userdata);
        }
    public:
        // Constructor
        Playback(int X,int Y,int W,int H,const char*L=0) : Fl_Gl_Window(X,Y,W,H,L) {
            frame = 0;
            Fl::add_timeout(1.0/24.0, Timer_CB, (void*)this);       // 24fps timer
            end();
        }
    };
    
    int main() {
         Fl_Window win(500, 500);
         Playback  playback(10, 10, win.w()-20, win.h()-20);
         win.resizable(&playback);
         win.show();
         return(Fl::run());
    }
    

    This example more/less does exactly what you want. Greg Ercolano has more FLTK examples on his web-site. I recommend taking a look at http://seriss.com/people/erco/fltk/ .