OpenGL - FreeGlut Multiple Window Callbacks and C++ (OOP)

Using glut with cpp can be difficult in some cases for example because of the glut callback specification. You can’t specify a callback to a object methods due to c limitations.

One workaround is to use singletons as described here:

Another way to cope this issue is to use the glutGetWindow method. This method can be used within a static callback target method to determine which window should be updated etc. In my example i created a window class which is used to create and handle windows. Outside of this class i just created some wrapper callback methods which redirect the desired call to my object methods.

GL_GLUT_OOP.cpp

#include <GL/glut.h>
#include <GL/glu.h>
#include <stdio.h>
#include "window.h"

#define GAP  (200 / 4)
#define SPACING  (200 / 4 + 200)

window * windows[3];

void display(void) {
	int winId = glutGetWindow();
	//printf("win%i\n", winId - 1);
	windows[winId - 1]->display();
}

/**
 * Request redisplay of all three windows.
 */
void refresh() {
	for (int i = 0; i < 3; i++) {
		windows[i]->refresh();
	}
}

void mouse(int x, int y) {
	int winId = glutGetWindow();
	//printf("mouse in win%i\n", winId - 1);
	windows[winId - 1]->mouse(x, y);
	windows[winId - 1]->refresh();
}

/**
 *  Keyboard function works for all windows.
 */
void keyboard(unsigned char key, int x, int y) {
	if (key == 27)
		exit(0);
}

void idle() {
	for (int i = 0; i < 3; i++) {
		windows[i]->idle();
	}
}

int main(int argc, char *argv[]) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);

	windows[0] = new window("Window 0", GAP, GAP);
	glutDisplayFunc(display);
	glutKeyboardFunc(keyboard);
	glutMotionFunc(mouse);

	windows[1] = new window("Window 1", GAP + SPACING, GAP);
	glutDisplayFunc(display);
	glutKeyboardFunc(keyboard);
	glutMotionFunc(mouse);

	windows[2] = new window("Window 2", GAP + 2 * SPACING, GAP);
	glutDisplayFunc(display);
	glutKeyboardFunc(keyboard);
	glutMotionFunc(mouse);

	glutIdleFunc(idle);
	glutMainLoop();
}

window.h

#include "window.h"
#include <GL/glut.h>
#include <GL/glu.h>

#define WIN_SIZE  200
#define F_SIZE 200

double angle = 0;

window::window(string name, int posX, int posY) {
	this->_name = name;

	glutInitWindowSize(WIN_SIZE, WIN_SIZE);
	glutInitWindowPosition(posX, posY);
	_id = glutCreateWindow(name.c_str());
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45.0, 1.0, 1.0, 20.0);
	glMatrixMode(GL_MODELVIEW);

}

window::~window() {

}

/**
 *  Display callback function.
 */
void window::display() {

	glutSetWindow(_id);
	glClear(GL_COLOR_BUFFER_BIT);
	glLoadIdentity();

	if (_id == 1)
		gluLookAt(5.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
	else if (_id == 2)
		gluLookAt(0.0, 5.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
	else if (_id == 3)
		gluLookAt(5.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

	// Draw the cube, rotated and scaled.
	glPushMatrix();
	glTranslatef(-1.0, 0.0, 0.0);
	if (_id == 2) {
		glRotatef(360.0 * _x, 1.0, 0.0, 0.0);
		glRotatef(360.0 * _y, 0.0, 1.0, 0.0);
	}
	glRotatef(angle, 0.0, 0.0, 1.0);
	//glScalef(x1 + 1.0, y1 + 1.0, 1.0);
	glColor3f(0.8f, 0.0f, 0.8f);
	glutWireCube(2.0);
	glPopMatrix();

	// Draw thre cone, rotated and scaled.
	glPushMatrix();
	glTranslatef(1.0, 0.0, 0.0);
	if (_id == 1) {
		glRotatef(360.0 * _x, 1.0, 0.0, 0.0);
		glRotatef(360.0 * _y, 0.0, 1.0, 0.0);
	}
	if (_id == 3) {
		glScalef(this->_x + 1.0, this->_y + 1.0, 1.0);
	}
	glTranslatef(0.0, 0.0, -1.0);
	glColor3f(0.0f, 0.8f, 0.8f);
	glutWireCone(1.0, 3.0, 10, 10);
	glPopMatrix();
	glutSwapBuffers();

}

void window::spin() {
	angle += 1;
	if (angle > 360)
		angle -= 360;
	this->refresh();
}

void window::refresh() {
	glutSetWindow(_id);
	glutPostRedisplay();
}

void window::mouse(int x, int y) {
	this->_x = (float) x / (float) F_SIZE;
	this->_y = (float) y / (float) F_SIZE;
}

void window::idle() {
	spin();
}

window.cpp

#ifndef WINDOW_H_
#include <string>
#include <GL/glut.h>
#define WINDOW_H_

using namespace std;

class window {
	int _id;
	string _name;
	GLfloat _x, _y;

public:
	window(string name, int posX, int posY);
	virtual ~window();

	void display();
	void refresh();
	void spin();
	void mouse(int x, int y);
	void idle();
};

#endif /* WINDOW_H_ */