Created
March 23, 2017 10:37
-
-
Save KarimIO/7db1f50778fda63a36c10242989baab6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifdef __linux__ | |
#include "Core/Input.h" | |
#include "Window.h" | |
#include <stdio.h> | |
#include <X11/Xlib.h> | |
#include <X11/Xutil.h> | |
#include <X11/keysymdef.h> | |
#include <GL/glx.h> | |
#include <cstring> | |
typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); | |
typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGPROC) (GLenum name); | |
typedef void *(APIENTRYP PFNGLCLEAR) (int n); | |
typedef void *(APIENTRYP PFNGLCLEARCOLOR) (double r, double g, double b, double a); | |
GameWindow::~GameWindow() { | |
glXMakeCurrent(display, None, NULL); | |
glXDestroyContext(display, glc); | |
XDestroyWindow(display, window); | |
XCloseDisplay(display); | |
} | |
static bool isExtensionSupported(const char *extList, const char *extension) { | |
const char *start; | |
const char *where, *terminator; | |
where = strchr(extension, ' '); | |
if (where || *extension == '\0') { | |
return false; | |
} | |
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; | |
} | |
bool GameWindow::Initialize(const char *title, int resolutionX, int resolutionY) { | |
resX = resolutionX; | |
resY = resolutionY; | |
display = XOpenDisplay(NULL); | |
if (display == NULL) { | |
std::cout << "Could not open display\n"; | |
return false; | |
} | |
screen = DefaultScreenOfDisplay(display); | |
screenID = DefaultScreen(display); | |
GLint glxAttribs[] = { | |
/*GLX_DOUBLEBUFFER, | |
GLX_DEPTH_SIZE, 24, | |
GLX_STENCIL_SIZE, 8, | |
GLX_RED_SIZE, 8, | |
GLX_GREEN_SIZE, 8, | |
GLX_BLUE_SIZE, 8, | |
GLX_SAMPLE_BUFFERS, 0, | |
GLX_SAMPLES, 0, | |
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, | |
//GLX_SAMPLE_BUFFERS , 1, | |
//GLX_SAMPLES , 4, | |
None | |
}; | |
int fbcount; | |
GLXFBConfig* fbc = glXChooseFBConfig(display, screenID, glxAttribs, &fbcount); | |
if (fbc == 0) { | |
std::cout << "Failed to retrieve framebuffer.\n"; | |
XCloseDisplay(display); | |
return 0; | |
} | |
//std::cout << "Found " << fbcount << " matching framebuffers.\n"; | |
// Pick the FB config/visual with the most samples per pixel | |
//std::cout << "Getting best XVisualInfo\n"; | |
int best_fbc = -1, worst_fbc = -1, best_num_samp = -1, worst_num_samp = 999; | |
for (int i = 0; i < fbcount; ++i) { | |
XVisualInfo *vi = glXGetVisualFromFBConfig( display, fbc[i] ); | |
if ( vi != 0) { | |
int samp_buf, samples; | |
glXGetFBConfigAttrib( display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf ); | |
glXGetFBConfigAttrib( display, fbc[i], GLX_SAMPLES , &samples ); | |
//std::cout << " Matching fbconfig " << i << ", SAMPLE_BUFFERS = " << samp_buf << ", SAMPLES = " << samples << ".\n"; | |
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; | |
} | |
XFree( vi ); | |
} | |
//std::cout << "Best visual info index: " << best_fbc << "\n"; | |
GLXFBConfig bestFbc = fbc[ best_fbc ]; | |
XFree( fbc ); // Make sure to free this! | |
XVisualInfo* visual = glXGetVisualFromFBConfig( display, bestFbc ); | |
if (visual == 0) { | |
std::cout << "Could not create correct visual window.\n"; | |
XCloseDisplay(display); | |
return 0; | |
} | |
if (screenID != visual->screen) { | |
std::cout << "screenID(" << screenID << ") does not match visual->screen(" << visual->screen << ").\n"; | |
XCloseDisplay(display); | |
return 0; | |
} | |
// Open the window | |
XSetWindowAttributes windowAttribs; | |
windowAttribs.border_pixel = BlackPixel(display, screenID); | |
windowAttribs.background_pixel = WhitePixel(display, screenID); | |
windowAttribs.override_redirect = True; | |
windowAttribs.colormap = XCreateColormap(display, RootWindow(display, screenID), visual->visual, AllocNone); | |
windowAttribs.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | KeymapStateMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | FocusChangeMask; | |
window = XCreateWindow(display, RootWindow(display, screenID), 0, 0, resolutionX, resolutionY, 0, visual->depth, InputOutput, visual->visual, CWBackPixel | CWColormap | CWBorderPixel | CWEventMask, &windowAttribs); | |
// Name the window | |
XStoreName(display, window, title); | |
// Create GLX OpenGL context | |
glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; | |
glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" ); | |
int context_attribs[] = { | |
GLX_CONTEXT_MAJOR_VERSION_ARB, 3, | |
GLX_CONTEXT_MINOR_VERSION_ARB, 3, | |
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, | |
None | |
}; | |
GLXContext context = 0; | |
const char *glxExts = glXQueryExtensionsString( display, screenID ); | |
if (!isExtensionSupported( glxExts, "GLX_ARB_create_context")) { | |
std::cout << "GLX_ARB_create_context not supported\n"; | |
context = glXCreateNewContext( display, bestFbc, GLX_RGBA_TYPE, 0, True ); | |
} | |
else { | |
context = glXCreateContextAttribsARB( display, bestFbc, 0, true, context_attribs ); | |
} | |
GLint majorGLX, minorGLX = 0; | |
glXQueryVersion(display, &majorGLX, &minorGLX); | |
if (majorGLX <= 1 && minorGLX < 2) { | |
std::cout << "GLX 1.2 or greater is required.\n"; | |
XCloseDisplay(display); | |
return false; | |
} | |
if (context == NULL) { | |
std::cout << "Null Context!" << "\n"; | |
return 0; | |
} | |
XSync( display, False ); | |
// Verifying that context is a direct context | |
if (!glXIsDirect (display, context)) { | |
std::cout << "Indirect GLX rendering context obtained\n"; | |
} | |
//if (!glXMakeCurrent(display, window, context)) | |
if (!glXMakeContextCurrent(display, window, window, context)) | |
std::cout << "GLX Make Current Failed!!" << "\n"; | |
// Show the window | |
XClearWindow(display, window); | |
XMapRaised(display, window); | |
/*XEvent ev; | |
while (true) { | |
XNextEvent(display, &ev); | |
if (ev.type == Expose) { | |
XWindowAttributes attribs; | |
XGetWindowAttributes(display, window, &attribs); | |
glViewport(0, 0, attribs.width, attribs.height); | |
} | |
// OpenGL Rendering | |
glClear(GL_COLOR_BUFFER_BIT); | |
glBegin(GL_TRIANGLES); | |
glColor3f( 1.0f, 0.0f, 0.0f); | |
glVertex3f( 0.0f, -1.0f, 0.0f); | |
glColor3f( 0.0f, 1.0f, 0.0f); | |
glVertex3f(-1.0f, 1.0f, 0.0f); | |
glColor3f( 0.0f, 0.0f, 1.0f); | |
glVertex3f( 1.0f, 1.0f, 0.0f); | |
glEnd(); | |
// Present frame | |
glXSwapBuffers(display, window); | |
}*/ | |
// Resize window | |
/*unsigned int change_values = CWWidth | CWHeight; | |
XWindowChanges values; | |
values.width = game.settings.resolution.x; | |
values.height = game.settings.resolution.y; | |
XConfigureWindow(display, window, change_values, &values);*/ | |
return true; | |
} | |
void GameWindow::SwapBuffer() { | |
glXSwapBuffers(display, window); | |
} | |
void GameWindow::SetCursorShown(bool) { | |
// Create blank cursor | |
static char data[1] = {0}; | |
Cursor cursor; | |
Pixmap blank; | |
XColor dummy; | |
blank = XCreateBitmapFromData(display, window, data, 1, 1); | |
if (blank == None) { | |
std::cout << "Can't create blank cursor.\n"; | |
return; | |
} | |
cursor = XCreatePixmapCursor(display, blank, blank, | |
&dummy, &dummy, 0, 0); | |
XFreePixmap(display, blank); | |
XDefineCursor(display, window, cursor); | |
} | |
void GameWindow::ResetCursor() { | |
SetCursor(resX / 2, resY / 2); | |
} | |
void GameWindow::SetCursor(int x, int y) { | |
XWarpPointer(display, None, window, 0, 0, 0, 0, x, y); | |
XFlush(display); | |
} | |
void GameWindow::GetCursor(int &x, int &y) { | |
Window root, child; | |
int rootX, rootY; | |
unsigned int mask; | |
if (!XQueryPointer(display,window,&root,&child,&x,&y,&x,&y,&mask)) | |
std::cout << "Could not get cursor position\n"; | |
} | |
int TranslateKey(int key) { | |
switch (key) { | |
case XK_A: case XK_a: return KEY_A; | |
case XK_B: case XK_b: return KEY_B; | |
case XK_C: case XK_c: return KEY_C; | |
case XK_D: case XK_d: return KEY_D; | |
case XK_E: case XK_e: return KEY_E; | |
case XK_F: case XK_f: return KEY_F; | |
case XK_G: case XK_g: return KEY_G; | |
case XK_H: case XK_h: return KEY_H; | |
case XK_I: case XK_i: return KEY_I; | |
case XK_J: case XK_j: return KEY_J; | |
case XK_K: case XK_k: return KEY_K; | |
case XK_L: case XK_l: return KEY_L; | |
case XK_M: case XK_m: return KEY_M; | |
case XK_N: case XK_n: return KEY_N; | |
case XK_O: case XK_o: return KEY_O; | |
case XK_P: case XK_p: return KEY_P; | |
case XK_Q: case XK_q: return KEY_Q; | |
case XK_R: case XK_r: return KEY_R; | |
case XK_S: case XK_s: return KEY_S; | |
case XK_T: case XK_t: return KEY_T; | |
case XK_U: case XK_u: return KEY_U; | |
case XK_V: case XK_v: return KEY_V; | |
case XK_W: case XK_w: return KEY_W; | |
case XK_X: case XK_x: return KEY_X; | |
case XK_Y: case XK_y: return KEY_Y; | |
case XK_Z: case XK_z: return KEY_Z; | |
case XK_Escape: return KEY_ESCAPE; | |
case XK_Tab: return KEY_TAB; | |
case XK_space: return KEY_SPACE; | |
case XK_Control_L: return KEY_LCONTROL; | |
case XK_Control_R: return KEY_CONTROL; | |
case XK_Shift_L: return KEY_LSHIFT; | |
case XK_Shift_R: return KEY_SHIFT; | |
case XK_Alt_L: return KEY_LALT; | |
case XK_Alt_R: return KEY_ALT; | |
case XK_Left: return KEY_LEFT; | |
case XK_Right: return KEY_RIGHT; | |
case XK_Up: return KEY_UP; | |
case XK_Down: return KEY_DOWN; | |
case XK_KP_0: return KEY_NUMPAD_0; | |
case XK_KP_1: return KEY_NUMPAD_1; | |
case XK_KP_2: return KEY_NUMPAD_2; | |
case XK_KP_3: return KEY_NUMPAD_3; | |
case XK_KP_4: return KEY_NUMPAD_4; | |
case XK_KP_5: return KEY_NUMPAD_5; | |
case XK_KP_6: return KEY_NUMPAD_6; | |
case XK_KP_7: return KEY_NUMPAD_7; | |
case XK_KP_8: return KEY_NUMPAD_8; | |
case XK_KP_9: return KEY_NUMPAD_9; | |
case XK_Num_Lock: return KEY_NUMPAD_NUMLOCK; | |
case XK_KP_Divide: return KEY_NUMPAD_DIVIDE; | |
case XK_KP_Multiply: return KEY_NUMPAD_MULTIPLY; | |
case XK_KP_Subtract: return KEY_NUMPAD_SUBTRACT; | |
case XK_KP_Add: return KEY_NUMPAD_ADD; | |
case XK_KP_Enter: return KEY_NUMPAD_ENTER; | |
case XK_KP_Decimal: return KEY_NUMPAD_DOT; | |
case XK_F1: return KEY_F1; | |
case XK_F2: return KEY_F2; | |
case XK_F3: return KEY_F3; | |
case XK_F4: return KEY_F4; | |
case XK_F5: return KEY_F5; | |
case XK_F6: return KEY_F6; | |
case XK_F7: return KEY_F7; | |
case XK_F8: return KEY_F8; | |
case XK_F9: return KEY_F9; | |
case XK_F10:return KEY_F10; | |
case XK_F11:return KEY_F11; | |
case XK_F12:return KEY_F12; | |
case XK_F13:return KEY_F13; | |
case XK_F14:return KEY_F14; | |
case XK_F15:return KEY_F15; | |
case XK_F16:return KEY_F16; | |
case XK_F17:return KEY_F17; | |
case XK_F18:return KEY_F18; | |
case XK_F19:return KEY_F19; | |
case XK_F20:return KEY_F20; | |
case XK_F21:return KEY_F21; | |
case XK_F22:return KEY_F22; | |
case XK_F23:return KEY_F23; | |
case XK_F24:return KEY_F24; | |
case XK_F25:return KEY_F25; | |
case XK_0: return KEY_0; | |
case XK_1: return KEY_1; | |
case XK_2: return KEY_2; | |
case XK_3: return KEY_3; | |
case XK_4: return KEY_4; | |
case XK_5: return KEY_5; | |
case XK_6: return KEY_6; | |
case XK_7: return KEY_7; | |
case XK_8: return KEY_8; | |
case XK_9: return KEY_9; | |
case XK_minus: return KEY_DASH; | |
case XK_equal: return KEY_ADD; | |
case XK_Insert: return KEY_INSERT; | |
case XK_Home: return KEY_HOME; | |
case XK_Page_Up: return KEY_PG_UP; | |
case XK_Page_Down: return KEY_PG_DOWN; | |
case XK_End: return KEY_END; | |
case XK_KP_Delete: return KEY_DELETE; | |
case XK_Pause: return KEY_PAUSE; | |
case XK_Caps_Lock: return KEY_CAPSLOCK; | |
case XK_Scroll_Lock: return KEY_SCROLL_LOCK; | |
case XK_comma: return KEY_COMMA; | |
case XK_period: return KEY_PERIOD; | |
case XK_slash: return KEY_FORWARD_SLASH; | |
case XK_backslash: return KEY_BACK_SLASH; | |
case XK_semicolon: return KEY_SEMICOLON; | |
case XK_apostrophe: return KEY_APOSTROPHE; | |
case XK_bracketleft: return KEY_LBRACKET; | |
case XK_bracketright: return KEY_RBRACKET; | |
case XK_Return: return KEY_ENTER; | |
case XK_BackSpace: return KEY_BACKSPACE; | |
case XK_grave: return KEY_TILDE; | |
default: return -1; | |
} | |
} | |
void GameWindow::HandleEvents() { | |
if (input == NULL) { | |
std::cout << "No Interface!" << std::endl; | |
return; | |
} | |
XWindowAttributes attribs; | |
char str[25] = {0}; | |
KeySym keysym = 0; | |
int len = 0; | |
XEvent ev; | |
while (XPending(display) > 0) { | |
XNextEvent(display, &ev); | |
switch(ev.type) { | |
case KeymapNotify: | |
XRefreshKeyboardMapping(&ev.xmapping); | |
break; | |
case KeyPress: | |
len = XLookupString(&ev.xkey, str, 25, &keysym, NULL); | |
input->SetKey(TranslateKey(keysym), true); | |
break; | |
case KeyRelease: | |
len = XLookupString(&ev.xkey, str, 25, &keysym, NULL); | |
input->SetKey(TranslateKey(keysym), false); | |
break; | |
case ButtonPress: | |
input->SetMouseButton(ev.xbutton.button-1, true); | |
break; | |
case ButtonRelease: | |
input->SetMouseButton(ev.xbutton.button-1, false); | |
break; | |
case MotionNotify: | |
input->SetMousePosition(ev.xmotion.x, ev.xmotion.y); | |
break; | |
case FocusIn: | |
input->SetFocused(true); | |
break; | |
case FocusOut: | |
input->SetFocused(false); | |
break; | |
case DestroyNotify: | |
input->ForceQuit(); | |
break; | |
/*case Expose: { | |
//XWindowAttributes attribs; | |
std::cout << "Expose event fired: " << "\n"; | |
XGetWindowAttributes(display, window, &attribs); | |
//std::cout << "\tWindow Width: " << attribs.width << ", Height: " << attribs.height << "\n"; | |
} | |
break;*/ | |
} | |
} | |
} | |
void GameWindow::GetHandles(Display* dpy, Window *win, Screen* scrn, int id) { | |
Display* display; | |
Window window; | |
Screen *screen; | |
id = screenID; | |
} | |
void GameWindow::Shutdown() { | |
delete this; | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment