#if defined(USE_OPENGL_API) #include "MiniFB_GL.h" #include "MiniFB_internal.h" #if defined(_WIN32) || defined(WIN32) #include #include #elif defined(linux) #include #include #include #endif #include #include //#define kUse_Clean_UP #if defined(kUse_Clean_UP) #define UseCleanUp(x) x #else #define UseCleanUp(x) #endif extern double g_time_for_frame; extern bool g_use_hardware_sync; //------------------------------------- #if defined(_WIN32) || defined(WIN32) bool setup_pixel_format(HDC hDC) { int pixelFormat; PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // size 1, // version PFD_SUPPORT_OPENGL | // PFD_DRAW_TO_WINDOW | // PFD_DOUBLEBUFFER, // support double-buffering PFD_TYPE_RGBA, // color type 24, // preferred color depth 0, 0, 0, 0, 0, 0, // color and shift bits (ignored) 0, // no alpha buffer 0, // alpha bits (ignored) 0, // no accumulation buffer 0, 0, 0, 0, // accum bits (ignored) 24, // depth buffer 8, // no stencil buffer 0, // no auxiliary buffers PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0, // no layer, visible, damage masks }; pixelFormat = ChoosePixelFormat(hDC, &pfd); if (pixelFormat == 0) { MessageBox(WindowFromDC(hDC), "ChoosePixelFormat failed.", "Error", MB_ICONERROR | MB_OK); return false; } if (SetPixelFormat(hDC, pixelFormat, &pfd) != TRUE) { MessageBox(WindowFromDC(hDC), "SetPixelFormat failed.", "Error", MB_ICONERROR | MB_OK); return false; } return true; } typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int); typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC)(void); PFNWGLSWAPINTERVALEXTPROC SwapIntervalEXT = 0x0; PFNWGLGETSWAPINTERVALEXTPROC GetSwapIntervalEXT = 0x0; #elif defined(linux) bool setup_pixel_format(SWindowData_X11 *window_data_x11) { GLint glxAttribs[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, 8, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, GLX_DEPTH_SIZE, 24, GLX_STENCIL_SIZE, 8, GLX_SAMPLE_BUFFERS, 0, GLX_SAMPLES, 0, None }; XVisualInfo* visualInfo = glXChooseVisual(window_data_x11->display, window_data_x11->screen, glxAttribs); if (visualInfo == 0) { fprintf(stderr, "Could not create correct visual window.\n"); XCloseDisplay(window_data_x11->display); return false; } window_data_x11->context = glXCreateContext(window_data_x11->display, visualInfo, NULL, GL_TRUE); return true; } typedef void (*PFNGLXSWAPINTERVALEXTPROC)(Display*,GLXDrawable,int); PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT = 0x0; #endif //------------------------------------- bool create_GL_context(SWindowData *window_data) { #if defined(_WIN32) || defined(WIN32) SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific; if (setup_pixel_format(window_data_win->hdc) == false) return false; window_data_win->hGLRC = wglCreateContext(window_data_win->hdc); wglMakeCurrent(window_data_win->hdc, window_data_win->hGLRC); init_GL(window_data); SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) wglGetProcAddress("wglSwapIntervalEXT"); GetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC) wglGetProcAddress("wglGetSwapIntervalEXT"); set_target_fps_aux(); return true; #elif defined(linux) SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; GLint majorGLX, minorGLX = 0; glXQueryVersion(window_data_x11->display, &majorGLX, &minorGLX); if (majorGLX <= 1 && minorGLX < 2) { fprintf(stderr, "GLX 1.2 or greater is required.\n"); XCloseDisplay(window_data_x11->display); return false; } else { //fprintf(stdout, "GLX version: %d.%d\n", majorGLX, minorGLX); } if (setup_pixel_format(window_data_x11) == false) return false; glXMakeCurrent(window_data_x11->display, window_data_x11->window, window_data_x11->context); //fprintf(stdout, "GL Vendor: %s\n", glGetString(GL_VENDOR)); //fprintf(stdout, "GL Renderer: %s\n", glGetString(GL_RENDERER)); //fprintf(stdout, "GL Version: %s\n", glGetString(GL_VERSION)); //fprintf(stdout, "GL Shading Language: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION)); init_GL(window_data); SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) glXGetProcAddress("glXSwapIntervalEXT"); set_target_fps_aux(); return true; #endif } //------------------------------------- void destroy_GL_context(SWindowData *window_data) { #if defined(_WIN32) || defined(WIN32) SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific; if (window_data_win->hGLRC) { wglMakeCurrent(NULL, NULL); wglDeleteContext(window_data_win->hGLRC); window_data_win->hGLRC = 0; } #elif defined(linux) SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; glXDestroyContext(window_data_x11->display, window_data_x11->context); #endif } //------------------------------------- #if defined(RGB) #undef RGB #endif #define TEXTURE0 0x84C0 // [ Core in gl 1.3, gles1 1.0, gles2 2.0, glsc2 2.0, Provided by GL_ARB_multitexture (gl) ] #define RGB 0x1907 // [ Core in gl 1.0, gles1 1.0, gles2 2.0, glsc2 2.0 ] #define RGBA 0x1908 // [ Core in gl 1.0, gles1 1.0, gles2 2.0, glsc2 2.0 ] #define BGR 0x80E0 // [ Core in gl 1.2 ] #define BGRA 0x80E1 // [ Core in gl 1.2, Provided by GL_ARB_vertex_array_bgra (gl|glcore) ] //------------------------------------- void init_GL(SWindowData *window_data) { #if defined(_WIN32) || defined(WIN32) SWindowData_Win *window_data_ex = (SWindowData_Win *) window_data->specific; #elif defined(linux) SWindowData_X11 *window_data_ex = (SWindowData_X11 *) window_data->specific; #endif glViewport(0, 0, window_data->window_width, window_data->window_height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, window_data->window_width, window_data->window_height, 0, 2048, -2048); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glDisable(GL_DEPTH_TEST); glDisable(GL_STENCIL_TEST); glEnable(GL_TEXTURE_2D); glGenTextures(1, &window_data_ex->text_id); //glActiveTexture(TEXTURE0); glBindTexture(GL_TEXTURE_2D, window_data_ex->text_id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); UseCleanUp(glDisableClientState(GL_TEXTURE_COORD_ARRAY)); UseCleanUp(glDisableClientState(GL_VERTEX_ARRAY)); UseCleanUp(glBindTexture(GL_TEXTURE_2D, 0)); } //------------------------------------- void resize_GL(SWindowData *window_data) { if (window_data->is_initialized) { #if defined(_WIN32) || defined(WIN32) SWindowData_Win *window_data_ex = (SWindowData_Win *) window_data->specific; wglMakeCurrent(window_data_ex->hdc, window_data_ex->hGLRC); #elif defined(linux) SWindowData_X11 *window_data_ex = (SWindowData_X11 *) window_data->specific; glXMakeCurrent(window_data_ex->display, window_data_ex->window, window_data_ex->context); #endif glViewport(0, 0, window_data->window_width, window_data->window_height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, window_data->window_width, window_data->window_height, 0, 2048, -2048); glClear(GL_COLOR_BUFFER_BIT); } } //------------------------------------- void redraw_GL(SWindowData *window_data, const void *pixels) { #if defined(_WIN32) || defined(WIN32) SWindowData_Win *window_data_ex = (SWindowData_Win *) window_data->specific; GLenum format = BGRA; wglMakeCurrent(window_data_ex->hdc, window_data_ex->hGLRC); #elif defined(linux) SWindowData_X11 *window_data_ex = (SWindowData_X11 *) window_data->specific; GLenum format = BGRA; glXMakeCurrent(window_data_ex->display, window_data_ex->window, window_data_ex->context); #endif float x, y, w, h; x = (float) window_data->dst_offset_x; y = (float) window_data->dst_offset_y; w = (float) window_data->dst_offset_x + window_data->dst_width; h = (float) window_data->dst_offset_y + window_data->dst_height; float vertices[] = { x, y, 0, 0, w, y, 1, 0, x, h, 0, 1, w, h, 1, 1, }; glClear(GL_COLOR_BUFFER_BIT); UseCleanUp(glBindTexture(GL_TEXTURE_2D, window_data_ex->text_id)); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, window_data->buffer_width, window_data->buffer_height, 0, format, GL_UNSIGNED_BYTE, pixels); //glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, window_data->buffer_width, window_data->buffer_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); UseCleanUp(glEnableClientState(GL_VERTEX_ARRAY)); UseCleanUp(glEnableClientState(GL_TEXTURE_COORD_ARRAY)); glVertexPointer(2, GL_FLOAT, 4 * sizeof(float), vertices); glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), vertices + 2); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); UseCleanUp(glDisableClientState(GL_TEXTURE_COORD_ARRAY)); UseCleanUp(glDisableClientState(GL_VERTEX_ARRAY)); UseCleanUp(glBindTexture(GL_TEXTURE_2D, 0)); #if defined(_WIN32) || defined(WIN32) SwapBuffers(window_data_ex->hdc); #elif defined(linux) glXSwapBuffers(window_data_ex->display, window_data_ex->window); #endif } //------------------------------------- void set_target_fps_aux() { // Assuming the monitor refresh rate is 60 hz int interval = (int) ((60.0 * g_time_for_frame) + 0.5); #if defined(_WIN32) || defined(WIN32) if (SwapIntervalEXT != 0x0) { bool success = SwapIntervalEXT(interval); if (GetSwapIntervalEXT != 0x0) { int currentInterval = GetSwapIntervalEXT(); if (interval != currentInterval) { fprintf(stderr, "Cannot set target swap interval. Current swap interval is %d\n", currentInterval); } } else if (success == false) { fprintf(stderr, "Cannot set target swap interval.\n"); } g_use_hardware_sync = true; } #elif defined(linux) #define kGLX_SWAP_INTERVAL_EXT 0x20F1 #define kGLX_MAX_SWAP_INTERVAL_EXT 0x20F2 if (SwapIntervalEXT != 0x0) { Display *dpy = glXGetCurrentDisplay(); GLXDrawable drawable = glXGetCurrentDrawable(); unsigned int currentInterval, maxInterval; SwapIntervalEXT(dpy, drawable, interval); glXQueryDrawable(dpy, drawable, kGLX_SWAP_INTERVAL_EXT, ¤tInterval); if (interval != currentInterval) { glXQueryDrawable(dpy, drawable, kGLX_MAX_SWAP_INTERVAL_EXT, &maxInterval); fprintf(stderr, "Cannot set target swap interval. Current swap interval is %d (max: %d)\n", currentInterval, maxInterval); } g_use_hardware_sync = true; } #endif } #endif