Problem with dynamically updating display from program output

Hey All!

I am working on visualizing the output of a program I wrote by using OpenGL/GLEW/FreeGlut. I currently have a dual threaded program that calculates some 3D Cartesian coordinates from some data. I also wrote a little OpenGL program that can display coordinates as spheres on a rough 3D axis.

My problem is I cannot get the display to accept input from the two threads performing the computations.

I tried adding my OpenGL display just before I launch both threads and having the threads write their outputs to global variables used by both sides of the program, but I think that the glutMainLoop(); function is not returning control back over to the main program as I am left with just the empty display of the 3D axis and no points. Is there a way to launch the OpenGL display function and have it passively wait for an updated input or simply run and return control back to the program is was launched from?

I just found glutMainLoopEvent();, but I have not found any decent documentation on how to use it. If this is the way I would want to go, then can anyone recommend some examples or docs?

I also thought that maybe I have to put all of my computations inside of the “display” function from glutDisplayFunc(display); but the program is fairly large and complicated with different initializations and thread checks and I am unsure of how it will like being put entirely in the display.

Thanks for looking!

Dave

EDIT: I think it is worth noting that the dual threaded program is also cuda, I am looking into CUDA/OpenGL interop now as well.

Is there a way to launch the OpenGL display function and have it passively wait for an updated input or simply run and return control back to the program is was launched from?
I think glutIdlefunc is what you need. Look up definition and examples.

Thank you for your reply!

I am vaguely familiar with glutIdleFunc, and I believe it assigns what the program is to do while it waits for a callback. Since the glutMainLoop() does not return control after it has been launched I am still confused as to how the idle function will help this situation.

Initialize input data and system(Load data, set up buffers)
|
V
Start OpenGL/Freeglut display (read input from shared globals with threads)[Program displays window and empty axis created here but I dont think it is allowing the next steps to occur]
|
V
Start two threads that perform compuations (write output to global variables)
|
V
Run until exit

I currently have glutIdleFunc running with my display function as the input as well. Are you suggesting that I move my entire program inside of glutIdleFunc? I thought about doing this but I am not sure if it is the best option since the program is fairly large and complex.

EDIT: I think my phrasing was confusing, the input I want it to wait for is simply updated coordinates from the code I wrote to perform calculations, not a keyboard or mouse or reshape callback. Sorry!

Here is some code that might show my problem a little more clearly. I have a main program and two functions, one that generates xyz coords and the display function I want to plot the points on. I just can’t figure out a method to get the input to the display.

///////////////////////////////main.cpp
#include "simpleGL.h"
#include <stdio.h>
#include <string.h>


void gen_XYZ_coords(int time){
    //Large program that just munches on data creating XYZ coords
    memset( XYZ_Size,0,sizeof(float)*(NumObj+1)*4);
    float x = 0.0;
    float y = 0.0;
    float z = 0.0;
    float sz = 1;

    for (int frame = 0; frame<4; frame++){
        NumObj = 1;
        for(int i = 0; i<4; i++){

            x = float(i)+float(time)/10;
            y = float(i)+float(time)/10;
            z = float(i)+float(time)/10;

            XYZ_Size[NumObj*4] = x;
            XYZ_Size[NumObj*4+1] = y;
            XYZ_Size[NumObj*4+2] = z;
            XYZ_Size[NumObj*4+3] = sz;
        }
    }

    for(int num =0; num < NumObj; num++){

        printf("x: %f y: %f z: %f size: %f
", XYZ_Size[NumObj*4] , XYZ_Size[NumObj*4+1], XYZ_Size[NumObj*4+2], XYZ_Size[NumObj*4+3] );

    }


}


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


    int t = 0;

    simpleGL(argc, argv); //Gets stuck here, but I want it to be up and generating spheres when gen_xyz starts running

    for(t = 0; t < 100; t++){

    gen_XYZ_coords(t);
    }

}

////////////////////////simpleGL.h


#pragma

#ifndef SIMPLEGL_H
#define HEADERFILE_H


