mirror of
https://github.com/bulletphysics/bullet3
synced 2025-01-19 05:20:06 +00:00
dd8fcad6d8
X11OpenGLWindow::X11OpenGLWindow() ends up calling dlopen() to get libX11. When this fails, it only reports that it failed, and what filename it was looking for. This commit adds dlerror() to the error message, which makes investigating failures easier.
1196 lines
32 KiB
C++
1196 lines
32 KiB
C++
|
|
#ifndef B3_USE_GLFW
|
|
|
|
#include "X11OpenGLWindow.h"
|
|
#include "OpenGLInclude.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "glad/gl.h"
|
|
|
|
#ifdef GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS
|
|
#include "glad/glx.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)
|
|
{
|
|
// 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
|
|
|
|
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);
|
|
|
|
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 <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;
|
|
}
|
|
#endif
|