I am writing a prototype for something at work. Not very many people here know much about Linux/Unix or Xlib, so I can't really ask here at work (most developers are expert Windows programmers). With this said, I have one class and a driver that I would like feedback on how well I have integrated threads, XLib and OpenGL.
The order of the files below is:
- glx_data.h
- linux_main.cpp
- map.h
- map.cpp
- Makefile
// 1. glx_data.h
#ifndef GLX_DATA_
#define GLX_DATA_
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <X11/Xlib.h>
#include <GL/glx.h>
#include <GL/gl.h>
#include <GL/glu.h>
typedef
struct glx_data
{
Display *dpy;
Window win;
XVisualInfo *vi;
Colormap cmap;
XSetWindowAttributes swa;
GLXContext cx;
XEvent event;
int dummy;
bool double_buffer;
} GLXDATA;
#endif//GLX_DATA
linux_main.cpp
#include "glx_data.h"
#include "map.h"
static int snglBuf[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1, GLX_DEPTH_SIZE, 12, None };
static int dblBuf[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1, GLX_DEPTH_SIZE, 12,
GLX_DOUBLEBUFFER, None };
//Global Data
static Map *gsp_Map;
static GLXDATA glxdata;
bool init_instance() {
glxdata.dpy = XOpenDisplay(NULL);
if (glxdata.dpy == NULL) {
fprintf(stderr, "Failed to get XDisplay\n");
return false;
}
if (!glXQueryExtension( glxdata.dpy,
&glxdata.dummy,
&glxdata.dummy)) {
fprintf(stderr, "X server has no OpenGL GLX extension");
return false;
}
glxdata.vi = glXChooseVisual( glxdata.dpy,
DefaultScreen(glxdata.dpy),
dblBuf);
if (NULL == glxdata.vi) {
glxdata.vi = glXChooseVisual( glxdata.dpy,
DefaultScreen(glxdata.dpy),
snglBuf
);
if (NULL == glxdata.vi) {
fprintf(stderr, "No RGB visual with depth buffer");
return false;
}
glxdata.double_buffer = false;
} else {
glxdata.double_buffer = true;
}
glxdata.cmap = XCreateColormap( glxdata.dpy,
RootWindow(
glxdata.dpy,
(glxdata.vi)->screen
),
(glxdata.vi)->visual,
AllocNone);
glxdata.swa.colormap = glxdata.cmap;
glxdata.swa.border_pixel = 0;
glxdata.swa.event_mask = ExposureMask | ButtonPressMask |
StructureNotifyMask;
glxdata.win = XCreateWindow( glxdata.dpy,
RootWindow(
glxdata.dpy,
(glxdata.vi)->screen
),
0, 0,
300, 300,
0,
(glxdata.vi)->depth,
InputOutput,
(glxdata.vi)->visual,
CWBorderPixel | CWColormap |
CWEventMask,
&glxdata.swa
);
XSetStandardProperties(
glxdata.dpy,
glxdata.win,
"glxsimple",
"glxsimple",
None,
NULL,
0,
NULL
);
/*
* After window is set and glx context configured
* Note that we have not created the glx context yet
*/
gsp_Map = new Map(&glxdata, 300, 300);
/*
* Now we can show the window and go to main message loop
*/
XMapWindow(glxdata.dpy, glxdata.win);
return true;
}
void
message_loop()
{
while (1) {
do {
XNextEvent(glxdata.dpy, &glxdata.event);
switch (glxdata.event.type) {
case ButtonPress:
switch (glxdata.event.xbutton.button) {
case 1:
gsp_Map->inc_xrotate(10);
gsp_Map->set_update(true);
break;
case 2:
gsp_Map->inc_yrotate(10);
gsp_Map->set_update(true);
break;
case 3:
gsp_Map->inc_zrotate(10);
gsp_Map->set_update(true);
break;
}
break;
case ConfigureNotify:
gsp_Map->set_deminsions(
glxdata.event.xconfigure.width,
glxdata.event.xconfigure.height
);
case Expose:
gsp_Map->set_update(true);
break;
}
} while (XPending(glxdata.dpy));
}
pthread_join(gsp_Map->get_pthread(), NULL);
}
int
main(int argc, char *argv[]) {
if (!init_instance()) {
fprintf(stderr, "Failed to initialize application instance\n");
}
message_loop();
if(gsp_Map) {
delete gsp_Map;
}
}
map.h
#ifndef MAP_H_
#define MAP_H_
#include "glx_data.h"
class Map
{
public:
Map();
Map(Map ©);
Map(GLXDATA *glxdata, int width, int height);
~Map();
inline pthread_t &get_pthread() {return m_render_thread;}
inline void set_update(bool update) {m_update = update;}
inline void inc_xrotate(GLfloat deg)
{
if ((m_xAngle + deg) < 360) {
m_xAngle += deg;
} else {
m_xAngle = deg - (360 - m_xAngle);
}
}
inline void inc_yrotate(GLfloat deg)
{
if ((m_yAngle + deg) < 360) {
m_yAngle += deg;
} else {
m_yAngle = deg - (360 - m_yAngle);
}
}
inline void inc_zrotate(GLfloat deg)
{
if ((m_zAngle + deg) < 360) {
m_zAngle += deg;
} else {
m_zAngle = deg - (360 - m_zAngle);
}
}
inline void set_deminsions(int width, int height)
{
m_width = width;
m_height = height;
}
void render_data();
private:
GLXDATA *m_pglxdata;
pthread_t m_render_thread;
bool m_render;
bool m_update;
bool m_update_viewport;
int m_width;
int m_height;
GLfloat m_xAngle;
GLfloat m_yAngle;
GLfloat m_zAngle;
static void *create_pthread(void *data)
{
Map *thread_map = static_cast<Map *>(data);
thread_map->render_data();
return data;
}
};
#endif//MAP_H_
map.cpp
#include "map.h"
Map::Map()
{
}
Map::Map(Map ©)
{
}
Map::Map(GLXDATA *glxdata, int width, int height)
{
m_width = width;
m_height = height;
m_render = true;
m_update = true;
m_update_viewport = true;
m_xAngle = 42.0;
m_yAngle = 82.0;
m_zAngle = 112.0;
this->m_pglxdata = glxdata;
pthread_create(&m_render_thread, NULL, Map::create_pthread, this);
}
void Map::render_data()
{
m_pglxdata->cx = glXCreateContext(
m_pglxdata->dpy,
m_pglxdata->vi,
None,
True
);
if (NULL == m_pglxdata->cx) {
fprintf(stderr, "could not create rendering context");
return;
}
glXMakeCurrent(m_pglxdata->dpy, m_pglxdata->win, m_pglxdata->cx);
static Bool displayListInited = false;
glEnable(GL_DEPTH_TEST);
while(m_render) {
if(m_update_viewport) {
glViewport(0, 0, m_width, m_height);
m_update_viewport = false;
m_update = true;
}
if(m_update) {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, 1, 1, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -3.0);
glRotatef(m_xAngle, 0.1, 0.0, 0.0);
glRotatef(m_yAngle, 0.0, 1.0, 0.0);
glRotatef(m_zAngle, 0.0, 0.0, 1.0);
if (displayListInited) {
glCallList(1);
} else {
glNewList(1, GL_COMPILE_AND_EXECUTE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_QUADS);
// Front face
glColor3f(0.0, 0.7, 0.1); // Green
glVertex3f(-1.0, 1.0, 1.0);
glVertex3f(1.0, 1.0, 1.0);
glVertex3f(1.0, -1.0, 1.0);
glVertex3f(-1.0, -1.0, 1.0);
// Back face
glColor3f(0.9, 1.0, 0.0); // Yellow
glVertex3f(-1.0, 1.0, -1.0);
glVertex3f(1.0, 1.0, -1.0);
glVertex3f(1.0, -1.0, -1.0);
glVertex3f(-1.0, -1.0, -1.0);
// Top face
glColor3f(0.2, 0.2, 1.0); // Blue
glVertex3f(-1.0, 1.0, 1.0);
glVertex3f(1.0, 1.0, 1.0);
glVertex3f(1.0, 1.0, -1.0);
glVertex3f(-1.0, 1.0, -1.0);
// Bottom face
glColor3f(0.7, 0.0, 0.1); // Red
glVertex3f(-1.0, -1.0, 1.0);
glVertex3f(1.0, -1.0, 1.0);
glVertex3f(1.0, -1.0, -1.0);
glVertex3f(-1.0, -1.0, -1.0);
glEnd();
glEndList();
displayListInited = true;
}
if (m_pglxdata->double_buffer) {
glXSwapBuffers(m_pglxdata->dpy, m_pglxdata->win);
} else {
glFlush();
}
m_update = false;
}
}
}
Map::~Map()
{
}
Makefile
all : linux_main
linux_main : map.o linux_main.o
g++ -pthread -Wall linux_main.o map.o -o linux_main -lGL -lXext -lX11 -lGLU
linux_main.o : linux_main.cpp
g++ -pthread -Wall -c -o linux_main.o linux_main.cpp
map.o : map.cpp
g++ -pthread -Wall -c -o map.o map.cpp
clean :
rm -f ./*.o linux_main