extern float XYZ_Size[];
extern int NumObj;

int simpleGL(int argc, char **argv);

#endif

//////////////////////////////////simpleGL.cu

#include <GL/glew.h>
#include <GL/freeglut.h>
#include "simpleGL.h"



GLfloat Color_Material_AMB[] = {0.25, 0.20725, 0.20725,1}; //
GLfloat Color_Material_SPEC[] = {0.296648, 0.296648, 0.296648};  //
GLfloat Color_Material_DIFF[] = {0.829, 0.829,1.0, 1.0}; //
GLfloat SpecularLight[] = {1.0, 1.0, 1.0};//
GLfloat AmbientLight[] =  {1.0, 1.0, 1.0};//
GLfloat DiffuseLight[] = {1.0, 1.0, 1.0}; //
GLfloat mShininess[] = {11.264}; //set the shininess of the material 0 =very shiny 128 = duller than a rock
GLfloat Light_Position[] = {10,10,10,1};

// This is for 
float XYZ_Size[4*50]; //imit to 50 obj
int NumObj = 0;

// List for fast creationg of axis
static GLuint axes_list;

// mouse controls
int mouse_old_x, mouse_old_y;
int mouse_buttons = 0;
float rotate_x = 0.0;
float rotate_y = 0.0;
float xshift = 0.0;
float yshift = 0.0;
float translate_z = -3.0;
GLfloat angle = 0.0;

void keyboard(unsigned char key, int x, int y);
void mouse(int button, int state, int x, int y);
void motion(int x, int y);


void init (void) {
    glEnable (GL_DEPTH_TEST);
    glEnable (GL_LIGHTING);
    glEnable (GL_LIGHT0);
    glShadeModel(GL_SMOOTH);   // Enable smooth shading
}

void light (void) {
    glLightfv(GL_LIGHT0, GL_SPECULAR, SpecularLight);
    glLightfv(GL_LIGHT0, GL_AMBIENT, AmbientLight);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, DiffuseLight);
    glLightfv(GL_LIGHT0, GL_POSITION, Light_Position);
}

///////////////////////////////////////////////////////////////////////////////
// draw a grid on the xz plane
///////////////////////////////////////////////////////////////////////////////
void drawGrid(float size, float step)
{
    // disable lighting
    glDisable(GL_LIGHTING);

    glBegin(GL_LINES);

    glColor3f(0.3f, 0.3f, 0.3f);
    for(float i=step; i <= size; i+= step)
    {
        glVertex3f(0, 0,  i);   // lines parallel to X-axis
        glVertex3f( size, 0,  i);

        glVertex3f( i, 0, 0);   // lines parallel to Z-axis
        glVertex3f( i, 0,  size);

    }

    // x-axis red
    glColor3f(0.5f, 0, 0);
    glVertex3f(0, 0, 0);
    glVertex3f( size, 0, 0);

    // z-axis blue
    glColor3f(0,0,0.5f);
    glVertex3f(0, 0, 0);
    glVertex3f(0, 0,  size);

    // y-axis green
    glColor3f(0,0.5f,0);
    glVertex3f(0, 0, 0);
    glVertex3f(0, 6.4, 0); 
    glEnd();

    // enable lighting back
    glEnable(GL_LIGHTING);
}

///////////////////////////////////////////////////////////////////////////////
// draw the local axis of an object
///////////////////////////////////////////////////////////////////////////////
void drawAxis(float size)
{

    glDisable(GL_LIGHTING);
    glPushMatrix();             

    // draw axis
    glLineWidth(3);
    glBegin(GL_LINES);
        glColor3f(1, 0, 0); //red
        glVertex3f(0, 0, 0);
        glVertex3f(size, 0, 0); //
        glColor3f(0, 1, 0); //green
        glVertex3f(0, 0, 0);
        glVertex3f(0, size, 0);
        glColor3f(0, 0, 1); //blue
        glVertex3f(0, 0, 0);
        glVertex3f(0, 0, size);
    glEnd();
    glLineWidth(1);

    // draw arrows(actually big square dots)
    glPointSize(5);
    glBegin(GL_POINTS);
        glColor3f(1, 0, 0);
        glVertex3f(size, 0, 0);
        glColor3f(0, 1, 0);
        glVertex3f(0, size, 0);
        glColor3f(0, 0, 1);
        glVertex3f(0, 0, size);
    glEnd();
    glPointSize(1);

    // restore default settings
    glPopMatrix();
    glEnable(GL_LIGHTING);
    glDepthFunc(GL_LEQUAL);
}

