Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 1 | pmbaty | 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 | } |