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 | } |