////////////////////////////////////////////////////////////////////////////////
//! Mouse event handlers
////////////////////////////////////////////////////////////////////////////////
void mouse(int button, int state, int x, int y){
    //mouse buttons
    if (state == GLUT_DOWN)
    {
        mouse_buttons |= 1<<button;
    }
    else if (state == GLUT_UP)
    {
        mouse_buttons = 0;
    }

    mouse_old_x = x;
    mouse_old_y = y;
}

void motion(int x, int y)
{   //mouse motion
    float dx, dy;
    dx = (float)(x - mouse_old_x);
    dy = (float)(y - mouse_old_y);

    if (mouse_buttons & 1)
    {
        rotate_x += dy * 0.2f;
        rotate_y += dx * 0.2f;
    }
    else if (mouse_buttons & 4)
    {
        int mod = glutGetModifiers();
        if (mod == GLUT_ACTIVE_CTRL){
            xshift = xshift + dx*0.04;
            yshift = yshift - dy*0.04;

    }
    else{
        translate_z += dy * 0.1f;
    }
    }

    mouse_old_x = x;
    mouse_old_y = y;
}



////////////////////////////////////////////////////////////////////////////////
//! Display Tracked Points
////////////////////////////////////////////////////////////////////////////////
void trackedSphere(float x, float y, float z, int size){


    //Plot sphere, preserving original coords
    glPushMatrix();
        glTranslatef((GLfloat) x,(GLfloat) y, (GLfloat) z); //Move to object location
        glutSolidSphere(0.15,50,50); //maybe switch to size of object, scaled appropriately
    glPopMatrix();

}

////////////////////////////////////////////////////////////////////////////////
//! Render Display
////////////////////////////////////////////////////////////////////////////////
void display (void) {

    glClearColor (0.0,0.0,0.0,1.0);
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity(); 

    // Draw axes 
    glPushMatrix();
    glCallList(axes_list);
    glPopMatrix();
    light();

    // shift model, use right click and drag to move Z, control+right click and drag to pan
    glTranslatef(0 + xshift,-3 + yshift,-20 + translate_z);

    // rotate based off left click and drag
    glRotatef(rotate_x, 1.0, 0.0, 0.0);
    glRotatef(rotate_y, 0.0, 1.0, 0.0);

    // draw grid
    drawGrid(7.1, 0.71);

    // Display objects in buffer

    // Color objects to be drawn
    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Color_Material_DIFF);
    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Color_Material_SPEC);
    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, Color_Material_AMB);
    glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mShininess);

     //This needs to be an input to display as well as XYZsize
    for(int i = 0; i<NumObj; i++ ){
        float xl = XYZ_Size[4*i];
        float yl = XYZ_Size[4*i+1];
        float zl = XYZ_Size[4*i+2];
        float sz = XYZ_Size[4*i+3];

        trackedSphere(xl,yl,zl,sz);
    }

    drawAxis(1); // plot axis

    glutSwapBuffers();

}

////////////////////////////////////////////////////////////////////////////////
//! Window reshaping
////////////////////////////////////////////////////////////////////////////////

void reshape (int w, int h) {
    glViewport (0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    //glOrtho(-10.0f, 10.0f, -10.0f, 10.0f, 1.0f, 100.0f);  //ridged model, no perspective (objects dont get smaller in the background
    gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 100.0); //Has persepective when displayed << I like this one
    glMatrixMode (GL_MODELVIEW);
}




