-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.C
255 lines (225 loc) · 8.18 KB
/
main.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
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include "glext.h"
#include "glxext.h"
#include "config.h"
#include "Cube.h"
#include "Stopwatch.h"
// Helper to check for extension string presence. Adapted from:
// http://www.opengl.org/resources/features/OGLextensions/
// 'extList' is a string containing all extension strings, separated by spaces.
// 'extension' is a string containing the extension string being queried.
static bool isExtensionSupported(const char *extList, const char *extension) {
const char *start;
const char *where, *terminator;
// Extension names do not contain spaces.
// Make sure an extension name is surrounded
// by spaces, or is at the beginning or end of
// the list of extensions.
where = strchr(extension, ' ');
if ( where || *extension == '\0' )
return false;
for ( start = extList; ; ) {
where = strstr( start, extension );
if ( !where )
break;
terminator = where + strlen( extension );
if ((where == start || *(where - 1) == ' ') &&
(*terminator == ' ' || *terminator == '\0'))
return true;
start = terminator;
}
return false;
}
// Helper function to gracefully handle context creation errors.
// NOTE: This handler is not thread-safe!
static bool ctxErrorOccurred = false;
static int ctxErrorHandler( Display *dpy, XErrorEvent *ev )
{
ctxErrorOccurred = true;
return 0;
}
int main (int argc, char ** argv) {
// Get a reference to the display.
Display *display = XOpenDisplay(0);
if (!display) {
fprintf(stderr, "ERROR: Failed to open X display\n");
exit(1);
}
// Identify the "best" framebuffer config that meets minimum requirements.
// First, specify the minimum requirements in visual_attribs.
// Next, identify the "best" one meeting requirements, in this case the "best"
// has the most number of samples per pixel.
// Finally, store a reference to the "best", and free the storage for others.
static 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,
None
};
int fbcount = 0;
int best_fbc = -1;
int best_num_samp = -1;
GLXFBConfig *fbc = glXChooseFBConfig(display, DefaultScreen(display), visual_attribs, &fbcount);
if (!fbc) {
fprintf(stderr, "ERROR: Failed to retrieve a framebuffer config.\n");
exit(1);
}
for (int i = 0; i < fbcount; ++i) {
XVisualInfo *vi = glXGetVisualFromFBConfig(display, fbc[i]);
if (vi) {
int samp_buf, samples;
glXGetFBConfigAttrib(display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
glXGetFBConfigAttrib(display, fbc[i], GLX_SAMPLES, &samples );
if (best_fbc < 0 || (samp_buf && samples > best_num_samp)) {
best_fbc = i;
best_num_samp = samples;
}
XFree(vi);
vi = 0;
}
}
GLXFBConfig bestFbc = fbc[best_fbc];
XFree(fbc);
fbc = 0;
XVisualInfo *vi = glXGetVisualFromFBConfig(display, bestFbc);
fprintf(stderr, "INFO: Using visualID = 0x%x\n", (unsigned int)vi->visualid);
// Create a colormap and window.
XSetWindowAttributes swa;
Colormap cmap;
swa.colormap = cmap = XCreateColormap
(display, RootWindow(display, vi->screen), vi->visual, AllocNone);
swa.background_pixmap = None;
swa.border_pixel = 0;
swa.event_mask = StructureNotifyMask;
Window win = XCreateWindow
(display, RootWindow(display, vi->screen),
0, 0, RENDER_WIDTH, RENDER_HEIGHT, 0, vi->depth,
InputOutput, vi->visual, CWBorderPixel|CWColormap|CWEventMask, &swa);
if (!win) {
fprintf(stderr, "ERROR: Failed to create the window.\n");
exit(1);
}
XFree(vi);
vi = 0;
// Set the window name, and make it active.
XStoreName(display, win, "GL 4.0 Window");
XMapWindow(display, win);
// Get the default screen's GLX extension list
const char *glxExts = glXQueryExtensionsString(display, DefaultScreen(display));
// Install an X error handler so the application won't exit if context
// creation fails. Note that the error handler is not thread safe, so don't
// allow other threads to interact with X until the handler is uninstalled.
ctxErrorOccurred = false;
int (*oldHandler)(Display*, XErrorEvent*) = XSetErrorHandler(&ctxErrorHandler);
// TODO where better to put this?
GLXContext ctx = 0;
// Check for the GLX_ARB_create_context extension string and corresponding function.
// If either is not present, use GLX 1.3 context creation method.
// glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
// glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)
// glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" );
if (!isExtensionSupported(glxExts, "GLX_ARB_create_context")) {
fprintf(stderr, "WARNING: glXCreateContextAttribsARB() not found. Failing back to compatibility.\n");
ctx = glXCreateNewContext(display, bestFbc, GLX_RGBA_TYPE, 0, True);
}
// If it does, try to get a core GL context!
else {
int context_attribs[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, 4,
GLX_CONTEXT_MINOR_VERSION_ARB, 0,
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
None
};
ctx = glXCreateContextAttribsARB(display, bestFbc, 0, True, context_attribs);
// Sync to ensure any errors generated are processed.
XSync(display, False);
if (ctxErrorOccurred || !ctx) {
// Couldn't create a core GL context. Fall back to old-style 2.x context.
// When a context version below 4.0 is requested, implementations will
// return the newest context version compatible with OpenGL versions less
// than version 4.0.
// GLX_CONTEXT_MAJOR_VERSION_ARB = 1
context_attribs[1] = 1;
// GLX_CONTEXT_MINOR_VERSION_ARB = 0
context_attribs[3] = 0;
// Do not force a core context.
context_attribs[4] = None;
ctxErrorOccurred = false;
fprintf(stderr, "WARNING: Failed to create core GL context. Failing back to compatibility.\n");
ctx = glXCreateContextAttribsARB(display, bestFbc, 0, True, context_attribs);
}
}
XSync(display, False);
// Restore the original error handler.
XSetErrorHandler(oldHandler);
if (ctxErrorOccurred || !ctx) {
fprintf(stderr, "ERROR: Failed to create an OpenGL context.\n");
exit(1);
}
// Print out info on the context retrieved.
bool warn = false;
char status[8];
char direct[9];
char profile[14];
GLint profileMask;
glXMakeCurrent(display, win, ctx);
if (!glXIsDirect(display, ctx)) {
warn = true;
snprintf(direct, 9, "INDIRECT");
}
else
snprintf(direct, 9, "DIRECT");
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profileMask);
if (profileMask & GL_CONTEXT_CORE_PROFILE_BIT)
snprintf(profile, 14, "CORE");
else {
warn = true;
snprintf(profile, 14, "COMPATIBILITY");
}
if (warn)
snprintf(status, 8, "WARNING");
else
snprintf(status, 8, "INFO");
fprintf(stderr, "%s: GL context is %s %s profile version \'%s\'.\n",
status, direct, profile, glGetString(GL_VERSION));
//---------------------------------------------------------------------------
// INITIALIZATION IS COMPLETE
// OPENGL CODE GOES BELOW
//---------------------------------------------------------------------------
Cube cube;
Stopwatch stopwatch;
float secondsElapsed = 0.0f;
while (true) {
secondsElapsed = stopwatch.secondsElapsed();
stopwatch.start();
// Draw the scene.
cube.render(secondsElapsed);
glXSwapBuffers (display, win);
}
//---------------------------------------------------------------------------
// RENDERING IS COMPLETE
// OPENGL CODE GOES ABOVE
//---------------------------------------------------------------------------
// Destroy context
glXMakeCurrent( display, 0, 0 );
glXDestroyContext( display, ctx );
XDestroyWindow( display, win );
XFreeColormap( display, cmap );
XCloseDisplay( display );
}