Subversion Repositories Games.Descent

Rev

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
}