int simpleGL(int argc, char **argv) {
    glutInit (&argc, argv);
    glutInitDisplayMode (GLUT_DOUBLE | GLUT_DEPTH);
    glutInitWindowSize (500, 500);
    glutInitWindowPosition (100, 100);
    glutCreateWindow ("OutPutDisplay");
    init ();

    glutDisplayFunc (display);
    glutIdleFunc (display);
    glutMouseFunc(mouse);
    glutMotionFunc(motion);
    glutReshapeFunc (reshape);
    glutMainLoop ();
    //glutMainLoopEvent ();
    return 0;
}

When I read your first post, it sounded like you wanted an animation of balls or points moving as new positions were computed. But your last post seems to indicate that all you need is to show the positions of all the balls after the calculations are complete. This is MUCH easier.

Once you open a GL window with GLUT, you are in an infinite loop. You will never exit the simpleGL routine (unless you terminate the program). That’s what your problem is. The ‘for’ statement in ‘main’ is never reached. This is a flow problem which is easy to correct.

Try calling ‘gen_XYZ_coords’ from your ‘display’ routine. I would put the call at the very beginning, before ‘glClearColor’. Glut calls ‘display’ in response to an input action such as pushing a mouse button. I assume that each time you push a mouse button you want to recompute and redisplay your set of points. This should do it, or least get you much closer to what you want.

BTW - I wouldn’t call this a dual threaded program - at least not the example you’ve posted.

Thank you Carmine! I actually ended up doing a slightly different work around. I have my main thread open a GL window and set all the functions, then that main thread launches two threads that begin generating the XYZ coordinates. ( I left them out of the program for simplicity and to show only the openGL problem, I agree as shown it is not a multithreaded program) After control returns to the main thread I use globals to transfer data to the display function and repeated calls to glutPostRedisplay() and glutMainLoopEvent().

Ideally I would like to have an update call in each of the processing threads so that on every iteration, each thread will update the display, but I found that this could be limiting with the scope of GL and I don’t think it is threadsafe, but I may try to make some sort of work around.

Here is the code with my solution implemented in case anyone finds it useful.


//////////simpleGL.cu
#include <GL/glew.h>
#include <GL/freeglut.h>
#include "simpleGL.h"



GLfloat Color_Material_AMB[] = {0.25, 0.20725, 0.20725,1}; //
GLfloat Color_Material_SPEC[] = {0.296648, 0.296648, 0.296648};  //
GLfloat Color_Material_DIFF[] = {0.829, 0.829,1.0, 1.0}; //
GLfloat SpecularLight[] = {1.0, 1.0, 1.0};//
GLfloat AmbientLight[] =  {1.0, 1.0, 1.0};//
GLfloat DiffuseLight[] = {1.0, 1.0, 1.0}; //
GLfloat mShininess[] = {11.264}; //set the shininess of the material 0 =very shiny 128 = duller than a rock
GLfloat Light_Position[] = {10,10,10,1};

// This is for 
float XYZ_Size[4*50]; //imit to 50 obj
int NumObj = 0;

// List for fast creationg of axis
static GLuint axes_list;

// mouse controls
int mouse_old_x, mouse_old_y;
int mouse_buttons = 0;
float rotate_x = 0.0;
float rotate_y = 0.0;
float xshift = 0.0;
float yshift = 0.0;
float translate_z = -3.0;
GLfloat angle = 0.0;

void keyboard(unsigned char key, int x, int y);
void mouse(int button, int state, int x, int y);
void motion(int x, int y);


void init (void) {
    glEnable (GL_DEPTH_TEST);
    glEnable (GL_LIGHTING);
    glEnable (GL_LIGHT0);
	glShadeModel(GL_SMOOTH);   // Enable smooth shading
}

void light (void) {
    glLightfv(GL_LIGHT0, GL_SPECULAR, SpecularLight);
    glLightfv(GL_LIGHT0, GL_AMBIENT, AmbientLight);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, DiffuseLight);
	glLightfv(GL_LIGHT0, GL_POSITION, Light_Position);
}

