#ifndef B3_USE_GLFW #include "X11OpenGLWindow.h" #include "OpenGLInclude.h" #include #include #include "glad/gl.h" #ifdef GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS #include "glad/glx.h" #else #include #endif // GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS #include //#define DYNAMIC_LOAD_X11_FUNCTIONS #ifdef DYNAMIC_LOAD_X11_FUNCTIONS #include #endif //DYNAMIC_LOAD_X11_FUNCTIONS //#include //#include //#include //defined in GL/glxew.h //#include #include #include #include #include #include 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) { // TODO: Properly handle this error. fprintf(stderr, "Error opening X11 library %s: %s\n", X11_LIBRARY, dlerror()); exit(EXIT_FAILURE); } bool missingFunc = false; missingFunc = ((m_x11_XFree = (PFNXFREE)dlsym(m_x11_library, "XFree")) == NULL) | missingFunc; assert(!missingFunc); if (missingFunc) { fprintf(stderr, "Error: missing func XFree in %s, exiting!\n", X11_LIBRARY); exit(EXIT_FAILURE); } missingFunc = ((m_x11_XSetErrorHandler = (PFNXSETERRORHANDLER)dlsym(m_x11_library, "XSetErrorHandler")) == NULL) | missingFunc; if (missingFunc) { fprintf(stderr, "Error: missing func XSetErrorHandler in %s, exiting!\n", X11_LIBRARY); exit(EXIT_FAILURE); } missingFunc = ((m_x11_XSetErrorHandler = (PFNXSETERRORHANDLER)dlsym(m_x11_library, "XSetErrorHandler")) == NULL) | missingFunc; if (missingFunc) { fprintf(stderr, "Error: missing func XSetErrorHandler in %s, exiting!\n", X11_LIBRARY); exit(EXIT_FAILURE); } missingFunc = ((m_x11_XSync = (PFNXSYNC)dlsym(m_x11_library, "XSync")) == NULL) | missingFunc; if (missingFunc) { fprintf(stderr, "Error: missing func XSync in %s, exiting!\n", X11_LIBRARY); exit(EXIT_FAILURE); } missingFunc = ((m_x11_XOpenDisplay = (PFNXOPENDISPLAY)dlsym(m_x11_library, "XOpenDisplay")) == NULL) | missingFunc; if (missingFunc) { fprintf(stderr, "Error: missing func XOpenDisplay in %s, exiting!\n", X11_LIBRARY); exit(EXIT_FAILURE); } missingFunc = ((m_x11_XCreateColormap = (PFNXCREATECOLORMAP)dlsym(m_x11_library, "XCreateColormap")) == NULL) | missingFunc; if (missingFunc) { fprintf(stderr, "Error: missing func XCreateColormap in %s, exiting!\n", X11_LIBRARY); exit(EXIT_FAILURE); } missingFunc = ((m_x11_XCreateWindow = (PFNXCREATEWINDOW)dlsym(m_x11_library, "XCreateWindow")) == NULL) | missingFunc; if (missingFunc) { fprintf(stderr, "Error: missing func XCreateWindow in %s, exiting!\n", X11_LIBRARY); exit(EXIT_FAILURE); } missingFunc = ((m_x11_XMapWindow = (PFNXMAPWINDOW)dlsym(m_x11_library, "XMapWindow")) == NULL) | missingFunc; if (missingFunc) { fprintf(stderr, "Error: missing func XMapWindow in %s, exiting!\n", X11_LIBRARY); exit(EXIT_FAILURE); } missingFunc = ((m_x11_XStoreName = (PFNXSTORENAME)dlsym(m_x11_library, "XStoreName")) == NULL) | missingFunc; if (missingFunc) { fprintf(stderr, "Error: missing func XStoreName in %s, exiting!\n", X11_LIBRARY); exit(EXIT_FAILURE); } missingFunc = ((m_x11_XCloseDisplay = (PFNXCLOSEDISPLAY)dlsym(m_x11_library, "XCloseDisplay")) == NULL) | missingFunc; if (missingFunc) { fprintf(stderr, "Error: missing func XCloseDisplay in %s, exiting!\n", X11_LIBRARY); exit(EXIT_FAILURE); } missingFunc = ((m_x11_XDestroyWindow = (PFNXDESTROYWINDOW)dlsym(m_x11_library, "XDestroyWindow")) == NULL) | missingFunc; if (missingFunc) { fprintf(stderr, "Error: missing func XDestroyWindow in %s, exiting!\n", X11_LIBRARY); exit(EXIT_FAILURE); } missingFunc = ((m_x11_XRaiseWindow = (PFNXRAISEWINDOW)dlsym(m_x11_library, "XRaiseWindow")) == NULL) | missingFunc; if (missingFunc) { fprintf(stderr, "Error: missing func XRaiseWindow in %s, exiting!\n", X11_LIBRARY); exit(EXIT_FAILURE); } missingFunc = ((m_x11_XGetKeyboardMapping = (PFNXGETKEYBOARDMAPPING)dlsym(m_x11_library, "XGetKeyboardMapping")) == NULL) | missingFunc; if (missingFunc) { fprintf(stderr, "Error: missing func XGetKeyboardMapping in %s, exiting!\n", X11_LIBRARY); exit(EXIT_FAILURE); } missingFunc = ((m_x11_XKeycodeToKeysym = (PFNXKEYCODETOKEYSYM)dlsym(m_x11_library, "XKeycodeToKeysym")) == NULL) | missingFunc; if (missingFunc) { fprintf(stderr, "Error: missing func XKeycodeToKeysym in %s, exiting!\n", X11_LIBRARY); exit(EXIT_FAILURE); } missingFunc = ((m_x11_XConvertCase = (PFNXCONVERTCASE)dlsym(m_x11_library, "XConvertCase")) == NULL) | missingFunc; if (missingFunc) { fprintf(stderr, "Error: missing func XConvertCase in %s, exiting!\n", X11_LIBRARY); exit(EXIT_FAILURE); } missingFunc = ((m_x11_XPending = (PFNXPENDING)dlsym(m_x11_library, "XPending")) == NULL) | missingFunc; if (missingFunc) { fprintf(stderr, "Error: missing func XPending in %s, exiting!\n", X11_LIBRARY); exit(EXIT_FAILURE); } missingFunc = ((m_x11_XNextEvent = (PFNXNEXTEVENT)dlsym(m_x11_library, "XNextEvent")) == NULL) | missingFunc; if (missingFunc) { fprintf(stderr, "Error: missing func XNextEvent in %s, exiting!\n", X11_LIBRARY); exit(EXIT_FAILURE); } missingFunc = ((m_x11_XEventsQueued = (PFNXEVENTSQUEUED)dlsym(m_x11_library, "XEventsQueued")) == NULL) | missingFunc; if (missingFunc) { fprintf(stderr, "Error: missing func XEventsQueued in %s, exiting!\n", X11_LIBRARY); exit(EXIT_FAILURE); } missingFunc = ((m_x11_XPeekEvent = (PFNXPEEKEVENT)dlsym(m_x11_library, "XPeekEvent")) == NULL) | missingFunc; if (missingFunc) { fprintf(stderr, "Error: missing func XPeekEvent in %s, exiting!\n", X11_LIBRARY); exit(EXIT_FAILURE); } missingFunc = ((m_x11_XLookupKeysym = (PFNXLOOKUPKEYSYM)dlsym(m_x11_library, "XLookupKeysym")) == NULL) | missingFunc; if (missingFunc) { fprintf(stderr, "Error: missing func XLookupKeysym in %s, exiting!\n", X11_LIBRARY); exit(EXIT_FAILURE); } missingFunc = ((m_x11_XGetWindowAttributes = (PFNXGETWINDOWATTRIBUTES)dlsym(m_x11_library, "XGetWindowAttributes")) == NULL) | missingFunc; if (missingFunc) { fprintf(stderr, "Error: missing func XGetWindowAttributes in %s, exiting!\n", X11_LIBRARY); exit(EXIT_FAILURE); } if (missingFunc) { fprintf(stderr, "Error: a missing func in %s, exiting!\n", X11_LIBRARY); exit(EXIT_FAILURE); } 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.3 // 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.3 context! else { int context_attribs[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, 3, 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.3 context\n"); else { // Couldn't create GL 3.3 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.3 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) { fprintf(stderr, "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); } if (!gladLoaderLoadGL()) { printf("gladLoadGL failed!\n"); exit(-1); } 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 #if !defined(__NetBSD__) int i = pthread_getconcurrency(); printf("pthread_getconcurrency()=%d\n", i); #endif // 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); m_data->m_glWidth = ci.m_width; m_data->m_glHeight = ci.m_height; if (m_data->m_dpy == NULL) { fprintf(stderr, "\n\tcannot connect to X server\n\n"); exit(EXIT_FAILURE); } m_data->m_root = DefaultRootWindow(m_data->m_dpy); #ifdef GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS int res = gladLoaderLoadGLX(m_data->m_dpy, DefaultScreen(m_data->m_dpy)); if (!res) { printf("Error in gladLoadGLX\n"); exit(0); } #endif 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))) { fprintf(stderr, "Invalid GLX version: major %d, minor %d\n", glxMajor, glxMinor); exit(EXIT_FAILURE); } 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) { fprintf(stderr, "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) { fprintf(stderr, "Cannot create window\n"); exit(EXIT_FAILURE); } 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) { fprintf(stderr, "\n\tno appropriate visual found\n\n"); exit(EXIT_FAILURE); } 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_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 1 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; if (!is_retriggered) (*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 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; } #endif