| #include "X11OpenGLWindow.h" |
| #include "OpenGLInclude.h" |
| |
| #include<stdio.h> |
| #include<stdlib.h> |
| #ifdef GLEW_STATIC |
| #include "CustomGL/glew.h" |
| #else |
| #include <GL/glew.h> |
| #endif//GLEW_STATIC |
| |
| #ifdef GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS |
| #include "CustomGL/glxew.h" |
| #else |
| #include<GL/glx.h> |
| #endif // GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS |
| #include <assert.h> |
| |
| //#define DYNAMIC_LOAD_X11_FUNCTIONS |
| #ifdef DYNAMIC_LOAD_X11_FUNCTIONS |
| #include <dlfcn.h> |
| #endif //DYNAMIC_LOAD_X11_FUNCTIONS |
| |
| //#include<X11/X.h> |
| //#include<X11/Xlib.h> |
| //#include<GL/gl.h> |
| |
| //defined in GL/glxew.h |
| //#include<GL/glu.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| |
| #include <pthread.h> |
| |
| GLint att[] = { GLX_RGBA, |
| GLX_DEPTH_SIZE, 24, |
| GLX_RED_SIZE , 8, |
| GLX_GREEN_SIZE , 8, |
| GLX_BLUE_SIZE , 8, |
| GLX_ALPHA_SIZE , 8, |
| GLX_STENCIL_SIZE , 8, |
| GLX_DOUBLEBUFFER, |
| None }; |
| /* |
| static int att[] = |
| { |
| GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None |
| |
| 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 |
| }; |
| */ |
| static bool forceOpenGL3 = true; |
| |
| |
| |
| #ifdef DYNAMIC_LOAD_X11_FUNCTIONS |
| |
| ///our X11 function typedefs |
| |
| typedef int (*PFNXFREE)(void*); |
| typedef XErrorHandler (* PFNXSETERRORHANDLER) (XErrorHandler); |
| typedef int (* PFNXSYNC) (Display* a,Bool b); |
| typedef Display* (* PFNXOPENDISPLAY) (_Xconst char* a); |
| typedef Colormap (*PFNXCREATECOLORMAP) (Display* a,Window b,Visual* c,int d); |
| typedef Window (*PFNXCREATEWINDOW) (Display* a,Window b,int c,int d,unsigned int e,unsigned int f,unsigned int g,int h,unsigned int i,Visual* j,unsigned long k,XSetWindowAttributes* l); |
| typedef int (*PFNXMAPWINDOW) (Display*, Window); |
| typedef int (*PFNXSTORENAME) (Display* a,Window b,_Xconst char* c); |
| typedef int (*PFNXCLOSEDISPLAY) (Display* a); |
| typedef int (*PFNXDESTROYWINDOW) (Display* a,Window b); |
| typedef int (*PFNXRAISEWINDOW) (Display* a, Window b); |
| |
| #if NeedWidePrototypes |
| typedef KeySym* (*PFNXGETKEYBOARDMAPPING) (Display*,unsigned int,int,int*); |
| typedef KeySym (*PFNXKEYCODETOKEYSYM) (Display* a,unsigned int b,int c); |
| #else |
| typedef KeySym* (*PFNXGETKEYBOARDMAPPING) (Display*,KeyCode,int,int*); |
| typedef KeySym (*PFNXKEYCODETOKEYSYM) (Display* a,KeyCode b,int c); |
| #endif |
| typedef void (*PFNXCONVERTCASE) (KeySym /* sym */,KeySym * /* lower */,KeySym * /* upper */); |
| typedef int (*PFNXPENDING) (Display* a); |
| typedef int (*PFNXNEXTEVENT) (Display* a,XEvent* b); |
| typedef int (*PFNXEVENTSQUEUED) (Display* a,int b); |
| typedef int (*PFNXPEEKEVENT) (Display* a,XEvent* b); |
| typedef KeySym (*PFNXLOOKUPKEYSYM) (XKeyEvent* a,int b); |
| typedef Status (*PFNXGETWINDOWATTRIBUTES) (Display* a,Window b,XWindowAttributes* c); |
| |
| #define X11_LIBRARY "libX11.so.6" |
| |
| #define MyXSync m_data->m_x11_XSync |
| #define MyXGetKeyboardMapping m_data->m_x11_XGetKeyboardMapping |
| #define MyXSetErrorHandler m_data->m_x11_XSetErrorHandler |
| #define MyXOpenDisplay m_data->m_x11_XOpenDisplay |
| #define MyXCreateColormap m_data->m_x11_XCreateColormap |
| #define MyXCreateWindow m_data->m_x11_XCreateWindow |
| #define MyXMapWindow m_data->m_x11_XMapWindow |
| #define MyXStoreName m_data->m_x11_XStoreName |
| #define MyXDestroyWindow m_data->m_x11_XDestroyWindow |
| #define MyXRaiseWindow m_data->m_x11_XRaiseWindow |
| #define MyXCloseDisplay m_data->m_x11_XCloseDisplay |
| #define MyXKeycodeToKeysym m_data->m_x11_XKeycodeToKeysym |
| #define MyXConvertCase m_data->m_x11_XConvertCase |
| #define MyXPending m_data->m_x11_XPending |
| #define MyXNextEvent m_data->m_x11_XNextEvent |
| #define MyXEventsQueued m_data->m_x11_XEventsQueued |
| #define MyXPeekEvent m_data->m_x11_XPeekEvent |
| #define MyXNextEvent m_data->m_x11_XNextEvent |
| #define MyXGetWindowAttributes m_data->m_x11_XGetWindowAttributes |
| #define MyXStoreName m_data->m_x11_XStoreName |
| #define MyXFree m_data->m_x11_XFree |
| #define MyXMapWindow m_data->m_x11_XMapWindow |
| #define MyXStoreName m_data->m_x11_XStoreName |
| #define MyXLookupKeysym m_data->m_x11_XLookupKeysym |
| |
| #else |
| #define MyXSync XSync |
| #define MyXGetKeyboardMapping XGetKeyboardMapping |
| #define MyXSetErrorHandler XSetErrorHandler |
| #define MyXOpenDisplay XOpenDisplay |
| #define MyXCreateColormap XCreateColormap |
| #define MyXCreateWindow XCreateWindow |
| #define MyXMapWindow XMapWindow |
| #define MyXStoreName XStoreName |
| #define MyXDestroyWindow XDestroyWindow |
| #define MyXRaiseWindow XRaiseWindow |
| #define MyXCloseDisplay XCloseDisplay |
| #define MyXKeycodeToKeysym XKeycodeToKeysym |
| #define MyXConvertCase XConvertCase |
| #define MyXPending XPending |
| #define MyXNextEvent XNextEvent |
| #define MyXEventsQueued XEventsQueued |
| #define MyXPeekEvent XPeekEvent |
| #define MyXNextEvent XNextEvent |
| #define MyXGetWindowAttributes XGetWindowAttributes |
| #define MyXStoreName XStoreName |
| #define MyXFree XFree |
| #define MyXMapWindow XMapWindow |
| #define MyXStoreName XStoreName |
| #define MyXLookupKeysym XLookupKeysym |
| |
| #endif//DYNAMIC_LOAD_X11_FUNCTIONS |
| |
| enum |
| { |
| MY_X11_ALT_KEY = 1, |
| MY_X11_SHIFT_KEY = 2, |
| MY_X11_CONTROL_KEY = 4 |
| }; |
| |
| struct InternalData2 |
| { |
| Display* m_dpy; |
| Window m_root; |
| XVisualInfo* m_vi; |
| Colormap m_cmap; |
| XSetWindowAttributes m_swa; |
| Window m_win; |
| GLXContext m_glc; |
| XWindowAttributes m_gwa; |
| XEvent m_xev; |
| GLXFBConfig m_bestFbc; |
| int m_modifierFlags; |
| int m_glWidth; |
| int m_glHeight; |
| |
| #ifdef DYNAMIC_LOAD_X11_FUNCTIONS |
| //dynamically load stuff |
| void* m_x11_library; |
| PFNXFREE m_x11_XFree; |
| PFNXSETERRORHANDLER m_x11_XSetErrorHandler; |
| PFNXSYNC m_x11_XSync; |
| PFNXOPENDISPLAY m_x11_XOpenDisplay; |
| PFNXCREATECOLORMAP m_x11_XCreateColormap; |
| PFNXCREATEWINDOW m_x11_XCreateWindow; |
| PFNXMAPWINDOW m_x11_XMapWindow; |
| PFNXSTORENAME m_x11_XStoreName; |
| PFNXCLOSEDISPLAY m_x11_XCloseDisplay; |
| PFNXDESTROYWINDOW m_x11_XDestroyWindow; |
| PFNXRAISEWINDOW m_x11_XRaiseWindow; |
| PFNXKEYCODETOKEYSYM m_x11_XKeycodeToKeysym; |
| PFNXGETKEYBOARDMAPPING m_x11_XGetKeyboardMapping; |
| PFNXCONVERTCASE m_x11_XConvertCase; |
| PFNXPENDING m_x11_XPending; |
| PFNXNEXTEVENT m_x11_XNextEvent; |
| PFNXEVENTSQUEUED m_x11_XEventsQueued; |
| PFNXPEEKEVENT m_x11_XPeekEvent; |
| PFNXLOOKUPKEYSYM m_x11_XLookupKeysym; |
| PFNXGETWINDOWATTRIBUTES m_x11_XGetWindowAttributes; |
| #endif //DYNAMIC_LOAD_X11_FUNCTIONS |
| |
| b3WheelCallback m_wheelCallback; |
| b3MouseMoveCallback m_mouseMoveCallback; |
| b3MouseButtonCallback m_mouseButtonCallback; |
| b3ResizeCallback m_resizeCallback; |
| b3KeyboardCallback m_keyboardCallback; |
| |
| InternalData2() |
| :m_dpy(0), |
| m_vi(0), |
| m_modifierFlags(0), |
| m_glWidth(-1), |
| m_glHeight(-1), |
| m_wheelCallback(0), |
| m_mouseMoveCallback(0), |
| m_mouseButtonCallback(0), |
| m_resizeCallback(0), |
| m_keyboardCallback(0) |
| { |
| #ifdef DYNAMIC_LOAD_X11_FUNCTIONS |
| m_x11_library = dlopen(X11_LIBRARY, RTLD_LOCAL | RTLD_NOW); |
| if (!m_x11_library) |
| { |
| printf("Error opening X11 library %s\n", X11_LIBRARY); |
| exit(0); |
| } |
| |
| bool missingFunc = false; |
| |
| missingFunc = ((m_x11_XFree = (PFNXFREE) dlsym(m_x11_library, "XFree"))==NULL) | missingFunc; |
| assert(!missingFunc); |
| if (missingFunc) { printf("Error: missing func XFree in %s, exiting!\n", X11_LIBRARY); exit(0);} |
| missingFunc = ((m_x11_XSetErrorHandler = (PFNXSETERRORHANDLER) dlsym(m_x11_library,"XSetErrorHandler"))==NULL) | missingFunc; |
| if (missingFunc) { printf("Error: missing func XSetErrorHandler in %s, exiting!\n", X11_LIBRARY); exit(0);} |
| missingFunc = ((m_x11_XSetErrorHandler = (PFNXSETERRORHANDLER) dlsym(m_x11_library,"XSetErrorHandler"))==NULL) | missingFunc; |
| if (missingFunc) { printf("Error: missing func XSetErrorHandler in %s, exiting!\n", X11_LIBRARY); exit(0);} |
| missingFunc = ((m_x11_XSync = (PFNXSYNC) dlsym(m_x11_library,"XSync"))==NULL) | missingFunc; |
| if (missingFunc) { printf("Error: missing func XSync in %s, exiting!\n", X11_LIBRARY); exit(0);} |
| missingFunc = ((m_x11_XOpenDisplay = (PFNXOPENDISPLAY) dlsym(m_x11_library,"XOpenDisplay"))==NULL) | missingFunc; |
| if (missingFunc) { printf("Error: missing func XOpenDisplay in %s, exiting!\n", X11_LIBRARY); exit(0);} |
| missingFunc = ((m_x11_XCreateColormap = (PFNXCREATECOLORMAP) dlsym(m_x11_library,"XCreateColormap"))==NULL) | missingFunc; |
| if (missingFunc) { printf("Error: missing func XCreateColormap in %s, exiting!\n", X11_LIBRARY); exit(0);} |
| missingFunc = ((m_x11_XCreateWindow = (PFNXCREATEWINDOW) dlsym(m_x11_library,"XCreateWindow"))==NULL) | missingFunc; |
| if (missingFunc) { printf("Error: missing func XCreateWindow in %s, exiting!\n", X11_LIBRARY); exit(0);} |
| missingFunc = ((m_x11_XMapWindow = (PFNXMAPWINDOW) dlsym(m_x11_library,"XMapWindow"))==NULL) | missingFunc; |
| if (missingFunc) { printf("Error: missing func XMapWindow in %s, exiting!\n", X11_LIBRARY); exit(0);} |
| missingFunc = ((m_x11_XStoreName = (PFNXSTORENAME) dlsym(m_x11_library,"XStoreName"))==NULL) | missingFunc; |
| if (missingFunc) { printf("Error: missing func XStoreName in %s, exiting!\n", X11_LIBRARY); exit(0);} |
| missingFunc = ((m_x11_XCloseDisplay = (PFNXCLOSEDISPLAY) dlsym(m_x11_library,"XCloseDisplay"))==NULL) | missingFunc; |
| if (missingFunc) { printf("Error: missing func XCloseDisplay in %s, exiting!\n", X11_LIBRARY); exit(0);} |
| missingFunc = ((m_x11_XDestroyWindow = (PFNXDESTROYWINDOW) dlsym(m_x11_library,"XDestroyWindow"))==NULL) | missingFunc; |
| if (missingFunc) { printf("Error: missing func XDestroyWindow in %s, exiting!\n", X11_LIBRARY); exit(0);} |
| missingFunc = ((m_x11_XRaiseWindow = (PFNXRAISEWINDOW) dlsym(m_x11_library,"XRaiseWindow"))==NULL) | missingFunc; |
| if (missingFunc) { printf("Error: missing func XRaiseWindow in %s, exiting!\n", X11_LIBRARY); exit(0);} |
| |
| missingFunc = ((m_x11_XGetKeyboardMapping = (PFNXGETKEYBOARDMAPPING) dlsym(m_x11_library,"XGetKeyboardMapping"))==NULL) | missingFunc; |
| if (missingFunc) { printf("Error: missing func XGetKeyboardMapping in %s, exiting!\n", X11_LIBRARY); exit(0);} |
| missingFunc = ((m_x11_XKeycodeToKeysym = (PFNXKEYCODETOKEYSYM) dlsym(m_x11_library,"XKeycodeToKeysym"))==NULL) | missingFunc; |
| if (missingFunc) { printf("Error: missing func XKeycodeToKeysym in %s, exiting!\n", X11_LIBRARY); exit(0);} |
| missingFunc = ((m_x11_XConvertCase = (PFNXCONVERTCASE) dlsym(m_x11_library,"XConvertCase"))==NULL) | missingFunc; |
| if (missingFunc) { printf("Error: missing func XConvertCase in %s, exiting!\n", X11_LIBRARY); exit(0);} |
| missingFunc = ((m_x11_XPending = (PFNXPENDING) dlsym(m_x11_library,"XPending"))==NULL) | missingFunc; |
| if (missingFunc) { printf("Error: missing func XPending in %s, exiting!\n", X11_LIBRARY); exit(0);} |
| missingFunc = ((m_x11_XNextEvent = (PFNXNEXTEVENT) dlsym(m_x11_library,"XNextEvent"))==NULL) | missingFunc; |
| if (missingFunc) { printf("Error: missing func XNextEvent in %s, exiting!\n", X11_LIBRARY); exit(0);} |
| missingFunc = ((m_x11_XEventsQueued = (PFNXEVENTSQUEUED) dlsym(m_x11_library,"XEventsQueued"))==NULL) | missingFunc; |
| if (missingFunc) { printf("Error: missing func XEventsQueued in %s, exiting!\n", X11_LIBRARY); exit(0);} |
| missingFunc = ((m_x11_XPeekEvent = (PFNXPEEKEVENT) dlsym(m_x11_library,"XPeekEvent"))==NULL) | missingFunc; |
| if (missingFunc) { printf("Error: missing func XPeekEvent in %s, exiting!\n", X11_LIBRARY); exit(0);} |
| missingFunc = ((m_x11_XLookupKeysym = (PFNXLOOKUPKEYSYM) dlsym(m_x11_library,"XLookupKeysym"))==NULL) | missingFunc; |
| if (missingFunc) { printf("Error: missing func XLookupKeysym in %s, exiting!\n", X11_LIBRARY); exit(0);} |
| missingFunc = ((m_x11_XGetWindowAttributes = (PFNXGETWINDOWATTRIBUTES) dlsym(m_x11_library,"XGetWindowAttributes"))==NULL) | missingFunc; |
| if (missingFunc) { printf("Error: missing func XGetWindowAttributes in %s, exiting!\n", X11_LIBRARY); exit(0);} |
| |
| if (missingFunc) |
| { |
| printf("Error: a missing func in %s, exiting!\n", X11_LIBRARY); |
| exit(0); |
| } else |
| { |
| printf("X11 functions dynamically loaded using dlopen/dlsym OK!\n"); |
| } |
| #endif //DYNAMIC_LOAD_X11_FUNCTIONS |
| } |
| }; |
| |
| #define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 |
| #define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 |
| typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); |
| |
| // Helper to check for extension string presence. Adapted from: |
| // http://www.opengl.org/resources/features/OGLextensions/ |
| static bool isExtensionSupported(const char *extList, const char *extension) |
| { |
| const char *start; |
| const char *where, *terminator; |
| |
| /* Extension names should not have spaces. */ |
| where = strchr(extension, ' '); |
| if (where || *extension == '\0') |
| return false; |
| |
| /* It takes a bit of care to be fool-proof about parsing the |
| OpenGL extensions string. Don't be fooled by sub-strings, |
| etc. */ |
| for (start=extList;;) { |
| where = strstr(start, extension); |
| |
| if (!where) |
| break; |
| |
| terminator = where + strlen(extension); |
| |
| if ( where == start || *(where - 1) == ' ' ) |
| if ( *terminator == ' ' || *terminator == '\0' ) |
| return true; |
| |
| start = terminator; |
| } |
| |
| return false; |
| } |
| |
| static bool ctxErrorOccurred = false; |
| static int ctxErrorHandler( Display *dpy, XErrorEvent *ev ) |
| { |
| ctxErrorOccurred = true; |
| return 0; |
| } |
| |
| |
| |
| |
| X11OpenGLWindow::X11OpenGLWindow() |
| :m_OpenGLInitialized(false), |
| m_requestedExit(false) |
| { |
| m_data = new InternalData2; |
| } |
| |
| X11OpenGLWindow::~X11OpenGLWindow() |
| { |
| if (m_OpenGLInitialized) |
| { |
| disableOpenGL(); |
| } |
| |
| delete m_data; |
| } |
| |
| |
| |
| void X11OpenGLWindow::enableOpenGL() |
| { |
| |
| |
| if (forceOpenGL3) |
| { |
| // Get the default screen's GLX extension list |
| const char *glxExts = glXQueryExtensionsString( m_data->m_dpy, |
| DefaultScreen( m_data->m_dpy ) ); |
| |
| // NOTE: It is not necessary to create or make current to a context before |
| // calling glXGetProcAddressARB, unless we dynamically load OpenGL/GLX/X11 |
| |
| glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; |
| glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) |
| glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" ); |
| |
| GLXContext ctx = 0; |
| |
| // Install an X error handler so the application won't exit if GL 3.0 |
| // context allocation fails. |
| // |
| // Note this error handler is global. All display connections in all threads |
| // of a process use the same error handler, so be sure to guard against other |
| // threads issuing X commands while this code is running. |
| ctxErrorOccurred = false; |
| int (*oldHandler)(Display*, XErrorEvent*) = |
| MyXSetErrorHandler(&ctxErrorHandler); |
| |
| // Check for the GLX_ARB_create_context extension string and the function. |
| // If either is not present, use GLX 1.3 context creation method. |
| if ( !isExtensionSupported( glxExts, "GLX_ARB_create_context" ) || |
| !glXCreateContextAttribsARB ) |
| { |
| printf( "glXCreateContextAttribsARB() not found" |
| " ... using old-style GLX context\n" ); |
| ctx = glXCreateNewContext( m_data->m_dpy, m_data->m_bestFbc, GLX_RGBA_TYPE, 0, True ); |
| } |
| |
| // If it does, try to get a GL 3.0 context! |
| else |
| { |
| int context_attribs[] = { |
| GLX_CONTEXT_MAJOR_VERSION_ARB ,3, |
| GLX_CONTEXT_MINOR_VERSION_ARB, 2, |
| GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, |
| GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,None |
| }; |
| /* |
| int context_attribs[] = |
| { |
| GLX_CONTEXT_MAJOR_VERSION_ARB, 3, |
| GLX_CONTEXT_MINOR_VERSION_ARB, 2, |
| |
| //GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, |
| None |
| }; |
| */ |
| printf( "Creating context\n" ); |
| ctx = glXCreateContextAttribsARB( m_data->m_dpy, m_data->m_bestFbc, 0, |
| True, context_attribs ); |
| |
| // Sync to ensure any errors generated are processed. |
| MyXSync( m_data->m_dpy, False ); |
| if ( !ctxErrorOccurred && ctx ) |
| printf( "Created GL 3.0 context\n" ); |
| else |
| { |
| // Couldn't create GL 3.0 context. Fall back to old-style 2.x context. |
| // When a context version below 3.0 is requested, implementations will |
| // return the newest context version compatible with OpenGL versions less |
| // than version 3.0. |
| // GLX_CONTEXT_MAJOR_VERSION_ARB = 1 |
| context_attribs[1] = 1; |
| // GLX_CONTEXT_MINOR_VERSION_ARB = 0 |
| context_attribs[3] = 0; |
| |
| ctxErrorOccurred = false; |
| |
| printf( "Failed to create GL 3.0 context" |
| " ... using old-style GLX context\n" ); |
| ctx = glXCreateContextAttribsARB( m_data->m_dpy, m_data->m_bestFbc, 0, |
| True, context_attribs ); |
| } |
| } |
| |
| // Sync to ensure any errors generated are processed. |
| MyXSync( m_data->m_dpy, False ); |
| |
| // Restore the original error handler |
| MyXSetErrorHandler( oldHandler ); |
| |
| if ( ctxErrorOccurred || !ctx ) |
| { |
| printf( "Failed to create an OpenGL context\n" ); |
| exit(1); |
| } |
| |
| // Verifying that context is a direct context |
| if ( ! glXIsDirect ( m_data->m_dpy, ctx ) ) |
| { |
| printf( "Indirect GLX rendering context obtained\n" ); |
| } |
| else |
| { |
| printf( "Direct GLX rendering context obtained\n" ); |
| } |
| |
| printf( "Making context current\n" ); |
| glXMakeCurrent( m_data->m_dpy, m_data->m_win, ctx ); |
| m_data->m_glc = ctx; |
| |
| } else |
| { |
| m_data->m_glc = glXCreateContext(m_data->m_dpy, m_data->m_vi, NULL, GL_TRUE); |
| glXMakeCurrent(m_data->m_dpy, m_data->m_win, m_data->m_glc); |
| } |
| |
| #ifdef GLEW_INIT_OPENGL11_FUNCTIONS |
| { |
| GLboolean res = glewOpenGL11Init(); |
| if (res==0) |
| { |
| printf("glewOpenGL11Init OK!\n"); |
| } else |
| { |
| printf("ERROR: glewOpenGL11Init failed, exiting!\n"); |
| exit(0); |
| } |
| } |
| |
| #endif //GLEW_INIT_OPENGL11_FUNCTIONS |
| |
| const GLubyte* ven = glGetString(GL_VENDOR); |
| printf("GL_VENDOR=%s\n", ven); |
| |
| const GLubyte* ren = glGetString(GL_RENDERER); |
| printf("GL_RENDERER=%s\n",ren); |
| const GLubyte* ver = glGetString(GL_VERSION); |
| printf("GL_VERSION=%s\n", ver); |
| const GLubyte* sl = glGetString(GL_SHADING_LANGUAGE_VERSION); |
| printf("GL_SHADING_LANGUAGE_VERSION=%s\n", sl); |
| |
| //Access pthreads as a workaround for a bug in Linux/Ubuntu |
| //See https://bugs.launchpad.net/ubuntu/+source/nvidia-graphics-drivers-319/+bug/1248642 |
| |
| int i=pthread_getconcurrency(); |
| printf("pthread_getconcurrency()=%d\n",i); |
| |
| // const GLubyte* ext = glGetString(GL_EXTENSIONS); |
| // printf("GL_EXTENSIONS=%s\n", ext); |
| } |
| |
| void X11OpenGLWindow::disableOpenGL() |
| { |
| glXMakeCurrent(m_data->m_dpy, None, NULL); |
| glXDestroyContext(m_data->m_dpy, m_data->m_glc); |
| } |
| |
| |
| void X11OpenGLWindow::createWindow(const b3gWindowConstructionInfo& ci) |
| { |
| |
| m_data->m_dpy = MyXOpenDisplay(NULL); |
| |
| if(m_data->m_dpy == NULL) { |
| printf("\n\tcannot connect to X server\n\n"); |
| exit(0); |
| } |
| |
| m_data->m_root = DefaultRootWindow(m_data->m_dpy); |
| |
| |
| #ifdef GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS |
| GLboolean res = glewXInit(); |
| if (res==0) |
| { |
| printf("glewXInit OK\n"); |
| } else |
| { |
| printf("glewXInit failed, exit\n"); |
| exit(0); |
| } |
| #endif //GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS |
| |
| |
| if (ci.m_openglVersion < 3) |
| { |
| forceOpenGL3 = false; |
| } |
| |
| if (forceOpenGL3) |
| { |
| int glxMinor, glxMajor; |
| if (!glXQueryVersion(m_data->m_dpy,&glxMajor,&glxMinor) || (((glxMajor==1)&&(glxMinor<3)) || (glxMajor<1))) |
| { |
| printf("Invalid GLX version: major %d, minor %d\n",glxMajor,glxMinor); |
| exit(0); |
| } |
| |
| 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; |
| GLXFBConfig* fbc = glXChooseFBConfig(m_data->m_dpy, DefaultScreen(m_data->m_dpy), visual_attribs, &fbcount); |
| if (!fbc) |
| { |
| printf( "Failed to retrieve a framebuffer config\n" ); |
| exit(1); |
| } |
| ///don't use highest samples, it is really slow on some NVIDIA Quadro cards |
| #ifdef USE_HIGHEST_SAMPLES |
| int best_fbc = -1, worst_fbc = -1, best_num_samp = -1, worst_num_samp = 999; |
| |
| int i; |
| for (i=0; i<fbcount; ++i) |
| { |
| XVisualInfo *vi = glXGetVisualFromFBConfig( m_data->m_dpy, fbc[i] ); |
| if ( vi ) |
| { |
| int samp_buf, samples; |
| glXGetFBConfigAttrib( m_data->m_dpy, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf ); |
| glXGetFBConfigAttrib( m_data->m_dpy, fbc[i], GLX_SAMPLES , &samples ); |
| |
| //printf( " Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d," |
| // " SAMPLES = %d\n", |
| // i, vi -> visualid, samp_buf, samples ); |
| |
| if ( best_fbc < 0 || (samp_buf && (samples > best_num_samp)) ) |
| best_fbc = i, best_num_samp = samples; |
| if ( worst_fbc < 0 || (!samp_buf || (samples < worst_num_samp)) ) |
| worst_fbc = i, worst_num_samp = samples; |
| } |
| MyXFree( vi ); |
| } |
| |
| m_data->m_bestFbc = fbc[ best_fbc ]; |
| #else |
| m_data->m_bestFbc = *fbc; |
| #endif |
| // Be sure to free the FBConfig list allocated by glXChooseFBConfig() |
| MyXFree( fbc ); |
| |
| m_data->m_vi = glXGetVisualFromFBConfig( m_data->m_dpy, m_data->m_bestFbc ); |
| |
| |
| m_data->m_swa.colormap = m_data->m_cmap = MyXCreateColormap( m_data->m_dpy, |
| RootWindow( m_data->m_dpy, m_data->m_vi->screen ), |
| m_data->m_vi->visual, AllocNone ); |
| m_data->m_swa.background_pixmap = None ; |
| m_data->m_swa.border_pixel = 0; |
| m_data->m_swa.event_mask = ExposureMask | KeyReleaseMask | KeyPressMask |ButtonPressMask | ButtonReleaseMask |PointerMotionMask|StructureNotifyMask; |
| ; |
| m_data->m_root = RootWindow( m_data->m_dpy, m_data->m_vi->screen ); |
| |
| m_data->m_win = MyXCreateWindow( m_data->m_dpy, m_data->m_root, |
| 0, 0, ci.m_width, ci.m_height, 0, m_data->m_vi->depth, InputOutput, |
| m_data->m_vi->visual, |
| CWBorderPixel|CWColormap|CWEventMask, &m_data->m_swa ); |
| |
| //m_data->m_win = m_data->m_x11_XCreateWindow(m_data->m_dpy, m_data->m_root, 0, 0, ci.m_width, ci.m_height, 0, m_data->m_vi->depth, InputOutput, m_data->m_vi->visual, CWColormap | CWEventMask, &m_data->m_swa); |
| |
| |
| if (!m_data->m_win) |
| { |
| printf("Cannot create window\n"); |
| exit(0); |
| } |
| |
| MyXMapWindow(m_data->m_dpy, m_data->m_win); |
| MyXStoreName(m_data->m_dpy, m_data->m_win, "OpenGL3 Window"); |
| |
| |
| } else |
| { |
| m_data->m_vi = glXChooseVisual(m_data->m_dpy, 0, att); |
| |
| printf("4\n"); |
| |
| if(m_data->m_vi == NULL) { |
| printf("\n\tno appropriate visual found\n\n"); |
| exit(0); |
| } |
| else { |
| printf("\n\tvisual %p selected\n", (void *)m_data->m_vi->visualid); /* %p creates hexadecimal output like in glxinfo */ |
| } |
| |
| |
| m_data->m_cmap = MyXCreateColormap(m_data->m_dpy, m_data->m_root, m_data->m_vi->visual, AllocNone); |
| m_data->m_swa.colormap = m_data->m_cmap; |
| m_data->m_swa.event_mask = ExposureMask | KeyReleaseMask | KeyPressMask |ButtonPressMask | ButtonReleaseMask |PointerMotionMask|StructureNotifyMask; |
| m_data->m_win = MyXCreateWindow(m_data->m_dpy, m_data->m_root, 0, 0, ci.m_width, ci.m_height, 0, m_data->m_vi->depth, InputOutput, m_data->m_vi->visual, CWColormap | CWEventMask, &m_data->m_swa); |
| |
| MyXMapWindow(m_data->m_dpy, m_data->m_win); |
| |
| MyXStoreName(m_data->m_dpy, m_data->m_win, "OpenGL2 Window"); |
| |
| |
| } |
| |
| enableOpenGL(); |
| } |
| |
| void X11OpenGLWindow::closeWindow() |
| { |
| disableOpenGL(); |
| |
| MyXDestroyWindow(m_data->m_dpy, m_data->m_win); |
| MyXCloseDisplay(m_data->m_dpy); |
| } |
| |
| int X11OpenGLWindow::getAsciiCodeFromVirtualKeycode(int keycode) |
| { |
| int result = 0; |
| |
| KeySym key, key_lc, key_uc; |
| |
| int keysyms_per_keycode_return; |
| KeySym *keysym = MyXGetKeyboardMapping(m_data->m_dpy, |
| keycode, |
| 1, |
| &keysyms_per_keycode_return); |
| |
| key = keysym[0]; |
| |
| |
| //key = MyXKeycodeToKeysym( m_data->m_dpy, keycode, 0 ); |
| |
| switch( key ) |
| { |
| case XK_Escape: return B3G_ESCAPE; |
| case XK_Return: return B3G_RETURN; |
| case XK_BackSpace: return B3G_BACKSPACE; |
| case XK_Delete: return B3G_DELETE; |
| case XK_Tab: return 9; |
| |
| case XK_Control_L: |
| case XK_Control_R: { |
| return B3G_CONTROL; |
| } |
| case XK_Left: return B3G_LEFT_ARROW; |
| case XK_Right: return B3G_RIGHT_ARROW; |
| case XK_Up: return B3G_UP_ARROW; |
| case XK_Down: return B3G_DOWN_ARROW; |
| |
| case XK_Alt_L: |
| case XK_Alt_R: |
| { |
| return B3G_ALT; |
| } |
| case XK_Shift_L: |
| case XK_Shift_R: return B3G_SHIFT; |
| case XK_F1: return B3G_F1; |
| case XK_F2: return B3G_F2; |
| case XK_F3: return B3G_F3; |
| case XK_F4: return B3G_F4; |
| case XK_F5: return B3G_F5; |
| case XK_F6: return B3G_F6; |
| case XK_F7: return B3G_F7; |
| case XK_F8: return B3G_F8; |
| case XK_F9: return B3G_F9; |
| case XK_F10: return B3G_F10; |
| case XK_F11: return B3G_F11; |
| case XK_F12: return B3G_F12; |
| case XK_F13: return B3G_F13; |
| case XK_F14: return B3G_F14; |
| case XK_F15: return B3G_F15; |
| default: |
| // Make lowercase |
| MyXConvertCase( key, &key_lc, &key_uc ); |
| key = key_lc; |
| // Valid ISO 8859-1 character? |
| if( (key >= 32 && key <= 126) ||(key >= 160 && key <= 255) ) |
| { |
| return (int) key; |
| } |
| result = -1; |
| } |
| |
| MyXFree(keysym); |
| |
| return result; |
| } |
| |
| bool X11OpenGLWindow::isModifierKeyPressed(int key) |
| { |
| bool isPressed = false; |
| |
| switch (key) |
| { |
| case B3G_ALT: |
| { |
| isPressed = ((m_data->m_modifierFlags & MY_X11_ALT_KEY)!=0); |
| break; |
| }; |
| case B3G_SHIFT: |
| { |
| isPressed = ((m_data->m_modifierFlags & MY_X11_SHIFT_KEY)!=0); |
| break; |
| }; |
| case B3G_CONTROL: |
| { |
| isPressed = ((m_data->m_modifierFlags & MY_X11_CONTROL_KEY )!=0); |
| break; |
| }; |
| |
| default: |
| { |
| } |
| }; |
| return isPressed; |
| } |
| |
| void X11OpenGLWindow::pumpMessage() |
| { |
| |
| int buttonState = 1; |
| |
| // Process all pending events |
| while( MyXPending( m_data->m_dpy ) ) |
| { |
| MyXNextEvent(m_data->m_dpy, &m_data->m_xev); |
| // printf("#"); |
| // fflush(stdout); |
| switch( m_data->m_xev.type ) |
| { |
| case KeyPress: |
| { |
| int keycode = getAsciiCodeFromVirtualKeycode(m_data->m_xev.xkey.keycode); |
| switch (keycode) |
| { |
| case B3G_ALT: |
| m_data->m_modifierFlags |= MY_X11_ALT_KEY; |
| break; |
| case B3G_SHIFT: |
| m_data->m_modifierFlags |= MY_X11_SHIFT_KEY; |
| break; |
| case B3G_CONTROL: |
| m_data->m_modifierFlags |= MY_X11_CONTROL_KEY; |
| break; |
| default: |
| {} |
| }; |
| if (m_data->m_keyboardCallback) |
| { |
| |
| int state = 1; |
| (*m_data->m_keyboardCallback)(keycode,state); |
| // printf("keycode %d",keycode); |
| // fflush(stdout); |
| |
| } |
| break; |
| } |
| |
| case KeyRelease: |
| { |
| // fflush(stdout); |
| int keycode = getAsciiCodeFromVirtualKeycode( m_data->m_xev.xkey.keycode); |
| switch (keycode) |
| { |
| case B3G_ALT: |
| m_data->m_modifierFlags &= ~MY_X11_ALT_KEY; |
| break; |
| case B3G_SHIFT: |
| m_data->m_modifierFlags &= ~MY_X11_SHIFT_KEY; |
| break; |
| case B3G_CONTROL: |
| m_data->m_modifierFlags &= ~MY_X11_CONTROL_KEY; |
| break; |
| default: |
| {} |
| }; |
| |
| if (m_data->m_keyboardCallback) |
| { |
| #if 0 |
| unsigned short is_retriggered = 0; |
| ///filter out keyboard repeat |
| //see http://stackoverflow.com/questions/2100654/ignore-auto-repeat-in-x11-applications |
| if (MyXEventsQueued(m_data->m_dpy, QueuedAfterReading)) |
| { |
| XEvent nev; |
| MyXPeekEvent(m_data->m_dpy, &nev); |
| |
| if (nev.type == KeyPress && nev.xkey.time == m_data->m_xev.xkey.time && |
| nev.xkey.keycode == m_data->m_xev.xkey.keycode) |
| { |
| fprintf (stdout, "key #%ld was retriggered.\n", |
| (long) MyXLookupKeysym(&nev.xkey, 0)); |
| |
| // delete retriggered KeyPress event |
| MyXNextEvent(m_data->m_dpy, & m_data->m_xev); |
| is_retriggered = 1; |
| } |
| } |
| #endif |
| int state = 0; |
| (*m_data->m_keyboardCallback)(keycode,state); |
| } |
| |
| break; |
| } |
| |
| case ButtonRelease: |
| buttonState = 0; |
| //continue with ButtonPress code |
| case ButtonPress: |
| { |
| // printf("!"); |
| // fflush(stdout); |
| |
| int button=-1; |
| |
| switch (m_data->m_xev.xbutton.button) |
| { |
| case Button1: |
| { |
| button=0; |
| break; |
| } |
| case Button2: |
| { |
| button=1; |
| break; |
| } |
| case Button3: |
| { |
| button=2; |
| break; |
| } |
| case Button4: |
| { |
| if (m_data->m_wheelCallback) |
| { |
| (*m_data->m_wheelCallback)(0,10); |
| } |
| break; |
| } |
| case Button5: |
| { |
| if (m_data->m_wheelCallback) |
| { |
| (*m_data->m_wheelCallback)(0,-10); |
| } |
| break; |
| } |
| } |
| int xpos = m_data->m_xev.xmotion.x; |
| int ypos = m_data->m_xev.xmotion.y; |
| |
| if (button>=0 && m_data->m_mouseButtonCallback) |
| { |
| // printf("xpos = %d, ypos = %d\n",xpos,ypos); |
| |
| (*m_data->m_mouseButtonCallback)(button,buttonState,xpos,ypos); |
| } |
| break; |
| } |
| case MotionNotify: |
| { |
| // printf("!"); |
| // fflush(0); |
| if (m_data->m_mouseMoveCallback) |
| { |
| int xpos = m_data->m_xev.xmotion.x; |
| int ypos = m_data->m_xev.xmotion.y; |
| (*m_data->m_mouseMoveCallback)(xpos,ypos); |
| } |
| break; |
| } |
| case ConfigureNotify: |
| { |
| // printf("@"); |
| // fflush(0); |
| m_data->m_glWidth = m_data->m_xev.xconfigure.width; |
| m_data->m_glHeight = m_data->m_xev.xconfigure.height; |
| |
| if (m_data->m_resizeCallback) |
| { |
| (*m_data->m_resizeCallback)(m_data->m_xev.xconfigure.width,m_data->m_xev.xconfigure.height); |
| } |
| break; |
| } |
| case ClientMessage: |
| { |
| // printf("?"); |
| // fflush(stdout); |
| break; |
| } |
| case Expose: |
| { |
| break; |
| } |
| case DestroyNotify: |
| { |
| break; |
| } |
| default: |
| { |
| //XRRUpdateConfiguration( &event ); |
| } |
| }; |
| } |
| } |
| |
| |
| |
| void X11OpenGLWindow::startRendering() |
| { |
| pumpMessage(); |
| |
| MyXGetWindowAttributes(m_data->m_dpy, m_data->m_win, &m_data->m_gwa); |
| glViewport(0, 0, m_data->m_gwa.width, m_data->m_gwa.height); |
| |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); //clear buffers |
| |
| //glCullFace(GL_BACK); |
| //glFrontFace(GL_CCW); |
| glEnable(GL_DEPTH_TEST); |
| } |
| |
| void X11OpenGLWindow::renderAllObjects() |
| { |
| |
| } |
| |
| void X11OpenGLWindow::endRendering() |
| { |
| glXSwapBuffers(m_data->m_dpy, m_data->m_win); |
| } |
| |
| void X11OpenGLWindow::runMainLoop() |
| { |
| |
| } |
| |
| float X11OpenGLWindow::getTimeInSeconds() |
| { |
| return 0.f; |
| } |
| |
| bool X11OpenGLWindow::requestedExit() const |
| { |
| return m_requestedExit; |
| } |
| |
| void X11OpenGLWindow::setRequestExit() |
| { |
| m_requestedExit=true; |
| } |
| |
| void X11OpenGLWindow::setRenderCallback( b3RenderCallback renderCallback) |
| { |
| |
| } |
| |
| void X11OpenGLWindow::setWindowTitle(const char* title) |
| { |
| MyXStoreName(m_data->m_dpy, m_data->m_win, title); |
| } |
| |
| |
| void X11OpenGLWindow::setWheelCallback(b3WheelCallback wheelCallback) |
| { |
| m_data->m_wheelCallback = wheelCallback; |
| } |
| |
| void X11OpenGLWindow::setMouseMoveCallback(b3MouseMoveCallback mouseCallback) |
| { |
| m_data->m_mouseMoveCallback = mouseCallback; |
| } |
| |
| void X11OpenGLWindow::setMouseButtonCallback(b3MouseButtonCallback mouseCallback) |
| { |
| m_data->m_mouseButtonCallback = mouseCallback; |
| } |
| |
| void X11OpenGLWindow::setResizeCallback(b3ResizeCallback resizeCallback) |
| { |
| if (resizeCallback && m_data->m_glWidth>0 && m_data->m_glHeight > 0) |
| { |
| resizeCallback(m_data->m_glWidth, m_data->m_glHeight); |
| } |
| m_data->m_resizeCallback = resizeCallback; |
| } |
| |
| void X11OpenGLWindow::setKeyboardCallback( b3KeyboardCallback keyboardCallback) |
| { |
| m_data->m_keyboardCallback = keyboardCallback; |
| |
| } |
| |
| b3MouseMoveCallback X11OpenGLWindow::getMouseMoveCallback() |
| { |
| return m_data->m_mouseMoveCallback; |
| } |
| b3MouseButtonCallback X11OpenGLWindow::getMouseButtonCallback() |
| { |
| return m_data->m_mouseButtonCallback; |
| } |
| b3ResizeCallback X11OpenGLWindow::getResizeCallback() |
| { |
| return m_data->m_resizeCallback; |
| } |
| b3WheelCallback X11OpenGLWindow::getWheelCallback() |
| { |
| return m_data->m_wheelCallback; |
| } |
| |
| |
| b3KeyboardCallback X11OpenGLWindow::getKeyboardCallback() |
| { |
| return m_data->m_keyboardCallback; |
| } |
| |
| int X11OpenGLWindow::getWidth() const |
| { |
| if (m_data) |
| return m_data->m_glWidth; |
| return 0; |
| } |
| int X11OpenGLWindow::getHeight() const |
| { |
| if (m_data) |
| return m_data->m_glHeight; |
| return 0; |
| } |
| |
| |
| #include <stdio.h> |
| |
| int X11OpenGLWindow::fileOpenDialog(char* filename, int maxNameLength) |
| { |
| int len = 0; |
| FILE * output = popen("zenity --file-selection --file-filter=\"*.urdf\" --file-filter=\"*.sdf\" --file-filter=\"*.obj\" --file-filter=\"*.*\"","r"); |
| if (output) |
| { |
| while( fgets(filename, maxNameLength-1, output) != NULL ) |
| { |
| len=strlen(filename); |
| if (len>0) |
| { |
| filename[len-1]=0; |
| printf("file open (length=%d) = %s\n", len,filename); |
| } |
| } |
| pclose(output); |
| } else |
| { |
| printf("Error: fileOpenDialog no popen output, perhaps install zenity?\n"); |
| } |
| MyXRaiseWindow(m_data->m_dpy, m_data->m_win); |
| return len; |
| |
| } |