///////////////////////////////////////////////////////////////////////////////
// draw a grid on the xz plane
///////////////////////////////////////////////////////////////////////////////
void drawGrid(float size, float step)
{
    // disable lighting
    glDisable(GL_LIGHTING);

    glBegin(GL_LINES);

    glColor3f(0.3f, 0.3f, 0.3f);
    for(float i=step; i <= size; i+= step)
    {
        glVertex3f(0, 0,  i);   // lines parallel to X-axis
        glVertex3f( size, 0,  i);

        glVertex3f( i, 0, 0);   // lines parallel to Z-axis
        glVertex3f( i, 0,  size);

    }

    // x-axis red
    glColor3f(0.5f, 0, 0);
    glVertex3f(0, 0, 0);
    glVertex3f( size, 0, 0);

    // z-axis blue
    glColor3f(0,0,0.5f);
    glVertex3f(0, 0, 0);
    glVertex3f(0, 0,  size);

	// y-axis green
    glColor3f(0,0.5f,0);
    glVertex3f(0, 0, 0);
    glVertex3f(0, 6.4, 0); 
    glEnd();

    // enable lighting back
    glEnable(GL_LIGHTING);
}

///////////////////////////////////////////////////////////////////////////////
// draw the local axis of an object
///////////////////////////////////////////////////////////////////////////////
void drawAxis(float size)
{

    glDisable(GL_LIGHTING);
    glPushMatrix();             

    // draw axis
    glLineWidth(3);
    glBegin(GL_LINES);
        glColor3f(1, 0, 0); //red
        glVertex3f(0, 0, 0);
        glVertex3f(size, 0, 0); //
        glColor3f(0, 1, 0); //green
        glVertex3f(0, 0, 0);
        glVertex3f(0, size, 0);
        glColor3f(0, 0, 1); //blue
        glVertex3f(0, 0, 0);
        glVertex3f(0, 0, size);
    glEnd();
    glLineWidth(1);

    // draw arrows(actually big square dots)
    glPointSize(5);
    glBegin(GL_POINTS);
        glColor3f(1, 0, 0);
        glVertex3f(size, 0, 0);
        glColor3f(0, 1, 0);
        glVertex3f(0, size, 0);
        glColor3f(0, 0, 1);
        glVertex3f(0, 0, size);
    glEnd();
    glPointSize(1);

    // restore default settings
    glPopMatrix();
    glEnable(GL_LIGHTING);
    glDepthFunc(GL_LEQUAL);
}

////////////////////////////////////////////////////////////////////////////////
//! Mouse event handlers
////////////////////////////////////////////////////////////////////////////////
void mouse(int button, int state, int x, int y){
	//mouse buttons
    if (state == GLUT_DOWN)
    {
        mouse_buttons |= 1<<button;
    }
    else if (state == GLUT_UP)
    {
        mouse_buttons = 0;
    }

    mouse_old_x = x;
    mouse_old_y = y;
}

void motion(int x, int y)
{	//mouse motion
    float dx, dy;
    dx = (float)(x - mouse_old_x);
    dy = (float)(y - mouse_old_y);

    if (mouse_buttons & 1)
    {
        rotate_x += dy * 0.2f;
        rotate_y += dx * 0.2f;
    }
    else if (mouse_buttons & 4)
    {
		int mod = glutGetModifiers();
		if (mod == GLUT_ACTIVE_CTRL){
			xshift = xshift + dx*0.04;
			yshift = yshift - dy*0.04;

	}
	else{
        translate_z += dy * 0.1f;
	}
    }

    mouse_old_x = x;
    mouse_old_y = y;
}



////////////////////////////////////////////////////////////////////////////////
//! Display Tracked Points
////////////////////////////////////////////////////////////////////////////////
void trackedSphere(float x, float y, float z, int size){
	
	
	//Plot sphere, preserving original coords
	glPushMatrix();
		glTranslatef((GLfloat) x,(GLfloat) y, (GLfloat) z); //Move to object location
		glutSolidSphere(0.15,50,50); //maybe switch to size of object, scaled appropriately
	glPopMatrix();

}

