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.  * SDL video functions.
  10.  *
  11.  */
  12.  
  13. #include <algorithm>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <limits.h>
  17. #include <math.h>
  18. #include <SDL.h>
  19. #include "gr.h"
  20. #include "grdef.h"
  21. #include "palette.h"
  22. #include "game.h"
  23. #include "console.h"
  24. #include "u_mem.h"
  25. #include "dxxerror.h"
  26. #include "vers_id.h"
  27. #include "gamefont.h"
  28. #include "args.h"
  29. #include "config.h"
  30. #include "palette.h"
  31.  
  32. #include "compiler-range_for.h"
  33. #include "d_range.h"
  34. #include <memory>
  35.  
  36. using std::min;
  37.  
  38. namespace dcx {
  39.  
  40. static int sdl_video_flags = SDL_SWSURFACE | SDL_HWPALETTE | SDL_DOUBLEBUF;
  41. static SDL_Surface *screen, *canvas;
  42. static int gr_installed;
  43.  
  44. void gr_flip()
  45. {
  46.         SDL_Rect src, dest;
  47.  
  48.         dest.x = src.x = dest.y = src.y = 0;
  49.         dest.w = src.w = canvas->w;
  50.         dest.h = src.h = canvas->h;
  51.  
  52.         SDL_BlitSurface(canvas, &src, screen, &dest);
  53.         SDL_Flip(screen);
  54. }
  55.  
  56. // returns possible (fullscreen) resolutions if any.
  57. uint_fast32_t gr_list_modes(std::array<screen_mode, 50> &gsmodes)
  58. {
  59.         SDL_Rect** modes;
  60.         int modesnum = 0;
  61.         int sdl_check_flags = sdl_video_flags;
  62.  
  63.         sdl_check_flags |= SDL_FULLSCREEN; // always use Fullscreen as lead.
  64.  
  65.         modes = SDL_ListModes(NULL, sdl_check_flags);
  66.  
  67.         if (modes == reinterpret_cast<SDL_Rect **>(0)) // check if we get any modes - if not, return 0
  68.                 return 0;
  69.  
  70.  
  71.         if (modes == reinterpret_cast<SDL_Rect**>(-1))
  72.         {
  73.                 return 0; // can obviously use any resolution... strange!
  74.         }
  75.         else
  76.         {
  77.                 for (int i = 0; modes[i]; ++i)
  78.                 {
  79.                         if (modes[i]->w > 0xFFF0 || modes[i]->h > 0xFFF0 // resolutions saved in 32bits. so skip bigger ones (unrealistic in 2010) (kreatordxx - made 0xFFF0 to kill warning)
  80.                                 || modes[i]->w < 320 || modes[i]->h < 200) // also skip everything smaller than 320x200
  81.                                 continue;
  82.                         gsmodes[modesnum].width = modes[i]->w;
  83.                         gsmodes[modesnum].height = modes[i]->h;
  84.                         modesnum++;
  85.                         if (modesnum >= gsmodes.size()) // that really seems to be enough big boy.
  86.                                 break;
  87.                 }
  88.                 return modesnum;
  89.         }
  90. }
  91.  
  92. }
  93.  
  94. namespace dsx {
  95.  
  96. int gr_set_mode(screen_mode mode)
  97. {
  98.         screen=NULL;
  99.  
  100.         SDL_WM_SetCaption(DESCENT_VERSION, DXX_SDL_WINDOW_CAPTION);
  101.         SDL_WM_SetIcon( SDL_LoadBMP( DXX_SDL_WINDOW_ICON_BITMAP ), NULL );
  102.  
  103.         const auto sdl_video_flags = ::sdl_video_flags;
  104.         const auto DbgBpp = CGameArg.DbgBpp;
  105.         if(SDL_VideoModeOK(SM_W(mode), SM_H(mode), DbgBpp, sdl_video_flags))
  106.         {
  107.         }
  108.         else
  109.         {
  110.                 con_printf(CON_URGENT,"Cannot set %hux%hu. Fallback to 640x480", SM_W(mode), SM_H(mode));
  111.                 mode.width = 640;
  112.                 mode.height = 480;
  113.                 Game_screen_mode = mode;
  114.         }
  115.         const unsigned w = SM_W(mode), h = SM_H(mode);
  116.         screen = SDL_SetVideoMode(w, h, DbgBpp, sdl_video_flags);
  117.  
  118.         if (screen == NULL)
  119.         {
  120.                 Error("Could not set %dx%dx%d video mode\n", w, h, DbgBpp);
  121.                 exit(1);
  122.         }
  123.  
  124.         canvas = SDL_CreateRGBSurface(sdl_video_flags, w, h, 8, 0, 0, 0, 0);
  125.         if (canvas == NULL)
  126.         {
  127.                 Error("Could not create canvas surface\n");
  128.                 exit(1);
  129.         }
  130.  
  131.         *grd_curscreen = {};
  132.         grd_curscreen->set_screen_width_height(w, h);
  133.         grd_curscreen->sc_aspect = fixdiv(grd_curscreen->get_screen_width() * GameCfg.AspectX, grd_curscreen->get_screen_height() * GameCfg.AspectY);
  134.         gr_init_canvas(grd_curscreen->sc_canvas, reinterpret_cast<unsigned char *>(canvas->pixels), bm_mode::linear, w, h);
  135.         window_update_canvases();
  136.         gr_set_default_canvas();
  137.  
  138.         SDL_ShowCursor(0);
  139.         gamefont_choose_game_font(w,h);
  140.         gr_palette_load(gr_palette);
  141.         gr_remap_color_fonts();
  142.  
  143.         return 0;
  144. }
  145.  
  146. }
  147.  
  148. namespace dcx {
  149.  
  150. int gr_check_fullscreen(void)
  151. {
  152.         return !!(sdl_video_flags & SDL_FULLSCREEN);
  153. }
  154.  
  155. void gr_toggle_fullscreen()
  156. {
  157.         sdl_video_flags ^= SDL_FULLSCREEN;
  158.         const int WindowMode = !(sdl_video_flags & SDL_FULLSCREEN);
  159.         CGameCfg.WindowMode = WindowMode;
  160.         gr_remap_color_fonts();
  161.         SDL_WM_ToggleFullScreen(screen);
  162. }
  163.  
  164. }
  165.  
  166. namespace dsx {
  167.  
  168. int gr_init()
  169. {
  170.         // Only do this function once!
  171.         if (gr_installed==1)
  172.                 return -1;
  173.  
  174.         if (SDL_Init(SDL_INIT_VIDEO) < 0)
  175.         {
  176.                 Error("SDL library video initialisation failed: %s.",SDL_GetError());
  177.         }
  178.  
  179.         grd_curscreen = std::make_unique<grs_screen>();
  180.         *grd_curscreen = {};
  181.  
  182.         if (!CGameCfg.WindowMode && !CGameArg.SysWindow)
  183.                 sdl_video_flags|=SDL_FULLSCREEN;
  184.  
  185.         if (CGameArg.SysNoBorders)
  186.                 sdl_video_flags|=SDL_NOFRAME;
  187.  
  188.         if (CGameArg.DbgSdlHWSurface)
  189.                 sdl_video_flags|=SDL_HWSURFACE;
  190.  
  191.         if (CGameArg.DbgSdlASyncBlit)
  192.                 sdl_video_flags|=SDL_ASYNCBLIT;
  193.  
  194.         // Set the mode.
  195.         grd_curscreen->sc_canvas.cv_fade_level = GR_FADE_OFF;
  196.         grd_curscreen->sc_canvas.cv_font = NULL;
  197.         grd_curscreen->sc_canvas.cv_font_fg_color = 0;
  198.         grd_curscreen->sc_canvas.cv_font_bg_color = 0;
  199.         gr_set_current_canvas( &grd_curscreen->sc_canvas );
  200.  
  201.         gr_installed = 1;
  202.  
  203.         return 0;
  204. }
  205.  
  206. void gr_close()
  207. {
  208.         if (gr_installed==1)
  209.         {
  210.                 gr_installed = 0;
  211.                 grd_curscreen.reset();
  212.                 SDL_ShowCursor(1);
  213.                 SDL_FreeSurface(canvas);
  214.         }
  215. }
  216.  
  217. }
  218.  
  219. namespace dcx {
  220.  
  221. // Palette functions follow.
  222. static int last_r=0, last_g=0, last_b=0;
  223.  
  224. void gr_palette_step_up( int r, int g, int b )
  225. {
  226.         palette_array_t &p = gr_palette;
  227.         SDL_Palette *palette;
  228.  
  229.         if ( (r==last_r) && (g==last_g) && (b==last_b) )
  230.                 return;
  231.  
  232.         last_r = r;
  233.         last_g = g;
  234.         last_b = b;
  235.  
  236.         palette = canvas->format->palette;
  237.  
  238.         if (palette == NULL)
  239.                 return; // Display is not palettised
  240.  
  241.         std::array<SDL_Color, 256> colors{};
  242.         range_for (const int i, xrange(256u))
  243.         {
  244.                 const auto ir = static_cast<int>(p[i].r) + r + gr_palette_gamma;
  245.                 colors[i].r = std::min(std::max(ir, 0), 63) * 4;
  246.                 const auto ig = static_cast<int>(p[i].g) + g + gr_palette_gamma;
  247.                 colors[i].g = std::min(std::max(ig, 0), 63) * 4;
  248.                 const auto ib = static_cast<int>(p[i].b) + b + gr_palette_gamma;
  249.                 colors[i].b = std::min(std::max(ib, 0), 63) * 4;
  250.         }
  251.         SDL_SetColors(canvas, colors.data(), 0, colors.size());
  252. }
  253.  
  254. void gr_palette_load( palette_array_t &pal )
  255. {
  256.         SDL_Palette *palette;
  257.         std::array<uint8_t, 64> gamma;
  258.  
  259.         if (pal != gr_current_pal)
  260.                 SDL_FillRect(canvas, NULL, SDL_MapRGB(canvas->format, 0, 0, 0));
  261.  
  262.         copy_bound_palette(gr_current_pal, pal);
  263.  
  264.         if (canvas == NULL)
  265.                 return;
  266.  
  267.         palette = canvas->format->palette;
  268.  
  269.         if (palette == NULL)
  270.                 return; // Display is not palettised
  271.  
  272.         range_for (const int i, xrange(64u))
  273.                 gamma[i] = static_cast<int>((pow((static_cast<double>(14)/static_cast<double>(32)), 1.0)*i) + 0.5);
  274.  
  275.         std::array<SDL_Color, 256> colors{};
  276.         for (int i = 0, j = 0; j < 256; j++)
  277.         {
  278.                 const auto c = gr_find_closest_color(gamma[gr_palette[j].r], gamma[gr_palette[j].g], gamma[gr_palette[j].b]);
  279.                 gr_fade_table[14][j] = c;
  280.                 colors[j].r = (min(gr_current_pal[i].r + gr_palette_gamma, 63)) * 4;
  281.                 colors[j].g = (min(gr_current_pal[i].g + gr_palette_gamma, 63)) * 4;
  282.                 colors[j].b = (min(gr_current_pal[i].b + gr_palette_gamma, 63)) * 4;
  283.                 i++;
  284.         }
  285.  
  286.         SDL_SetColors(canvas, colors.data(), 0, colors.size());
  287.         init_computed_colors();
  288.         gr_remap_color_fonts();
  289. }
  290.  
  291. void gr_palette_read(palette_array_t &pal)
  292. {
  293.         SDL_Palette *palette;
  294.         unsigned i;
  295.  
  296.         palette = canvas->format->palette;
  297.  
  298.         if (palette == NULL)
  299.                 return; // Display is not palettised
  300.  
  301.         for (i = 0; i < 256; i++)
  302.         {
  303.                 pal[i].r = palette->colors[i].r / 4;
  304.                 pal[i].g = palette->colors[i].g / 4;
  305.                 pal[i].b = palette->colors[i].b / 4;
  306.         }
  307. }
  308.  
  309. }
  310.