-
Notifications
You must be signed in to change notification settings - Fork 160
/
glx.c
303 lines (279 loc) · 9.93 KB
/
glx.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
/*
# GLX
http://stackoverflow.com/questions/879035/initializing-opengl-without-glut/36038230#36038230
Example without GLUT, but rather GLX which is what GLUT uses in Linux as backend:
https://www.opengl.org/discussion_boards/showthread.php/177999-GCC-OpenGL-without-glut?p=1239444&viewfull=1#post1239444
GLX is the X11 API that interfaces with OpenGL.
Requires -lGL -lGLU -lX11.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/time.h>
#define GL_GLEXT_PROTOTYPES
#define GLX_GLXEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glx.h>
struct MyWin {
Display *display;
Window win;
int displayed;
int width;
int height;
};
const int WIN_XPOS = 256;
const int WIN_YPOS = 64;
const int WIN_XRES = 320;
const int WIN_YRES = 320;
const int NUM_SAMPLES = 4;
struct MyWin Win;
double elapsedMsec(const struct timeval *start, const struct timeval *stop) {
return ((stop->tv_sec - start->tv_sec ) * 1000.0 +
(stop->tv_usec - start->tv_usec) / 1000.0);
}
void displayCB() {
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glBegin(GL_TRIANGLES);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3f( 0.0f, 1.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f);
glVertex3f( 1.0f, -1.0f, 0.0f);
glEnd();
glFlush();
glXSwapBuffers(Win.display, Win.win);
}
void keyboardCB(KeySym sym, unsigned char key, int x, int y,
int *setting_change) {
switch (tolower(key)) {
case 27:
exit(EXIT_SUCCESS);
break;
case 'k':
printf("You hit the 'k' key\n");
break;
case 0:
switch (sym) {
case XK_Left :
printf("You hit the Left Arrow key\n");
break;
case XK_Right :
printf("You hit the Right Arrow key\n");
break;
}
break;
}
}
void reshapeCB(int width, int height) {
Win.width = width;
Win.height = height;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
glMatrixMode(GL_MODELVIEW);
}
/* Try to find a framebuffer config that matches
* the specified pixel requirements.
*/
GLXFBConfig chooseFBConfig(Display *display, int screen) {
static const int Visual_attribs[] = {
GLX_X_RENDERABLE , True,
GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT,
GLX_RENDER_TYPE , GLX_RGBA_BIT,
GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR,
GLX_RED_SIZE , 8,
GLX_GREEN_SIZE , 8,
GLX_BLUE_SIZE , 8,
GLX_ALPHA_SIZE , 8,
GLX_DEPTH_SIZE , 24,
GLX_STENCIL_SIZE , 8,
GLX_DOUBLEBUFFER , True,
GLX_SAMPLE_BUFFERS, 1,
GLX_SAMPLES , 4,
None
};
int attribs [ 100 ] ;
memcpy(attribs, Visual_attribs, sizeof(Visual_attribs));
GLXFBConfig ret = 0;
int fbcount;
GLXFBConfig *fbc = glXChooseFBConfig(display, screen, attribs, &fbcount);
if (fbc) {
if (fbcount >= 1)
ret = fbc[0];
XFree(fbc);
}
return ret;
}
GLXContext createContext(Display *display, int screen,
GLXFBConfig fbconfig, XVisualInfo *visinfo, Window window) {
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*,
GLXFBConfig, GLXContext, int, const int*);
/* Verify GL driver supports glXCreateContextAttribsARB() */
/* Create an old-style GLX context first, to get the correct function ptr. */
glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
GLXContext ctx_old = glXCreateContext(display, visinfo, 0, True);
if (!ctx_old) {
printf("Could not even allocate an old-style GL context!\n");
exit(EXIT_FAILURE);
}
glXMakeCurrent (display, window, ctx_old) ;
/* Verify that GLX implementation supports the new context create call */
if (strstr(glXQueryExtensionsString(display, screen),
"GLX_ARB_create_context") != 0)
glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)
glXGetProcAddress((const GLubyte *) "glXCreateContextAttribsARB");
if (!glXCreateContextAttribsARB) {
printf("Can't create new-style GL context\n");
exit(EXIT_FAILURE);
}
/* Got the pointer. Nuke old context. */
glXMakeCurrent(display, None, 0);
glXDestroyContext(display, ctx_old);
/* Try to allocate a GL 4.2 COMPATIBILITY context */
static int Context_attribs[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, 4,
GLX_CONTEXT_MINOR_VERSION_ARB, 2,
GLX_CONTEXT_PROFILE_MASK_ARB , GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
/*GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, */
/*GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, */
/*GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_DEBUG_BIT_ARB, */
None
};
GLXContext context = glXCreateContextAttribsARB(display, fbconfig, 0,
True, Context_attribs);
/* Forcably wait on any resulting X errors */
XSync(display, False);
if (!context) {
printf("Failed to allocate a GL 4.2 context\n");
exit(EXIT_FAILURE);
}
printf("Created GL 4.2 context\n");
return context;
}
void createWindow() {
/* Init X and GLX */
Win.displayed = 0;
Display *display = Win.display = XOpenDisplay(":0.0");
if (!display)
printf("Cannot open X display\n");
int screen = DefaultScreen(display);
Window root_win = RootWindow(display, screen);
if (!glXQueryExtension(display, 0, 0))
printf("X Server doesn't support GLX extension\n");
/* Pick an FBconfig and visual */
GLXFBConfig fbconfig = chooseFBConfig(display, screen);
if (!fbconfig) {
printf("Failed to get GLXFBConfig\n");
exit(EXIT_FAILURE);
}
XVisualInfo *visinfo = glXGetVisualFromFBConfig(display, fbconfig);
if (!visinfo) {
printf("Failed to get XVisualInfo\n");
exit(EXIT_FAILURE);
}
printf("X Visual ID = 0x%.2x\n", (int)visinfo->visualid);
/* Create the X window */
XSetWindowAttributes winAttr ;
winAttr.event_mask = StructureNotifyMask | KeyPressMask ;
winAttr.background_pixmap = None ;
winAttr.background_pixel = 0 ;
winAttr.border_pixel = 0 ;
winAttr.colormap = XCreateColormap(display, root_win,
visinfo->visual, AllocNone);
unsigned int mask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
Window win = Win.win = XCreateWindow (display, root_win,
WIN_XPOS, WIN_YPOS,
WIN_XRES, WIN_YRES, 0,
visinfo->depth, InputOutput,
visinfo->visual, mask, &winAttr) ;
XStoreName(Win.display, win, "My GLX Window");
/* Create an OpenGL context and attach it to our X window */
GLXContext context = createContext(display, screen, fbconfig, visinfo, win);
if (! glXMakeCurrent(display, win, context))
printf("glXMakeCurrent failed.\n");
if (! glXIsDirect (display, glXGetCurrentContext()))
printf("Indirect GLX rendering context obtained\n");
/* Display the window */
XMapWindow(display, win);
if (! glXMakeCurrent(display, win, context))
printf("glXMakeCurrent failed.\n");
printf("Window Size = %d x %d\n", WIN_XRES, WIN_YRES);
printf("Window Samples = %d\n", NUM_SAMPLES);
}
void processXEvents(Atom wm_protocols, Atom wm_delete_window) {
int setting_change = 0;
while (XEventsQueued(Win.display, QueuedAfterFlush)) {
XEvent event;
XNextEvent(Win.display, &event);
if(event.xany.window != Win.win)
continue;
switch (event.type) {
case MapNotify:
{
Win.displayed = 1;
break;
}
case ConfigureNotify:
{
XConfigureEvent cevent = event.xconfigure;
reshapeCB(cevent.width, cevent.height);
break;
}
case KeyPress:
{
char chr;
KeySym symbol;
XComposeStatus status;
XLookupString(&event.xkey, &chr, 1, &symbol, &status);
keyboardCB(symbol, chr, event.xkey.x, event.xkey.y,
&setting_change);
break;
}
case ClientMessage:
{
if (event.xclient.message_type == wm_protocols &&
(Atom)event.xclient.data.l[0] == wm_delete_window) {
exit(EXIT_SUCCESS);
}
break;
}
}
}
}
void mainLoop() {
/* Register to receive window close events (the "X" window manager button) */
Atom wm_protocols = XInternAtom(Win.display, "WM_PROTOCOLS" , False);
Atom wm_delete_window = XInternAtom(Win.display, "WM_DELETE_WINDOW", False);
XSetWMProtocols(Win.display, Win.win, &wm_delete_window, True);
while (1) {
/* Redraw window (after it's mapped) */
if (Win.displayed)
displayCB();
/* Update frame rate */
struct timeval last_xcheck = {0, 0};
struct timeval now;
gettimeofday(&now, 0);
/* Check X events every 1/10 second */
if (elapsedMsec(&last_xcheck, &now) > 100) {
processXEvents(wm_protocols, wm_delete_window);
last_xcheck = now;
}
}
}
int main(int argc, char *argv[]) {
Win.width = WIN_XRES;
Win.height = WIN_YRES;
createWindow();
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
printf("Valid keys: Left, Right, k, ESC\n");
printf("Press ESC to quit\n");
mainLoop();
return EXIT_SUCCESS;
}