////////////////////////////////////////////////////////////////////////////////
//! Render Display
////////////////////////////////////////////////////////////////////////////////
void display (void) {

    glClearColor (0.0,0.0,0.0,1.0);
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity(); 

	// Draw axes 
    glPushMatrix();
    glCallList(axes_list);
    glPopMatrix();
    light();
	
	// shift model, use right click and drag to move Z, control+right click and drag to pan
    glTranslatef(0 + xshift,-3 + yshift,-20 + translate_z);
    
	// rotate based off left click and drag
    glRotatef(rotate_x, 1.0, 0.0, 0.0);
    glRotatef(rotate_y, 0.0, 1.0, 0.0);
    
	// draw grid
    drawGrid(7.1, 0.71);

	// Display objects in buffer
	
	// Color objects to be drawn
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, Color_Material_DIFF);
	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, Color_Material_SPEC);
	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, Color_Material_AMB);
    glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mShininess);

	 //This needs to be an input to display as well as XYZsize
	for(int i = 0; i<NumObj; i++ ){
		float xl = XYZ_Size[4*(i+1)];
		float yl = XYZ_Size[4*(i+1)+1];
		float zl = XYZ_Size[4*(i+1)+2];
		float sz = XYZ_Size[4*(i+1)+3];

		trackedSphere(xl,yl,zl,sz);
	}

	drawAxis(1); // plot axis

    glutSwapBuffers();
    
}

////////////////////////////////////////////////////////////////////////////////
//! Window reshaping
////////////////////////////////////////////////////////////////////////////////

void reshape (int w, int h) {
    glViewport (0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 100.0); //Has persepective when displayed << I like this one
    glMatrixMode (GL_MODELVIEW);
}


	

int simpleGL(int argc, char **argv) {
    glutInit (&argc, argv);
    glutInitDisplayMode (GLUT_DOUBLE | GLUT_DEPTH);
    glutInitWindowSize (500, 500);
    glutInitWindowPosition (100, 100);
    glutCreateWindow ("OutPutDisplay");
    init ();
    glutDisplayFunc (display);
    glutIdleFunc (display);
	glutMouseFunc(mouse);
    glutMotionFunc(motion);
    glutReshapeFunc (reshape);



    return 0;
}

void updateGL(void){

	glutPostRedisplay();
	glutMainLoopEvent();

}

//////////////////main.cpp
#include "simpleGL.h"
#include <stdio.h>
#include <string.h>


void gen_XYZ_coords(int time){
	//Large program that just munches on data creating XYZ coords
	//memset( XYZ_Size,0,sizeof(float)*(NumObj+1)*4);
	
	
	
	float x = 0.0;
	float y = 0.0;
	float z = 0.0;
	float sz = 1;
	
	
		NumObj = 1;
		for(int i = 0; i<4; i++){
		
			x = float(time)/100.0f;
			y = float(time)/100.0f;
			z = float(time)/100.0f;
			
			XYZ_Size[NumObj*4] = x;
			XYZ_Size[NumObj*4+1] = y;
			XYZ_Size[NumObj*4+2] = z;
			XYZ_Size[NumObj*4+3] = sz;
		}
	

	for(int num =0; num < NumObj; num++){

		printf("x: %f y: %f z: %f size: %f
", XYZ_Size[NumObj*4] ,	XYZ_Size[NumObj*4+1], XYZ_Size[NumObj*4+2], XYZ_Size[NumObj*4+3] );

	}


}


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


	float t = 0.0;
	
	
	simpleGL(argc, argv); //Gets stuck here, but I want it to be up and generating spheres when gen_xyz starts running
	
	for(t = 0; t < 10000; t++){
	
	gen_XYZ_coords(t/10);
	
	updateGL();

	}

	
	
}
////////////////////////////simpleGL.h
#ifndef SIMPLEGL_H
#define HEADERFILE_H


extern float XYZ_Size[];
extern int NumObj;

int simpleGL(int argc, char **argv);
void updateGL(void);

#endif