Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
  3.  * It is copyright by its individual contributors, as recorded in the
  4.  * project's Git history.  See COPYING.txt at the top level for license
  5.  * terms and a link to the Git history.
  6.  */
  7. /*
  8.  *
  9.  * OGL video functions. - Added 9/15/99 Matthew Mueller
  10.  *
  11.  */
  12.  
  13. #define DECLARE_VARS
  14.  
  15. #ifdef RPI
  16. // extra libraries for the Raspberry Pi
  17. #include  <bcm_host.h>
  18. #endif
  19.  
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #ifdef _MSC_VER
  24. #include <windows.h>
  25. #endif
  26.  
  27. #if !defined(_MSC_VER) && !defined(macintosh)
  28. #include <unistd.h>
  29. #endif
  30. #if !defined(macintosh)
  31. #include <sys/types.h>
  32. #include <sys/stat.h>
  33. #include <fcntl.h>
  34. #endif
  35.  
  36. #include <algorithm>
  37. #include <errno.h>
  38. #include <SDL.h>
  39. #include "hudmsg.h"
  40. #include "game.h"
  41. #include "text.h"
  42. #include "gr.h"
  43. #include "gamefont.h"
  44. #include "grdef.h"
  45. #include "palette.h"
  46. #include "u_mem.h"
  47. #include "dxxerror.h"
  48. #include "inferno.h"
  49. #include "screens.h"
  50. #include "strutil.h"
  51. #include "args.h"
  52. #include "key.h"
  53. #include "physfsx.h"
  54. #include "internal.h"
  55. #include "render.h"
  56. #include "console.h"
  57. #include "config.h"
  58. #include "playsave.h"
  59. #include "vers_id.h"
  60.  
  61. #if defined(__APPLE__) && defined(__MACH__)
  62. #include <OpenGL/glu.h>
  63. #else
  64. #if DXX_USE_OGLES
  65. #include <EGL/egl.h>
  66. #include <X11/Xlib.h>
  67. #include <X11/Xutil.h>
  68. #include <SDL_syswm.h>
  69. #else
  70. #include <GL/glu.h>
  71. #endif
  72. #endif
  73.  
  74. #include "ogl_sync.h"
  75. #include <memory>
  76.  
  77. using std::min;
  78. using std::max;
  79.  
  80. namespace dcx {
  81.  
  82. static int ogl_brightness_r, ogl_brightness_g, ogl_brightness_b;
  83.  
  84. #if DXX_USE_OGLES
  85. static int sdl_video_flags;
  86.  
  87. #ifdef RPI
  88. static EGL_DISPMANX_WINDOW_T nativewindow;
  89. static DISPMANX_ELEMENT_HANDLE_T dispman_element=DISPMANX_NO_HANDLE;
  90. static DISPMANX_DISPLAY_HANDLE_T dispman_display=DISPMANX_NO_HANDLE;
  91. #endif
  92.  
  93. #else
  94. #if SDL_MAJOR_VERSION == 1
  95. static int sdl_video_flags = SDL_OPENGL;
  96. #elif SDL_MAJOR_VERSION == 2
  97. SDL_Window *g_pRebirthSDLMainWindow;
  98. static int g_iRebirthWindowX, g_iRebirthWindowY;
  99. #endif
  100. #endif
  101. static ogl_sync sync_helper;
  102. static int gr_installed;
  103. static int gl_initialized;
  104. int linedotscale=1; // scalar of glLinewidth and glPointSize - only calculated once when resolution changes
  105. #ifdef RPI
  106. static int sdl_no_modeswitch;
  107. #else
  108. enum { sdl_no_modeswitch = 0 };
  109. #endif
  110.  
  111. }
  112.  
  113. namespace dsx {
  114.  
  115. #if SDL_MAJOR_VERSION == 1
  116. void gr_set_mode_from_window_size()
  117. {
  118.         gr_set_mode(Game_screen_mode);
  119. }
  120. #elif SDL_MAJOR_VERSION == 2
  121. static void gr_set_mode_from_window_size(SDL_Window *const SDLWindow)
  122. {
  123.         assert(SDLWindow);
  124.         int w, h;
  125.         SDL_GL_GetDrawableSize(SDLWindow, &w, &h);
  126.         gr_set_mode(screen_mode(w, h));
  127. }
  128.  
  129. void gr_set_mode_from_window_size()
  130. {
  131.         gr_set_mode_from_window_size(g_pRebirthSDLMainWindow);
  132. }
  133. #endif
  134.  
  135. }
  136.  
  137. #if DXX_USE_OGLES
  138. static EGLDisplay eglDisplay=EGL_NO_DISPLAY;
  139. static EGLConfig eglConfig;
  140. static EGLSurface eglSurface=EGL_NO_SURFACE;
  141. static EGLContext eglContext=EGL_NO_CONTEXT;
  142.  
  143. static bool TestEGLError(const char* pszLocation)
  144. {
  145.         /*
  146.          * eglGetError returns the last error that has happened using egl,
  147.          * not the status of the last called function. The user has to
  148.          * check after every single egl call or at least once every frame.
  149.         */
  150.         EGLint iErr = eglGetError();
  151.         if (iErr != EGL_SUCCESS)
  152.         {
  153.                 con_printf(CON_URGENT, "%s failed (%d).", pszLocation, iErr);
  154.                 return 0;
  155.         }
  156.        
  157.         return 1;
  158. }
  159. #endif
  160.  
  161. namespace dcx {
  162.  
  163. void ogl_swap_buffers_internal(void)
  164. {
  165.         sync_helper.before_swap();
  166. #if DXX_USE_OGLES
  167.         eglSwapBuffers(eglDisplay, eglSurface);
  168. #else
  169. #if SDL_MAJOR_VERSION == 1
  170.         SDL_GL_SwapBuffers();
  171. #elif SDL_MAJOR_VERSION == 2
  172.         SDL_GL_SwapWindow(g_pRebirthSDLMainWindow);
  173. #endif
  174. #endif
  175.         sync_helper.after_swap();
  176. }
  177.  
  178. }
  179.  
  180. namespace dsx {
  181.  
  182. #ifdef RPI
  183.  
  184. // MH: I got the following constants for vc_dispmanx_element_change_attributes() from:
  185. //     http://qt.gitorious.org/qt/qtbase/commit/5933205cfcd73481cb0645fa6183103063fe3e0d
  186. //     I do not know where they got them from, but OTOH, they are quite obvious.
  187.  
  188. // these constants are not in any headers (yet)
  189. #define ELEMENT_CHANGE_LAYER          (1<<0)
  190. #define ELEMENT_CHANGE_OPACITY        (1<<1)
  191. #define ELEMENT_CHANGE_DEST_RECT      (1<<2)
  192. #define ELEMENT_CHANGE_SRC_RECT       (1<<3)
  193. #define ELEMENT_CHANGE_MASK_RESOURCE  (1<<4)
  194. #define ELEMENT_CHANGE_TRANSFORM      (1<<5)
  195.  
  196. static void rpi_destroy_element()
  197. {
  198.         if (dispman_element != DISPMANX_NO_HANDLE) {
  199.                 DISPMANX_UPDATE_HANDLE_T dispman_update;
  200.                 con_printf(CON_DEBUG, "RPi: destroying display manager element");
  201.                 dispman_update = vc_dispmanx_update_start( 0 );
  202.                 if (vc_dispmanx_element_remove( dispman_update, dispman_element)) {
  203.                          con_printf(CON_URGENT, "RPi: failed to remove dispmanx element!");
  204.                 }
  205.                 vc_dispmanx_update_submit_sync( dispman_update );
  206.                 dispman_element = DISPMANX_NO_HANDLE;
  207.         }
  208. }
  209.  
  210. static int rpi_setup_element(int x, int y, Uint32 video_flags, int update)
  211. {
  212.         // this code is based on the work of Ben O'Steen
  213.         // http://benosteen.wordpress.com/2012/04/27/using-opengl-es-2-0-on-the-raspberry-pi-without-x-windows/
  214.         // https://github.com/benosteen/opengles-book-samples/tree/master/Raspi
  215.         DISPMANX_UPDATE_HANDLE_T dispman_update;
  216.         VC_RECT_T dst_rect;
  217.         VC_RECT_T src_rect;
  218.         VC_DISPMANX_ALPHA_T alpha_descriptor;
  219.  
  220.         uint32_t rpi_display_device=DISPMANX_ID_MAIN_LCD;
  221.         uint32_t display_width;
  222.         uint32_t display_height;
  223.         int success;
  224.  
  225.         success = graphics_get_display_size(rpi_display_device, &display_width, &display_height);
  226.         if ( success < 0 ) {
  227.                 con_printf(CON_URGENT, "Could not get RPi display size, assuming 640x480");
  228.                 display_width=640;
  229.                 display_height=480;
  230.         }
  231.  
  232.         if (static_cast<uint32_t>(x) > display_width) {
  233.                 con_printf(CON_URGENT, "RPi: Requested width %d exceeds display width %u, scaling down!",
  234.                         x,display_width);
  235.                 x=static_cast<int>(display_width);
  236.         }
  237.         if (static_cast<uint32_t>(y) > display_height) {
  238.                 con_printf(CON_URGENT, "RPi: Requested height %d exceeds display height %u, scaling down!",
  239.                         y,display_height);
  240.                 y=static_cast<int>(display_height);
  241.         }
  242.  
  243.         con_printf(CON_DEBUG, "RPi: display resolution %ux%u, game resolution: %dx%d (%s)", display_width, display_height, x, y, (video_flags & SDL_FULLSCREEN)?"fullscreen":"windowed");
  244.         if (video_flags & SDL_FULLSCREEN) {
  245.                 /* scale to the full display size... */
  246.                 dst_rect.x = 0;
  247.                 dst_rect.y = 0;
  248.                 dst_rect.width = display_width;
  249.                 dst_rect.height= display_height;
  250.         } else {
  251.                 /* TODO: we could query the position of the X11 window here
  252.                    and try to place the ovelray exactly above that...,
  253.                    we would have to track window movements, though ... */
  254.                 dst_rect.x = 0;
  255.                 dst_rect.y = 0;
  256.                 dst_rect.width = static_cast<uint32_t>(x);
  257.                 dst_rect.height= static_cast<uint32_t>(y);
  258.         }
  259.  
  260.         src_rect.x = 0;
  261.         src_rect.y = 0;
  262.         src_rect.width = (static_cast<uint32_t>(x))<< 16;
  263.         src_rect.height =(static_cast<uint32_t>(y))<< 16;
  264.  
  265.         /* we do not want our overlay to be blended against the background */
  266.         alpha_descriptor.flags=DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS;
  267.         alpha_descriptor.opacity=0xffffffff;
  268.         alpha_descriptor.mask=0;
  269.  
  270.         // open display, if we do not already have one ...
  271.         if (dispman_display == DISPMANX_NO_HANDLE) {
  272.                 con_printf(CON_DEBUG, "RPi: opening display: %u",rpi_display_device);
  273.                 dispman_display = vc_dispmanx_display_open(rpi_display_device);
  274.                 if (dispman_display == DISPMANX_NO_HANDLE) {
  275.                         con_printf(CON_URGENT,"RPi: failed to open display: %u",rpi_display_device);
  276.                 }
  277.         }
  278.  
  279.         if (dispman_element != DISPMANX_NO_HANDLE) {
  280.                 if (!update) {
  281.                         // if the element already exists, and we cannot update it, so recreate it
  282.                         rpi_destroy_element();
  283.                 }
  284.         } else {
  285.                 // if the element does not exist, we cannot do an update
  286.                 update=0;
  287.         }
  288.  
  289.         dispman_update = vc_dispmanx_update_start( 0 );
  290.  
  291.         if (update) {
  292.                 con_printf(CON_DEBUG, "RPi: updating display manager element");
  293.                 vc_dispmanx_element_change_attributes ( dispman_update, nativewindow.element,
  294.                                                         ELEMENT_CHANGE_DEST_RECT | ELEMENT_CHANGE_SRC_RECT,
  295.                                                         0 /*layer*/, 0 /*opacity*/,
  296.                                                         &dst_rect, &src_rect,
  297.                                                         0 /*mask*/,
  298.                                                         static_cast<DISPMANX_TRANSFORM_T>(VC_IMAGE_ROT0) /*transform*/);
  299.         } else {
  300.                 // create a new element
  301.                 con_printf(CON_DEBUG, "RPi: creating display manager element");
  302.                 dispman_element = vc_dispmanx_element_add ( dispman_update, dispman_display,
  303.                                                                 0 /*layer*/, &dst_rect, 0 /*src*/,
  304.                                                                 &src_rect, DISPMANX_PROTECTION_NONE,
  305.                                                                 &alpha_descriptor, NULL /*clamp*/,
  306.                                                                 static_cast<DISPMANX_TRANSFORM_T>(VC_IMAGE_ROT0) /*transform*/);
  307.                 if (dispman_element == DISPMANX_NO_HANDLE) {
  308.                         con_printf(CON_URGENT,"RPi: failed to creat display manager elemenr");
  309.                 }
  310.                 nativewindow.element = dispman_element;
  311.         }
  312.         nativewindow.width = display_width;
  313.         nativewindow.height = display_height;
  314.         vc_dispmanx_update_submit_sync( dispman_update );
  315.  
  316.         return 0;
  317. }
  318.  
  319. #endif // RPI
  320.  
  321. #if DXX_USE_OGLES
  322. static void ogles_destroy()
  323. {
  324.         if( eglDisplay != EGL_NO_DISPLAY ) {
  325.                 eglMakeCurrent(eglDisplay, NULL, NULL, EGL_NO_CONTEXT);
  326.         }
  327.  
  328.         if (eglContext != EGL_NO_CONTEXT) {
  329.                 con_printf(CON_DEBUG, "EGL: destroyig context");
  330.                 eglDestroyContext(eglDisplay, eglContext);
  331.                 eglContext = EGL_NO_CONTEXT;
  332.         }
  333.  
  334.         if (eglSurface != EGL_NO_SURFACE) {
  335.                 con_printf(CON_DEBUG, "EGL: destroyig surface");
  336.                 eglDestroySurface(eglDisplay, eglSurface);
  337.                 eglSurface = EGL_NO_SURFACE;
  338.         }
  339.  
  340.         if (eglDisplay != EGL_NO_DISPLAY) {
  341.                 con_printf(CON_DEBUG, "EGL: terminating");
  342.                 eglTerminate(eglDisplay);
  343.                 eglDisplay = EGL_NO_DISPLAY;
  344.         }
  345. }
  346. #endif
  347.  
  348. static int ogl_init_window(int w, int h)
  349. {
  350. #if DXX_USE_OGLES
  351.         SDL_SysWMinfo info;
  352.         Window    x11Window = 0;
  353.         Display*  x11Display = 0;
  354.         EGLint    ver_maj, ver_min;
  355.         EGLint configAttribs[] =
  356.         {
  357.                 EGL_RED_SIZE, 5,
  358.                 EGL_GREEN_SIZE, 6,
  359.                 EGL_BLUE_SIZE, 5,
  360.                 EGL_DEPTH_SIZE, 16,
  361.                 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
  362.                 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
  363.                 EGL_NONE, EGL_NONE
  364.         };
  365.  
  366.         // explicitely request an OpenGL ES 1.x context
  367.         EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE, EGL_NONE };
  368.         // explicitely request a doublebuffering window
  369.         EGLint winAttribs[] = { EGL_RENDER_BUFFER, EGL_BACK_BUFFER, EGL_NONE, EGL_NONE };
  370.  
  371.         int iConfigs;
  372. #endif // OGLES
  373.  
  374. #if SDL_MAJOR_VERSION == 1
  375.         if (gl_initialized)
  376.                 ogl_smash_texture_list_internal();//if we are or were fullscreen, changing vid mode will invalidate current textures
  377.  
  378.         SDL_WM_SetCaption(DESCENT_VERSION, DXX_SDL_WINDOW_CAPTION);
  379.         if (const auto window_icon = SDL_LoadBMP(DXX_SDL_WINDOW_ICON_BITMAP))
  380.                 SDL_WM_SetIcon(window_icon, nullptr);
  381.  
  382.         int use_x = w;
  383.         int use_y = h;
  384.         int use_bpp = CGameArg.DbgBpp;
  385.         int use_flags = sdl_video_flags;
  386.         if (sdl_no_modeswitch) {
  387.                 const SDL_VideoInfo *vinfo=SDL_GetVideoInfo();
  388.                 if (vinfo) {   
  389.                         use_x=vinfo->current_w;
  390.                         use_y=vinfo->current_h;
  391.                         use_bpp=vinfo->vfmt->BitsPerPixel;
  392.                         use_flags=SDL_SWSURFACE | SDL_ANYFORMAT;
  393.                 } else {
  394.                         con_printf(CON_URGENT, "Could not query video info");
  395.                 }
  396.         }
  397.  
  398.         if (!SDL_SetVideoMode(use_x, use_y, use_bpp, use_flags))
  399.         {
  400. #ifdef RPI
  401.                 con_printf(CON_URGENT, "Could not set %dx%dx%d opengl video mode: %s\n (Ignored for RPI)",
  402.                             w, h, CGameArg.DbgBpp, SDL_GetError());
  403. #else
  404.                 Error("Could not set %dx%dx%d opengl video mode: %s\n", w, h, CGameArg.DbgBpp, SDL_GetError());
  405. #endif
  406.         }
  407. #elif SDL_MAJOR_VERSION == 2
  408.         const auto SDLWindow = g_pRebirthSDLMainWindow;
  409.         if (!(SDL_GetWindowFlags(SDLWindow) & SDL_WINDOW_FULLSCREEN))
  410.                 SDL_SetWindowSize(SDLWindow, w, h);
  411. #endif
  412.  
  413. #if DXX_USE_OGLES
  414. #ifndef RPI
  415.         // NOTE: on the RPi, the EGL stuff is not connected to the X11 window,
  416.         //       so there is no need to destroy and recreate this
  417.         ogles_destroy();
  418. #endif
  419.  
  420.         SDL_VERSION(&info.version);
  421.        
  422.         if (SDL_GetWMInfo(&info) > 0) {
  423.                 if (info.subsystem == SDL_SYSWM_X11) {
  424.                         x11Display = info.info.x11.display;
  425.                         x11Window = info.info.x11.window;
  426.                         con_printf (CON_DEBUG, "Display: %p, Window: %i ===", x11Display, static_cast<int>(x11Window));
  427.                 }
  428.         }
  429.  
  430.         if (eglDisplay == EGL_NO_DISPLAY) {
  431. #ifdef RPI
  432.                 eglDisplay = eglGetDisplay((EGLNativeDisplayType)EGL_DEFAULT_DISPLAY);
  433. #else
  434.                 eglDisplay = eglGetDisplay((EGLNativeDisplayType)x11Display);
  435. #endif
  436.                 if (eglDisplay == EGL_NO_DISPLAY) {
  437.                         con_printf(CON_URGENT, "EGL: Error querying EGL Display");
  438.                 }
  439.  
  440.                 if (!eglInitialize(eglDisplay, &ver_maj, &ver_min)) {
  441.                         con_printf(CON_URGENT, "EGL: Error initializing EGL");
  442.                 } else {
  443.                         con_printf(CON_DEBUG, "EGL: Initialized, version: major %i minor %i", ver_maj, ver_min);
  444.                 }
  445.         }
  446.  
  447.        
  448. #ifdef RPI
  449.         if (rpi_setup_element(w,h,sdl_video_flags,1)) {
  450.                 Error("RPi: Could not set up a %dx%d element\n", w, h);
  451.         }
  452. #endif
  453.  
  454.         if (eglSurface == EGL_NO_SURFACE) {
  455.                 if (!eglChooseConfig(eglDisplay, configAttribs, &eglConfig, 1, &iConfigs) || (iConfigs != 1)) {
  456.                         con_printf(CON_URGENT, "EGL: Error choosing config");
  457.                 } else {
  458.                         con_printf(CON_DEBUG, "EGL: config chosen");
  459.                 }
  460.  
  461. #ifdef RPI
  462.                 eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, static_cast<EGLNativeWindowType>(&nativewindow), winAttribs);
  463. #else
  464.                 eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, static_cast<NativeWindowType>(x11Window), winAttribs);
  465. #endif
  466.                 if ((!TestEGLError("eglCreateWindowSurface")) || eglSurface == EGL_NO_SURFACE) {
  467.                         con_printf(CON_URGENT, "EGL: Error creating window surface");
  468.                 } else {
  469.                         con_printf(CON_DEBUG, "EGL: Created window surface");
  470.                 }
  471.         }
  472.        
  473.         if (eglContext == EGL_NO_CONTEXT) {
  474.                 eglContext = eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, contextAttribs);
  475.                 if ((!TestEGLError("eglCreateContext")) || eglContext == EGL_NO_CONTEXT) {
  476.                         con_printf(CON_URGENT, "EGL: Error creating context");
  477.                 } else {
  478.                         con_printf(CON_DEBUG, "EGL: Created context");
  479.                 }
  480.         }
  481.        
  482.         eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
  483.         if (!TestEGLError("eglMakeCurrent")) {
  484.                 con_printf(CON_URGENT, "EGL: Error making current");
  485.         } else {
  486.                 con_printf(CON_DEBUG, "EGL: made context current");
  487.         }
  488. #endif
  489.  
  490.         const auto w640 = w / 640;
  491.         const auto h480 = h / 480;
  492.         const auto min_wh = std::min(w640, h480);
  493.         linedotscale = min_wh < 1 ? 1 : min_wh;
  494.  
  495.         gl_initialized=1;
  496.         return 0;
  497. }
  498.  
  499. }
  500.  
  501. namespace dcx {
  502.  
  503. int gr_check_fullscreen(void)
  504. {
  505. #if SDL_MAJOR_VERSION == 1
  506.         return !!(sdl_video_flags & SDL_FULLSCREEN);
  507. #elif SDL_MAJOR_VERSION == 2
  508.         return !!(SDL_GetWindowFlags(g_pRebirthSDLMainWindow) & SDL_WINDOW_FULLSCREEN);
  509. #endif
  510. }
  511.  
  512. void gr_toggle_fullscreen()
  513. {
  514. #if SDL_MAJOR_VERSION == 1
  515.         const auto local_sdl_video_flags = (sdl_video_flags ^= SDL_FULLSCREEN);
  516.         if (gl_initialized)
  517.         {
  518.                 if (sdl_no_modeswitch == 0) {
  519.                         auto gsm = Game_screen_mode;
  520.                         const auto DbgBpp = CGameArg.DbgBpp;
  521.                         if (!SDL_VideoModeOK(gsm.width, gsm.height, DbgBpp, local_sdl_video_flags))
  522.                         {
  523.                                 con_printf(CON_URGENT, "Cannot set %ix%i. Fallback to 640x480", gsm.width, gsm.height);
  524.                                 gsm.width = 640;
  525.                                 gsm.height = 480;
  526.                                 Game_screen_mode = gsm;
  527.                         }
  528.                         if (!SDL_SetVideoMode(gsm.width, gsm.height, DbgBpp, local_sdl_video_flags))
  529.                         {
  530.                                 Error("Could not set %dx%dx%d opengl video mode: %s\n", gsm.width, gsm.height, DbgBpp, SDL_GetError());
  531.                         }
  532.                 }
  533. #ifdef RPI
  534.                 if (rpi_setup_element(SM_W(Game_screen_mode), SM_H(Game_screen_mode), local_sdl_video_flags, 1)) {
  535.                          Error("RPi: Could not set up %dx%d element\n", SM_W(Game_screen_mode), SM_H(Game_screen_mode));
  536.                 }
  537. #endif
  538.         }
  539.  
  540.         gr_remap_color_fonts();
  541.  
  542.         if (gl_initialized) // update viewing values for menus
  543.         {
  544.                 glMatrixMode(GL_PROJECTION);
  545.                 glLoadIdentity();
  546. #if DXX_USE_OGLES
  547.                 glOrthof(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
  548. #else
  549.                 glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
  550. #endif
  551.                 glMatrixMode(GL_MODELVIEW);
  552.                 glLoadIdentity();//clear matrix
  553.                 glEnable(GL_BLEND);
  554.                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  555.                 ogl_smash_texture_list_internal();//if we are or were fullscreen, changing vid mode will invalidate current textures
  556.         }
  557.         CGameCfg.WindowMode = !(local_sdl_video_flags & SDL_FULLSCREEN);
  558. #elif SDL_MAJOR_VERSION == 2
  559.         const auto SDLWindow = g_pRebirthSDLMainWindow;
  560.         const auto is_fullscreen_before_change = SDL_GetWindowFlags(SDLWindow) & SDL_WINDOW_FULLSCREEN;
  561.         CGameCfg.WindowMode = !!is_fullscreen_before_change;
  562.         if (!is_fullscreen_before_change)
  563.                 SDL_GetWindowPosition(SDLWindow, &g_iRebirthWindowX, &g_iRebirthWindowY);
  564.         SDL_SetWindowFullscreen(SDLWindow, is_fullscreen_before_change ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP);
  565.         if (is_fullscreen_before_change)
  566.         {
  567.                 const auto mode = Game_screen_mode;
  568.                 SDL_SetWindowPosition(SDLWindow, g_iRebirthWindowX, g_iRebirthWindowY);
  569.                 SDL_SetWindowSize(SDLWindow, SM_W(mode), SM_H(mode));
  570.         }
  571.         gr_set_mode_from_window_size(SDLWindow);
  572. #endif
  573. }
  574.  
  575. static void ogl_init_state(void)
  576. {
  577.         /* select clearing (background) color   */
  578.         glClearColor(0.0, 0.0, 0.0, 0.0);
  579.  
  580.         /* initialize viewing values */
  581.         glMatrixMode(GL_PROJECTION);
  582.         glLoadIdentity();
  583. #if DXX_USE_OGLES
  584.         glOrthof(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
  585. #else
  586.         glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
  587. #endif
  588.         glMatrixMode(GL_MODELVIEW);
  589.         glLoadIdentity();//clear matrix
  590.         glEnable(GL_BLEND);
  591.         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  592.         gr_palette_step_up(0,0,0);//in case its left over from in game
  593.  
  594.         ogl_init_pixel_buffers(grd_curscreen->get_screen_width(), grd_curscreen->get_screen_height());
  595. }
  596.  
  597. }
  598.  
  599. namespace dsx {
  600.  
  601. static void ogl_tune_for_current(void)
  602. {
  603.         const auto gl_vendor = reinterpret_cast<const char *>(glGetString(GL_VENDOR));
  604.         const auto gl_renderer = reinterpret_cast<const char *>(glGetString(GL_RENDERER));
  605.         const auto gl_version = reinterpret_cast<const char *>(glGetString(GL_VERSION));
  606.  
  607.         con_printf(CON_VERBOSE, "DXX-Rebirth: OpenGL: vendor: %s", gl_vendor);
  608.         con_printf(CON_VERBOSE, "DXX-Rebirth: OpenGL: renderer: %s", gl_renderer);
  609.  
  610.         if (gl_renderer)
  611.         {
  612.         //add driver specific hacks here.  whee.
  613.         if ((d_stricmp(gl_renderer,"Mesa NVIDIA RIVA 1.0\n")==0 || d_stricmp(gl_renderer,"Mesa NVIDIA RIVA 1.2\n")==0) && d_stricmp(gl_version,"1.2 Mesa 3.0")==0)
  614.         {
  615.                 con_puts(CON_VERBOSE, "DXX-Rebirth: OpenGL renderer is blacklisted for GL intensity, GL read pixel, and GL GetTexLevel");
  616.                 CGameArg.DbgGlIntensity4Ok = false;     //ignores alpha, always black background instead of transparent.
  617.                 CGameArg.DbgGlReadPixelsOk = false;     //either just returns all black, or kills the X server entirely
  618.                 CGameArg.DbgGlGetTexLevelParamOk = false;       //returns random data..
  619.         }
  620.         if (d_stricmp(gl_vendor,"Matrox Graphics Inc.")==0)
  621.         {
  622.                 con_puts(CON_VERBOSE, "DXX-Rebirth: OpenGL renderer is blacklisted for GL intensity");
  623.                 //displays garbage. reported by
  624.                 //  redomen@crcwnet.com (render="Matrox G400" version="1.1.3 5.52.015")
  625.                 //  orulz (Matrox G200)
  626.                 CGameArg.DbgGlIntensity4Ok = 0;
  627.         }
  628. #ifdef macintosh
  629.         if (d_stricmp(gl_renderer,"3dfx Voodoo 3")==0) // strangely, includes Voodoo 2
  630.                 CGameArg.DbgGlGetTexLevelParamOk = false;       // Always returns 0
  631. #endif
  632.         }
  633.  
  634. #ifndef NDEBUG
  635.         con_printf(CON_VERBOSE, "DXX-Rebirth: OpenGL: gl_intensity4:%i gl_luminance4_alpha4:%i gl_rgba2:%i gl_readpixels:%i gl_gettexlevelparam:%i", CGameArg.DbgGlIntensity4Ok, CGameArg.DbgGlLuminance4Alpha4Ok, CGameArg.DbgGlRGBA2Ok, CGameArg.DbgGlReadPixelsOk, CGameArg.DbgGlGetTexLevelParamOk);
  636. #endif
  637.         if (ogl_maxanisotropy < 1.0f && CGameCfg.TexAnisotropy)
  638.         {
  639.                 con_puts(CON_VERBOSE, "DXX-Rebirth: OpenGL: anisotropic texture filter not supported");
  640.                 CGameCfg.TexAnisotropy = false;
  641.         }
  642. }
  643.  
  644. }
  645.  
  646. namespace dcx {
  647.  
  648. #if SDL_MAJOR_VERSION == 1
  649. // returns possible (fullscreen) resolutions if any.
  650. uint_fast32_t gr_list_modes(std::array<screen_mode, 50> &gsmodes)
  651. {
  652.         SDL_Rect** modes;
  653.         int modesnum = 0;
  654. #if DXX_USE_OGLES
  655.         int sdl_check_flags = SDL_FULLSCREEN; // always use Fullscreen as lead.
  656. #else
  657.         int sdl_check_flags = SDL_OPENGL | SDL_FULLSCREEN; // always use Fullscreen as lead.
  658. #endif
  659.  
  660.         if (sdl_no_modeswitch) {
  661.                 /* TODO: we could use the tvservice to list resolutions on the RPi */
  662.                 return 0;
  663.         }
  664.  
  665.         modes = SDL_ListModes(NULL, sdl_check_flags);
  666.  
  667.         if (modes == reinterpret_cast<SDL_Rect **>(0)) // check if we get any modes - if not, return 0
  668.                 return 0;
  669.  
  670.  
  671.         if (modes == reinterpret_cast<SDL_Rect**>(-1))
  672.         {
  673.                 return 0; // can obviously use any resolution... strange!
  674.         }
  675.         else
  676.         {
  677.                 for (int i = 0; modes[i]; ++i)
  678.                 {
  679.                         if (modes[i]->w > 0xFFF0 || modes[i]->h > 0xFFF0 // resolutions saved in 32bits. so skip bigger ones (unrealistic in 2010) (changed to 0xFFF0 to fix warning)
  680.                                 || modes[i]->w < 320 || modes[i]->h < 200) // also skip everything smaller than 320x200
  681.                                 continue;
  682.                         gsmodes[modesnum].width = modes[i]->w;
  683.                         gsmodes[modesnum].height = modes[i]->h;
  684.                         modesnum++;
  685.                         if (modesnum >= gsmodes.size()) // that really seems to be enough big boy.
  686.                                 break;
  687.                 }
  688.                 return modesnum;
  689.         }
  690. }
  691. #endif
  692.  
  693. }
  694.  
  695. namespace dsx {
  696.  
  697. #if SDL_MAJOR_VERSION == 1
  698. static int gr_check_mode(const screen_mode mode)
  699. {
  700.         if (sdl_no_modeswitch == 0) {
  701.                 return SDL_VideoModeOK(SM_W(mode), SM_H(mode), CGameArg.DbgBpp, sdl_video_flags);
  702.         } else {
  703.                 // just tell the caller that any mode is valid...
  704.                 return 32;
  705.         }
  706. }
  707. #endif
  708.  
  709. int gr_set_mode(screen_mode mode)
  710. {
  711.         unsigned char *gr_bm_data;
  712. #if SDL_MAJOR_VERSION == 1
  713.         if (!gr_check_mode(mode))
  714.         {
  715.                 con_printf(CON_URGENT, "Cannot set %ix%i. Fallback to 640x480", mode.width, mode.height);
  716.                 mode.width = 640;
  717.                 mode.height = 480;
  718.                 Game_screen_mode = mode;
  719.         }
  720. #endif
  721.         const uint_fast32_t w = SM_W(mode), h = SM_H(mode);
  722.  
  723.         gr_bm_data = grd_curscreen->sc_canvas.cv_bitmap.get_bitmap_data();//since we use realloc, we want to keep this pointer around.
  724.         auto gr_new_bm_data = reinterpret_cast<uint8_t *>(d_realloc(gr_bm_data, w * h));
  725.         if (!gr_new_bm_data)
  726.                 return 0;
  727.         *grd_curscreen = {};
  728.         grd_curscreen->set_screen_width_height(w, h);
  729.         grd_curscreen->sc_aspect = fixdiv(grd_curscreen->get_screen_width() * GameCfg.AspectX, grd_curscreen->get_screen_height() * GameCfg.AspectY);
  730.         gr_init_canvas(grd_curscreen->sc_canvas, gr_new_bm_data, bm_mode::ogl, w, h);
  731.         gr_set_default_canvas();
  732.  
  733.         ogl_init_window(w,h);//platform specific code
  734.         ogl_extensions_init();
  735.         ogl_tune_for_current();
  736.         sync_helper.init(CGameArg.OglSyncMethod, CGameArg.OglSyncWait);
  737.  
  738.         OGL_VIEWPORT(0,0,w,h);
  739.         ogl_init_state();
  740.         gamefont_choose_game_font(w,h);
  741.         gr_remap_color_fonts();
  742.  
  743.         return 0;
  744. }
  745.  
  746. #define GLstrcmptestr(a,b) if (d_stricmp(a,#b)==0 || d_stricmp(a,"GL_" #b)==0)return GL_ ## b;
  747.  
  748. #ifdef _WIN32
  749. constexpr char OglLibPath[]="opengl32.dll";
  750.  
  751. static int ogl_rt_loaded=0;
  752. static int ogl_init_load_library(void)
  753. {
  754.         int retcode=0;
  755.         if (!ogl_rt_loaded)
  756.         {
  757.                 retcode = OpenGL_LoadLibrary(true, OglLibPath);
  758.                 if(retcode)
  759.                 {
  760.                         if(!glEnd)
  761.                         {
  762.                                 Error("Opengl: Functions not imported\n");
  763.                         }
  764.                 }
  765.                 else
  766.                 {
  767.                         Error("Opengl: error loading %s\n", OglLibPath);
  768.                 }
  769.                 ogl_rt_loaded=1;
  770.         }
  771.         return retcode;
  772. }
  773. #endif
  774.  
  775. void gr_set_attributes(void)
  776. {
  777. #if !DXX_USE_OGLES
  778.         SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
  779.         SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE,0);
  780.         SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE,0);
  781.         SDL_GL_SetAttribute(SDL_GL_ACCUM_GREEN_SIZE,0);
  782.         SDL_GL_SetAttribute(SDL_GL_ACCUM_BLUE_SIZE,0);
  783.         SDL_GL_SetAttribute(SDL_GL_ACCUM_ALPHA_SIZE,0);
  784.         SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);
  785. #if SDL_MAJOR_VERSION == 1
  786.         SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, CGameCfg.VSync);
  787. #elif SDL_MAJOR_VERSION == 2
  788.         SDL_GL_SetSwapInterval(CGameCfg.VSync ? 1 : 0);
  789. #endif
  790.         int buffers, samples;
  791.         if (CGameCfg.Multisample)
  792.         {
  793.                 buffers = 1;
  794.                 samples = 4;
  795.         }
  796.         else
  797.         {
  798.                 buffers = samples = 0;
  799.         }
  800.         SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, buffers);
  801.         SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, samples);
  802. #endif
  803.         ogl_smash_texture_list_internal();
  804.         gr_remap_color_fonts();
  805. }
  806.  
  807. int gr_init()
  808. {
  809.         // Only do this function once!
  810.         if (gr_installed==1)
  811.                 return -1;
  812.  
  813. #ifdef RPI
  814.         // Initialize the broadcom host library
  815.         // we have to call this before we can create an OpenGL ES context
  816.         bcm_host_init();
  817.  
  818.         // Check if we are running with SDL directfb driver ...
  819.         char sdl_driver[32];
  820.         if (auto sdl_driver_ret = SDL_VideoDriverName(sdl_driver, sizeof(sdl_driver)))
  821.         {
  822.                 if (strcmp(sdl_driver_ret,"x11")) {
  823.                         con_printf(CON_URGENT,"RPi: activating hack for console driver");
  824.                         sdl_no_modeswitch=1;
  825.                 }
  826.         }
  827. #endif
  828.  
  829. #ifdef _WIN32
  830.         ogl_init_load_library();
  831. #endif
  832.  
  833. #if SDL_MAJOR_VERSION == 1
  834.         if (!CGameCfg.WindowMode && !CGameArg.SysWindow)
  835.                 sdl_video_flags|=SDL_FULLSCREEN;
  836.  
  837.         if (CGameArg.SysNoBorders)
  838.                 sdl_video_flags|=SDL_NOFRAME;
  839. #elif SDL_MAJOR_VERSION == 2
  840.         assert(!g_pRebirthSDLMainWindow);
  841.         unsigned sdl_window_flags = SDL_WINDOW_OPENGL;
  842.         if (CGameArg.SysNoBorders)
  843.                 sdl_window_flags |= SDL_WINDOW_BORDERLESS;
  844.         if (!CGameCfg.WindowMode && !CGameArg.SysWindow)
  845.                 sdl_window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
  846.         const auto mode = Game_screen_mode;
  847.         const auto SDLWindow = SDL_CreateWindow(DESCENT_VERSION, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SM_W(mode), SM_H(mode), sdl_window_flags);
  848.         if (!SDLWindow)
  849.                 return -1;
  850.         SDL_GetWindowPosition(SDLWindow, &g_iRebirthWindowX, &g_iRebirthWindowY);
  851.         g_pRebirthSDLMainWindow = SDLWindow;
  852.         SDL_GL_CreateContext(SDLWindow);
  853.         if (const auto window_icon = SDL_LoadBMP(DXX_SDL_WINDOW_ICON_BITMAP))
  854.                 SDL_SetWindowIcon(SDLWindow, window_icon);
  855. #endif
  856.  
  857.         gr_set_attributes();
  858.  
  859.         ogl_init_texture_list_internal();
  860.  
  861.         grd_curscreen = std::make_unique<grs_screen>();
  862.         *grd_curscreen = {};
  863.         grd_curscreen->sc_canvas.cv_bitmap.bm_data = NULL;
  864.  
  865.         // Set the mode.
  866.         grd_curscreen->sc_canvas.cv_fade_level = GR_FADE_OFF;
  867.         grd_curscreen->sc_canvas.cv_font = NULL;
  868.         grd_curscreen->sc_canvas.cv_font_fg_color = 0;
  869.         grd_curscreen->sc_canvas.cv_font_bg_color = 0;
  870.         gr_set_current_canvas(grd_curscreen->sc_canvas);
  871.  
  872.         ogl_init_pixel_buffers(256, 128);       // for gamefont_init
  873.  
  874.         gr_installed = 1;
  875.  
  876.         return 0;
  877. }
  878.  
  879. void gr_close()
  880. {
  881.         ogl_brightness_r = ogl_brightness_g = ogl_brightness_b = 0;
  882.  
  883.         if (gl_initialized)
  884.         {
  885.                 ogl_smash_texture_list_internal();
  886.                 sync_helper.deinit();
  887.         }
  888.  
  889.         if (grd_curscreen)
  890.         {
  891.                 if (grd_curscreen->sc_canvas.cv_bitmap.bm_mdata)
  892.                         d_free(grd_curscreen->sc_canvas.cv_bitmap.bm_mdata);
  893.                 /* Resetting grd_curscreen frees the default canvas, so set
  894.                  * grd_curcanv to nullptr since no canvas is available after
  895.                  * this block ends.
  896.                  */
  897.                 grd_curcanv = nullptr;
  898.                 grd_curscreen.reset();
  899.         }
  900.         ogl_close_pixel_buffers();
  901. #ifdef _WIN32
  902.         if (ogl_rt_loaded)
  903.                 OpenGL_LoadLibrary(false, OglLibPath);
  904. #endif
  905.  
  906. #if DXX_USE_OGLES
  907.         ogles_destroy();
  908. #ifdef RPI
  909.         con_printf(CON_DEBUG, "RPi: cleanuing up");
  910.         if (dispman_display != DISPMANX_NO_HANDLE) {
  911.                 rpi_destroy_element();
  912.                 con_printf(CON_DEBUG, "RPi: closing display");
  913.                 vc_dispmanx_display_close(dispman_display);
  914.                 dispman_display = DISPMANX_NO_HANDLE;
  915.         }
  916. #endif
  917. #endif
  918. }
  919.  
  920. }
  921.  
  922. namespace dcx {
  923.  
  924. void ogl_upixelc(const grs_bitmap &cv_bitmap, unsigned x, unsigned y, const color_palette_index c)
  925. {
  926.         std::array<GLfloat, 2> vertices = {{
  927.                 (x + cv_bitmap.bm_x) / static_cast<float>(last_width),
  928.                 static_cast<GLfloat>(1.0 - (y + cv_bitmap.bm_y) / static_cast<float>(last_height))
  929.         }};
  930.         const auto cr = static_cast<GLfloat>(CPAL2Tr(c));
  931.         const auto cg = static_cast<GLfloat>(CPAL2Tg(c));
  932.         const auto cb = static_cast<GLfloat>(CPAL2Tb(c));
  933.         GLfloat color_array[] = {
  934.                 cr, cg, cb, 1.0,
  935.                 cr, cg, cb, 1.0,
  936.                 cr, cg, cb, 1.0,
  937.                 cr, cg, cb, 1.0
  938.         };
  939.  
  940.         OGL_DISABLE(TEXTURE_2D);
  941.         glPointSize(linedotscale);
  942.         glEnableClientState(GL_VERTEX_ARRAY);
  943.         glEnableClientState(GL_COLOR_ARRAY);
  944.         glVertexPointer(2, GL_FLOAT, 0, vertices.data());
  945.         glColorPointer(4, GL_FLOAT, 0, color_array);
  946.         glDrawArrays(GL_POINTS, 0, 1);
  947.         glDisableClientState(GL_VERTEX_ARRAY);
  948.         glDisableClientState(GL_COLOR_ARRAY);
  949. }
  950.  
  951. color_palette_index ogl_ugpixel(const grs_bitmap &bitmap, unsigned x, unsigned y)
  952. {
  953.         ubyte buf[4];
  954.  
  955. #if !DXX_USE_OGLES
  956.         GLint gl_draw_buffer;
  957.         glGetIntegerv(GL_DRAW_BUFFER, &gl_draw_buffer);
  958.         glReadBuffer(gl_draw_buffer);
  959. #endif
  960.  
  961.         glReadPixels(bitmap.bm_x + x, SHEIGHT - bitmap.bm_y - y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buf);
  962.        
  963.         return gr_find_closest_color(buf[0]/4, buf[1]/4, buf[2]/4);
  964. }
  965.  
  966. void ogl_urect(grs_canvas &canvas, const int left, const int top, const int right, const int bot, const color_palette_index c)
  967. {
  968.         GLfloat xo, yo, xf, yf, color_r, color_g, color_b, color_a;
  969.  
  970.         glEnableClientState(GL_VERTEX_ARRAY);
  971.         glEnableClientState(GL_COLOR_ARRAY);
  972.  
  973.         xo = (left + canvas.cv_bitmap.bm_x) / static_cast<float>(last_width);
  974.         xf = (right + 1 + canvas.cv_bitmap.bm_x) / static_cast<float>(last_width);
  975.         yo = 1.0 - (top + canvas.cv_bitmap.bm_y) / static_cast<float>(last_height);
  976.         yf = 1.0 - (bot + 1 + canvas.cv_bitmap.bm_y) / static_cast<float>(last_height);
  977.  
  978.         OGL_DISABLE(TEXTURE_2D);
  979.  
  980.         color_r = CPAL2Tr(c);
  981.         color_g = CPAL2Tg(c);
  982.         color_b = CPAL2Tb(c);
  983.  
  984.         if (canvas.cv_fade_level >= GR_FADE_OFF)
  985.                 color_a = 1.0;
  986.         else
  987.                 color_a = 1.0 - static_cast<float>(canvas.cv_fade_level) / (static_cast<float>(GR_FADE_LEVELS) - 1.0);
  988.  
  989.         std::array<GLfloat, 16> color_array;
  990.         color_array[0] = color_array[4] = color_array[8] = color_array[12] = color_r;
  991.         color_array[1] = color_array[5] = color_array[9] = color_array[13] = color_g;
  992.         color_array[2] = color_array[6] = color_array[10] = color_array[14] = color_b;
  993.         color_array[3] = color_array[7] = color_array[11] = color_array[15] = color_a;
  994.  
  995.         std::array<GLfloat, 8> vertices;
  996.         vertices[0] = xo;
  997.         vertices[1] = yo;
  998.         vertices[2] = xo;
  999.         vertices[3] = yf;
  1000.         vertices[4] = xf;
  1001.         vertices[5] = yf;
  1002.         vertices[6] = xf;
  1003.         vertices[7] = yo;
  1004.         glVertexPointer(2, GL_FLOAT, 0, vertices.data());
  1005.         glColorPointer(4, GL_FLOAT, 0, color_array.data());
  1006.         glDrawArrays(GL_TRIANGLE_FAN, 0, 4);//replaced GL_QUADS
  1007.         glDisableClientState(GL_VERTEX_ARRAY);
  1008.         glDisableClientState(GL_COLOR_ARRAY);
  1009. }
  1010.  
  1011. void ogl_ulinec(grs_canvas &canvas, const int left, const int top, const int right, const int bot, const int c)
  1012. {
  1013.         GLfloat xo,yo,xf,yf;
  1014.         GLfloat fade_alpha = (canvas.cv_fade_level >= GR_FADE_OFF)
  1015.                 ? 1.0
  1016.                 : 1.0 - static_cast<float>(canvas.cv_fade_level) / (static_cast<float>(GR_FADE_LEVELS) - 1.0);
  1017.         GLfloat color_array[] = {
  1018.                 static_cast<GLfloat>(CPAL2Tr(c)), static_cast<GLfloat>(CPAL2Tg(c)), static_cast<GLfloat>(CPAL2Tb(c)), fade_alpha,
  1019.                 static_cast<GLfloat>(CPAL2Tr(c)), static_cast<GLfloat>(CPAL2Tg(c)), static_cast<GLfloat>(CPAL2Tb(c)), fade_alpha,
  1020.                 static_cast<GLfloat>(CPAL2Tr(c)), static_cast<GLfloat>(CPAL2Tg(c)), static_cast<GLfloat>(CPAL2Tb(c)), 1.0,
  1021.                 static_cast<GLfloat>(CPAL2Tr(c)), static_cast<GLfloat>(CPAL2Tg(c)), static_cast<GLfloat>(CPAL2Tb(c)), fade_alpha
  1022.         };
  1023.  
  1024.         glEnableClientState(GL_VERTEX_ARRAY);
  1025.         glEnableClientState(GL_COLOR_ARRAY);
  1026.        
  1027.         xo = (left + canvas.cv_bitmap.bm_x) / static_cast<float>(last_width);
  1028.         xf = (right + canvas.cv_bitmap.bm_x) / static_cast<float>(last_width);
  1029.         yo = 1.0 - (top + canvas.cv_bitmap.bm_y + 0.5) / static_cast<float>(last_height);
  1030.         yf = 1.0 - (bot + canvas.cv_bitmap.bm_y + 0.5) / static_cast<float>(last_height);
  1031.  
  1032.         OGL_DISABLE(TEXTURE_2D);
  1033.  
  1034.         std::array<GLfloat, 4> vertices = {{
  1035.                 xo,
  1036.                 yo,
  1037.                 xf,
  1038.                 yf,
  1039.         }};
  1040.  
  1041.         glVertexPointer(2, GL_FLOAT, 0, vertices.data());
  1042.         glColorPointer(4, GL_FLOAT, 0, color_array);
  1043.         glDrawArrays(GL_LINES, 0, 2);
  1044.         glDisableClientState(GL_VERTEX_ARRAY);
  1045.         glDisableClientState(GL_COLOR_ARRAY);
  1046. }
  1047.  
  1048. static GLfloat last_r, last_g, last_b;
  1049. static int do_pal_step;
  1050.  
  1051. void ogl_do_palfx(void)
  1052. {
  1053.         OGL_DISABLE(TEXTURE_2D);
  1054.  
  1055.         glEnableClientState(GL_VERTEX_ARRAY);
  1056.         glEnableClientState(GL_COLOR_ARRAY);
  1057.  
  1058.         GLfloat alast_r = last_r;
  1059.         GLfloat alast_g = last_g;
  1060.         GLfloat alast_b = last_b;
  1061.        
  1062.         if (!do_pal_step) {
  1063.                 return;
  1064.         }
  1065.         else if (last_r <= 0 && last_g <= 0 && last_b <= 0)
  1066.         {
  1067.                 // scale negative effect by 2.5 to match D1/D2 on GL
  1068.                 // also make values positive to actually have an effect
  1069.                 alast_r = last_r * -2.5;
  1070.                 alast_g = last_g * -2.5;
  1071.                 alast_b = last_b * -2.5;
  1072.                
  1073.                 glEnable(GL_BLEND);
  1074.                 glBlendFunc(GL_ZERO,GL_ONE_MINUS_SRC_COLOR);
  1075.         }
  1076.         else
  1077.         {
  1078.                 glEnable(GL_BLEND);
  1079.                 glBlendFunc(GL_ONE,GL_ONE);
  1080.         }
  1081.  
  1082.         GLfloat color_array[] = {
  1083.                 alast_r, alast_g, alast_b, 1.0,
  1084.                 alast_r, alast_g, alast_b, 1.0,
  1085.                 alast_r, alast_g, alast_b, 1.0,
  1086.                 alast_r, alast_g, alast_b, 1.0
  1087.         };
  1088.  
  1089.         std::array<GLfloat, 8> vertices = {{
  1090.                 0, 0, 0, 1, 1, 1, 1, 0
  1091.         }};
  1092.         glVertexPointer(2, GL_FLOAT, 0, vertices.data());
  1093.         glColorPointer(4, GL_FLOAT, 0, color_array);
  1094.         glDrawArrays(GL_TRIANGLE_FAN, 0, 4);//replaced GL_QUADS
  1095.         glDisableClientState(GL_VERTEX_ARRAY);
  1096.         glDisableClientState(GL_COLOR_ARRAY);
  1097.         glEnable(GL_BLEND);
  1098.         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  1099. }
  1100.  
  1101. static int ogl_brightness_ok;
  1102. static int old_b_r, old_b_g, old_b_b;
  1103.  
  1104. inline int gr_apply_gamma_clamp(int v)
  1105. {
  1106.         if (v >= 0)
  1107.                 return max(v + gr_palette_gamma, 0);
  1108.         else
  1109.                 return min(v + gr_palette_gamma, 0);
  1110. }
  1111.  
  1112. void gr_palette_step_up(int r, int g, int b)
  1113. {
  1114.         old_b_r = ogl_brightness_r;
  1115.         old_b_g = ogl_brightness_g;
  1116.         old_b_b = ogl_brightness_b;
  1117.  
  1118.         ogl_brightness_r = gr_apply_gamma_clamp(r);
  1119.         ogl_brightness_g = gr_apply_gamma_clamp(g);
  1120.         ogl_brightness_b = gr_apply_gamma_clamp(b);
  1121.  
  1122.         if (!ogl_brightness_ok)
  1123.         {
  1124.                 last_r = ogl_brightness_r / 63.0;
  1125.                 last_g = ogl_brightness_g / 63.0;
  1126.                 last_b = ogl_brightness_b / 63.0;
  1127.  
  1128.                 do_pal_step = (r || g || b || gr_palette_gamma);
  1129.         }
  1130.         else
  1131.         {
  1132.                 do_pal_step = 0;
  1133.         }
  1134. }
  1135.  
  1136. void gr_palette_load( palette_array_t &pal )
  1137. {
  1138.         copy_bound_palette(gr_current_pal, pal);
  1139.  
  1140.         gr_palette_step_up(0, 0, 0); // make ogl_setbrightness_internal get run so that menus get brightened too.
  1141.         init_computed_colors();
  1142. }
  1143.  
  1144. #define GL_BGR_EXT 0x80E0
  1145.  
  1146. struct TGA_header
  1147. {
  1148.       unsigned char TGAheader[12];
  1149.       unsigned char header[6];
  1150. };
  1151.  
  1152. //writes out an uncompressed RGB .tga file
  1153. //if we got really spiffy, we could optionally link in libpng or something, and use that.
  1154. #if DXX_USE_SCREENSHOT_FORMAT_LEGACY
  1155. void write_bmp(PHYSFS_File *const TGAFile, const unsigned w, const unsigned h)
  1156. {
  1157.         TGA_header TGA;
  1158.         GLbyte HeightH,HeightL,WidthH,WidthL;
  1159.         RAIIdmem<uint8_t[]> buf;
  1160.         const unsigned buffer_size_TGA = w * h * 3;
  1161.         CALLOC(buf, uint8_t[], buffer_size_TGA);
  1162.  
  1163.         RAIIdmem<uint8_t[]> rgbaBuf;
  1164.         CALLOC(rgbaBuf, uint8_t[], w * h * 4);
  1165.         glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, rgbaBuf.get());
  1166.         for(unsigned int pixel = 0; pixel < w * h; pixel++) {
  1167.                 buf[pixel * 3] = rgbaBuf[pixel * 4 + 2];
  1168.                 buf[pixel * 3 + 1] = rgbaBuf[pixel * 4 + 1];
  1169.                 buf[pixel * 3 + 2] = rgbaBuf[pixel * 4];
  1170.         }
  1171.  
  1172.         HeightH = static_cast<GLbyte>(h / 256);
  1173.         HeightL = static_cast<GLbyte>(h % 256);
  1174.         WidthH  = static_cast<GLbyte>(w / 256);
  1175.         WidthL  = static_cast<GLbyte>(w % 256);
  1176.         // Write TGA Header
  1177.         TGA.TGAheader[0] = 0;
  1178.         TGA.TGAheader[1] = 0;
  1179.         TGA.TGAheader[2] = 2;
  1180.         TGA.TGAheader[3] = 0;
  1181.         TGA.TGAheader[4] = 0;
  1182.         TGA.TGAheader[5] = 0;
  1183.         TGA.TGAheader[6] = 0;
  1184.         TGA.TGAheader[7] = 0;
  1185.         TGA.TGAheader[8] = 0;
  1186.         TGA.TGAheader[9] = 0;
  1187.         TGA.TGAheader[10] = 0;
  1188.         TGA.TGAheader[11] = 0;
  1189.         TGA.header[0] = WidthL;
  1190.         TGA.header[1] = WidthH;
  1191.         TGA.header[2] = HeightL;
  1192.         TGA.header[3] = HeightH;
  1193.         TGA.header[4] = static_cast<GLbyte>(24);
  1194.         TGA.header[5] = 0;
  1195.         PHYSFS_write(TGAFile,&TGA,sizeof(TGA_header),1);
  1196.         PHYSFS_write(TGAFile,buf, buffer_size_TGA * sizeof(unsigned char),1);
  1197. }
  1198. #endif
  1199.  
  1200. }
  1201.