Found that you have to manually get some references ie see EarlyInitGLXfnPointers(). Here’s an example code that works …
// Block.cpp
// OpenGL SuperBible, Chapter 15
// Demonstrates an assortment of basic 3D concepts
// Program by Richard S. Wright Jr.
// modified to demonstrate just opening a GL context/window
// g++ main.cpp -lGL -lGLEW
#include <GL/glew.h>
#include <GL/glxew.h>
#include <cstdio>
#include <cmath>
#include <cstdlib>
GLuint vao;
size_t VertexArrayCount;
/////////////////////////////////////////////////////////////////////////////////
void EarlyInitGLXfnPointers()
{
glXCreateContextAttribsARB = (GLXContext(*)(Display* dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list))glXGetProcAddressARB((GLubyte*)"glXCreateContextAttribsARB");
glXChooseFBConfig = (GLXFBConfig*(*)(Display *dpy, int screen, const int *attrib_list, int *nelements))glXGetProcAddressARB((GLubyte*)"glXChooseFBConfig");
glXGetVisualFromFBConfig = (XVisualInfo*(*)(Display *dpy, GLXFBConfig config))glXGetProcAddressARB((GLubyte*)"glXGetVisualFromFBConfig");
}
typedef struct RenderContextRec
{
GLXContext ctx;
Display *dpy;
Window win;
int nWinWidth;
int nWinHeight;
} RenderContext;
void CreateWindow(RenderContext *rcx)
{
XSetWindowAttributes winAttribs;
GLint winmask;
GLint nMajorVer = 0;
GLint nMinorVer = 0;
XVisualInfo *visualInfo;
GLXFBConfig *fbConfigs;
int numConfigs = 0;
static int fbAttribs[] = {
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_X_RENDERABLE, True,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_DOUBLEBUFFER, True,
GLX_RED_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_GREEN_SIZE, 8,
0 };
// Tell X we are going to use the display
rcx->dpy = XOpenDisplay(NULL);
// Get Version info
glXQueryVersion(rcx->dpy, &nMajorVer, &nMinorVer);
printf("Supported GLX version - %d.%d
", nMajorVer, nMinorVer);
if(nMajorVer == 1 && nMinorVer < 2)
{
printf("ERROR: GLX 1.2 or greater is necessary
");
XCloseDisplay(rcx->dpy);
exit(0);
}
// Get a new fb config that meets our attrib requirements
fbConfigs = glXChooseFBConfig(rcx->dpy, DefaultScreen(rcx->dpy), fbAttribs, &numConfigs);
visualInfo = glXGetVisualFromFBConfig(rcx->dpy, fbConfigs[0]);
// Now create an X window
winAttribs.event_mask = ExposureMask | VisibilityChangeMask |
KeyPressMask | PointerMotionMask |
StructureNotifyMask ;
winAttribs.border_pixel = 0;
winAttribs.bit_gravity = StaticGravity;
winAttribs.colormap = XCreateColormap(rcx->dpy,
RootWindow(rcx->dpy, visualInfo->screen),
visualInfo->visual, AllocNone);
winmask = CWBorderPixel | CWBitGravity | CWEventMask| CWColormap;
rcx->win = XCreateWindow(rcx->dpy, DefaultRootWindow(rcx->dpy), 20, 20,
rcx->nWinWidth, rcx->nWinHeight, 0,
visualInfo->depth, InputOutput,
visualInfo->visual, winmask, &winAttribs);
XMapWindow(rcx->dpy, rcx->win);
// Also create a new GL context for rendering
GLint attribs[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 1,
GLX_CONTEXT_PROFILE_MASK_ARB,GLX_CONTEXT_CORE_PROFILE_BIT_ARB, // added, required to get above 3.1
0 };
rcx->ctx = glXCreateContextAttribsARB(rcx->dpy, fbConfigs[0], 0, True, attribs);
glXMakeCurrent(rcx->dpy, rcx->win, rcx->ctx);
GLenum err = glewInit();
if (GLEW_OK != err)
{
/* Problem: glewInit failed, something is seriously wrong. */
fprintf(stderr, "Error: %s
", glewGetErrorString(err));
}
}
void SetupRC(RenderContext *rcx)
{
const GLubyte * strVersion = glGetString(GL_VERSION);
printf("%s
",strVersion);
//Create shaders and shader program
GLuint vshader(glCreateShader(GL_VERTEX_SHADER));
GLuint fshader(glCreateShader(GL_FRAGMENT_SHADER));
GLuint program(glCreateProgram());
const GLchar *vshader_source[] =
{
"#version 150 core
"
"
"
"in vec3 vert;
"
"
"
"void main() {
"
" gl_Position=vec4(vert,1.);
"
"}
"
"
"
};
glShaderSource(vshader,1,vshader_source,NULL);
const GLchar *fshader_source[] =
{
"#version 150 core
"
"out vec4 fragcolor;
"
"
"
"void main() {
"
"
"
" fragcolor=vec4(0.0f,0.0f,1.0f,0.0f);
"
"}
"
"
"
};
glShaderSource(fshader,1,fshader_source,NULL);
glCompileShader(vshader);
glCompileShader(fshader);
glAttachShader(program,vshader);
glAttachShader(program,fshader);
glLinkProgram(program);
glUseProgram(program);
//Get handles to shader uniforms
//... none for this simple vert/frag shader
//Datas destioned for video memory, can be local (and lost after bound to GPU!).
#define R 0.9
GLfloat vertices[] = { // in vec3 vert;
-R, R, 0.0, // xyz
-R, -R, 0.0,
R, R, 0.0,
R, -R, 0.0
};
VertexArrayCount=sizeof(vertices)/sizeof(GLfloat)/3; // 3 for {x y z}
//Create geometry vertex array using Model definition
glGenVertexArrays(1,&vao);
glBindVertexArray(vao);
//in vec3 vert;
GLuint bon_vert; // buffer object name
glGenBuffers(1,&bon_vert);
glBindBuffer(GL_ARRAY_BUFFER,bon_vert);
glBufferData(GL_ARRAY_BUFFER,sizeof(GLfloat)*3*VertexArrayCount,vertices,GL_STATIC_DRAW);
const GLint loc_vert(glGetAttribLocation(program,"vert"));
glVertexAttribPointer(loc_vert,3,GL_FLOAT,GL_TRUE,0,NULL);
glEnableVertexAttribArray(loc_vert);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
}
void RenderScene(RenderContext *rcx)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLE_STRIP,0,VertexArrayCount);
// Flush drawing commands
glXSwapBuffers(rcx->dpy, rcx->win);
}
void KeyPressFunc(unsigned char key)
{
switch( key )
{
default: exit(0); break;
}
}
void ChangeSize(int w, int h)
{
glViewport(0, 0, w, h);
}
void Cleanup(RenderContext *rcx)
{
// Unbind the context before deleting
glXMakeCurrent(rcx->dpy, None, NULL);
glXDestroyContext(rcx->dpy, rcx->ctx);
rcx->ctx = NULL;
XDestroyWindow(rcx->dpy, rcx->win);
rcx->win = (Window)NULL;
XCloseDisplay(rcx->dpy);
rcx->dpy = 0;
}
///////////////////////////////////////////////////////////////////////////////
// Main entry point
int main(int argc, char* argv[])
{
EarlyInitGLXfnPointers();
// Setup X window and GLX context
// Set initial window size
RenderContext rcx;
rcx.nWinWidth = 800;
rcx.nWinHeight = 600;
CreateWindow(&rcx);
SetupRC(&rcx);
ChangeSize(rcx.nWinWidth, rcx.nWinHeight);
// Draw the first frame before checking for messages
RenderScene(&rcx);
// Execute loop the whole time the app runs
Bool bWinMapped = False;
for(;;)
{
XEvent newEvent;
XWindowAttributes winData;
// Watch for new X events
XNextEvent(rcx.dpy, &newEvent);
switch(newEvent.type)
{
case UnmapNotify:
bWinMapped = False;
break;
case MapNotify :
bWinMapped = True;
case ConfigureNotify:
XGetWindowAttributes(rcx.dpy, rcx.win, &winData);
rcx.nWinHeight = winData.height;
rcx.nWinWidth = winData.width;
ChangeSize(rcx.nWinWidth, rcx.nWinHeight);
break;
case KeyPress:
KeyPressFunc(newEvent.xkey.keycode);
break;
case DestroyNotify:
Cleanup(&rcx);
exit(0);
break;
}
if(bWinMapped)
{
RenderScene(&rcx);
}
}
Cleanup(&rcx);
return 0;
}
note to get a 4.0 context on nvidia 465 in linux had to change code to
// Also create a new GL context for rendering
GLint attribs[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, 4,
GLX_CONTEXT_MINOR_VERSION_ARB, 0,
GLX_CONTEXT_PROFILE_MASK_ARB,GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, // added, required to get above 3.1
0 };