mirror of
https://github.com/bulletphysics/bullet3
synced 2024-12-13 13:20:07 +00:00
cbff4a0a06
not support for pthread_getconcurrency.
1198 lines
32 KiB
C++
1198 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
|
|
|
|
#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 <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
|