1 /*
2
3 Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4 and the "Aleph One" developers.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 This license is contained in the file "COPYING",
17 which is included with this source code; it is available online at
18 http://www.gnu.org/licenses/gpl.html
19
20 */
21
22 /*
23 * screen_sdl.cpp - Screen management, SDL implementation
24 *
25 * Written in 2000 by Christian Bauer
26 *
27 * Loren Petrich, Dec 23, 2000; moved shared content into screen_shared.cpp
28 */
29
30 #include "cseries.h"
31
32 #include <math.h>
33 #include <ctype.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #ifdef HAVE_OPENGL
38 #include "OGL_Headers.h"
39 #include "OGL_Blitter.h"
40 #include "OGL_Faders.h"
41 #endif
42
43 #include "world.h"
44 #include "map.h"
45 #include "render.h"
46 #include "shell.h"
47 #include "interface.h"
48 #include "player.h"
49 #include "overhead_map.h"
50 #include "fades.h"
51 #include "game_window.h"
52 #include "screen.h"
53 #include "preferences.h"
54 #include "computer_interface.h"
55 #include "Crosshairs.h"
56 #include "OGL_Render.h"
57 #include "ViewControl.h"
58 #include "screen_drawing.h"
59 #include "mouse.h"
60 #include "network.h"
61 #include "images.h"
62 #include "motion_sensor.h"
63 #include "Logging.h"
64
65 #include "sdl_fonts.h"
66
67 #include "lua_script.h"
68 #include "lua_hud_script.h"
69 #include "HUDRenderer_Lua.h"
70 #include "Movie.h"
71
72 #include <algorithm>
73
74 #if defined(__WIN32__) || (defined(__MACH__) && defined(__APPLE__))
75 #define MUST_RELOAD_VIEW_CONTEXT
76 #endif
77
78 // Global variables
79 static SDL_Surface *main_surface; // Main (display) surface
80 static SDL_Window *main_screen;
81 static SDL_Renderer *main_render;
82 static SDL_Texture *main_texture;
83
84 // Rendering buffer for the main view, the overhead map, and the terminals.
85 // The HUD has a separate buffer.
86 // It is initialized to NULL so as to allow its initing to be lazy.
87 SDL_Surface *world_pixels = NULL;
88 SDL_Surface *world_pixels_corrected = NULL;
89 SDL_Surface *HUD_Buffer = NULL;
90 SDL_Surface *Term_Buffer = NULL;
91 SDL_Surface *Intro_Buffer = NULL; // intro screens, main menu, chapters, credits, etc.
92 SDL_Surface *Intro_Buffer_corrected = NULL;
93 bool intro_buffer_changed = false;
94 SDL_Surface *Map_Buffer = NULL;
95
96 #ifdef HAVE_OPENGL
97 static OGL_Blitter Term_Blitter;
98 static OGL_Blitter Intro_Blitter;
99 #endif
100
101 // Initial gamma table
102 bool default_gamma_inited = false;
103 uint16 default_gamma_r[256];
104 uint16 default_gamma_g[256];
105 uint16 default_gamma_b[256];
106 uint16 current_gamma_r[256];
107 uint16 current_gamma_g[256];
108 uint16 current_gamma_b[256];
109 bool using_default_gamma = true;
110
111 static bool PrevFullscreen = false;
112 static bool in_game = false; // Flag: menu (fixed 640x480) or in-game (variable size) display
113
114 static int desktop_width;
115 static int desktop_height;
116
117 static int failed_multisamples = 0; // remember when GL multisample setting didn't succeed
118 static bool passed_shader = false; // remember when we passed Shader tests
119
120 // From shell_sdl.cpp
121 extern bool option_nogamma;
122
123 #include "screen_shared.h"
124
125 using namespace alephone;
126
127 Screen Screen::m_instance;
128
129
130 // Prototypes
131 static bool need_mode_change(int window_width, int window_height, int log_width, int log_height, int depth, bool nogl);
132 static void change_screen_mode(int width, int height, int depth, bool nogl, bool force_menu);
133 static bool get_auto_resolution_size(short *w, short *h, struct screen_mode_data *mode);
134 static void build_sdl_color_table(const color_table *color_table, SDL_Color *colors);
135 static void reallocate_world_pixels(int width, int height);
136 static void reallocate_map_pixels(int width, int height);
137 static void apply_gamma(SDL_Surface *src, SDL_Surface *dst);
138 static void update_screen(SDL_Rect &source, SDL_Rect &destination, bool hi_rez);
139 static void update_fps_display(SDL_Surface *s);
140 static void DisplayPosition(SDL_Surface *s);
141 static void DisplayMessages(SDL_Surface *s);
142 static void DisplayNetMicStatus(SDL_Surface *s);
143 static void DrawSurface(SDL_Surface *s, SDL_Rect &dest_rect, SDL_Rect &src_rect);
144 static void clear_screen_margin();
145
146 SDL_PixelFormat pixel_format_16, pixel_format_32;
147
148 // LP addition:
start_tunnel_vision_effect(bool out)149 void start_tunnel_vision_effect(
150 bool out)
151 {
152 // LP change: doing this by setting targets
153 world_view->target_field_of_view = (out && NetAllowTunnelVision()) ? TUNNEL_VISION_FIELD_OF_VIEW :
154 ((current_player->extravision_duration) ? EXTRAVISION_FIELD_OF_VIEW : NORMAL_FIELD_OF_VIEW);
155 }
156
157 /*
158 * Initialize screen management
159 */
160
Initialize(screen_mode_data * mode)161 void Screen::Initialize(screen_mode_data* mode)
162 //void initialize_screen(struct screen_mode_data *mode, bool ShowFreqDialog)
163 {
164 interface_bit_depth = bit_depth = mode->bit_depth;
165
166 if (!screen_initialized) {
167
168 SDL_PixelFormat *pf = SDL_AllocFormat(SDL_PIXELFORMAT_RGB565);
169 pixel_format_16 = *pf;
170 SDL_FreeFormat(pf);
171 pf = SDL_AllocFormat(SDL_PIXELFORMAT_ARGB8888);
172 pixel_format_32 = *pf;
173 SDL_FreeFormat(pf);
174
175 uncorrected_color_table = (struct color_table *)malloc(sizeof(struct color_table));
176 world_color_table = (struct color_table *)malloc(sizeof(struct color_table));
177 visible_color_table = (struct color_table *)malloc(sizeof(struct color_table));
178 interface_color_table = (struct color_table *)malloc(sizeof(struct color_table));
179 assert(uncorrected_color_table && world_color_table && visible_color_table && interface_color_table);
180 memset(uncorrected_color_table, 0, sizeof(struct color_table));
181 memset(world_color_table, 0, sizeof(struct color_table));
182 memset(visible_color_table, 0, sizeof(struct color_table));
183 memset(interface_color_table, 0, sizeof(struct color_table));
184
185 // Allocate the bitmap_definition structure for our GWorld (it is reinitialized every frame)
186 world_pixels_structure = (struct bitmap_definition *)malloc(sizeof(struct bitmap_definition) + sizeof(pixel8 *) * MAXIMUM_WORLD_HEIGHT);
187 assert(world_pixels_structure);
188
189 // Allocate and initialize our view_data structure
190 world_view = (struct view_data *)malloc(sizeof(struct view_data));
191 assert(world_view);
192 world_view->field_of_view = NORMAL_FIELD_OF_VIEW; // degrees (was 74 for a long, long time)
193 world_view->target_field_of_view = NORMAL_FIELD_OF_VIEW; // for no change in FOV
194 world_view->overhead_map_scale = DEFAULT_OVERHEAD_MAP_SCALE;
195 world_view->overhead_map_active = false;
196 world_view->terminal_mode_active = false;
197 world_view->horizontal_scale = 1;
198 world_view->vertical_scale = 1;
199 world_view->tunnel_vision_active = false;
200
201 m_modes.clear();
202 SDL_DisplayMode desktop;
203 if (SDL_GetDesktopDisplayMode(0, &desktop) == 0)
204 {
205 if (desktop.w >= 640 && desktop.h >= 480)
206 {
207 m_modes.push_back(std::pair<int, int>(desktop.w, desktop.h));
208 }
209 }
210 if (m_modes.empty())
211 {
212 // assume a decent screen size
213 m_modes.push_back(std::pair<int, int>(1600, 900));
214 }
215
216 if (1)
217 {
218 // insert some choices for windowed mode
219 std::vector<std::pair<int, int> > common_modes;
220 common_modes.push_back(std::pair<int, int>(1920, 1080));
221 common_modes.push_back(std::pair<int, int>(1600, 900));
222 common_modes.push_back(std::pair<int, int>(1200, 900));
223 common_modes.push_back(std::pair<int, int>(1366, 768));
224 common_modes.push_back(std::pair<int, int>(1280, 720));
225 common_modes.push_back(std::pair<int, int>(960, 720));
226 common_modes.push_back(std::pair<int, int>(800, 600));
227 common_modes.push_back(std::pair<int, int>(640, 480));
228 common_modes.push_back(std::pair<int, int>(480, 240));
229 common_modes.push_back(std::pair<int, int>(320, 160));
230
231 for (std::vector<std::pair<int, int> >::const_iterator it = common_modes.begin(); it != common_modes.end(); ++it)
232 {
233 if (it->first <= m_modes[0].first && it->second <= m_modes[0].second && !(it->first == m_modes[0].first && it->second == m_modes[0].second))
234 {
235 m_modes.push_back(*it);
236 }
237 }
238 }
239
240 // insert custom mode if it's in the prefs
241 if (graphics_preferences->screen_mode.width <= m_modes[0].first && graphics_preferences->screen_mode.height <= m_modes[0].second)
242 {
243 // sort it into the list
244 for (std::vector<std::pair<int, int> >::iterator it = m_modes.begin(); it != m_modes.end(); ++it)
245 {
246 if (graphics_preferences->screen_mode.width >= it->first && graphics_preferences->screen_mode.height >= it->second)
247 {
248 if (graphics_preferences->screen_mode.width != it->first || graphics_preferences->screen_mode.height != it->second)
249 {
250 m_modes.insert(it, std::pair<int, int>(graphics_preferences->screen_mode.width, graphics_preferences->screen_mode.height));
251 }
252 break;
253 }
254 }
255 }
256
257 // these are not validated in graphics prefs because
258 // SDL is not initialized yet when prefs load, so
259 // validate them here
260 if (Screen::instance()->FindMode(graphics_preferences->screen_mode.width, graphics_preferences->screen_mode.height) < 0)
261 {
262 graphics_preferences->screen_mode.width = 640;
263 graphics_preferences->screen_mode.height = 480;
264 write_preferences();
265 }
266 } else {
267
268 unload_all_collections();
269 if (world_pixels)
270 SDL_FreeSurface(world_pixels);
271 if (world_pixels_corrected)
272 SDL_FreeSurface(world_pixels_corrected);
273 }
274 world_pixels = NULL;
275 world_pixels_corrected = NULL;
276
277 screen_mode = *mode;
278 change_screen_mode(&screen_mode, true);
279 screen_initialized = true;
280
281 }
282
height()283 int Screen::height()
284 {
285 return MainScreenLogicalHeight();
286 }
287
width()288 int Screen::width()
289 {
290 return MainScreenLogicalWidth();
291 }
292
pixel_scale()293 float Screen::pixel_scale()
294 {
295 return MainScreenPixelScale();
296 }
297
window_height()298 int Screen::window_height()
299 {
300 return std::max(static_cast<short>(480), screen_mode.height);
301 }
302
window_width()303 int Screen::window_width()
304 {
305 return std::max(static_cast<short>(640), screen_mode.width);
306 }
307
hud()308 bool Screen::hud()
309 {
310 return screen_mode.hud;
311 }
312
lua_hud()313 bool Screen::lua_hud()
314 {
315 return screen_mode.hud && LuaHUDRunning();
316 }
317
openGL()318 bool Screen::openGL()
319 {
320 return screen_mode.acceleration != _no_acceleration;
321 }
322
fifty_percent()323 bool Screen::fifty_percent()
324 {
325 return screen_mode.height == 160;
326 }
327
seventyfive_percent()328 bool Screen::seventyfive_percent()
329 {
330 return screen_mode.height == 240;;
331 }
332
window_rect()333 SDL_Rect Screen::window_rect()
334 {
335 SDL_Rect r;
336 r.w = window_width();
337 r.h = window_height();
338 r.x = (width() - r.w) / 2;
339 r.y = (height() - r.h) / 2;
340 return r;
341 }
342
view_rect()343 SDL_Rect Screen::view_rect()
344 {
345 SDL_Rect r;
346 if (lua_hud())
347 {
348 r.x = lua_view_rect.x + (width() - window_width()) / 2;
349 r.y = lua_view_rect.y + (height() - window_height()) / 2;
350 r.w = MIN(lua_view_rect.w, window_width() - lua_view_rect.x);
351 r.h = MIN(lua_view_rect.h, window_height() - lua_view_rect.y);
352 }
353 else if (!hud())
354 {
355 r.x = (width() - window_width()) / 2;
356 r.y = (height() - window_height()) / 2;
357 r.w = window_width();
358 r.h = window_height();
359 }
360 else
361 {
362 int available_height = window_height() - hud_rect().h;
363 if (window_width() > available_height * 2)
364 {
365 r.w = available_height * 2;
366 r.h = available_height;
367 }
368 else
369 {
370 r.w = window_width();
371 r.h = window_width() / 2;
372 }
373 r.x = (width() - r.w) / 2;
374 r.y = (height() - window_height()) / 2 + (available_height - r.h) / 2;
375 }
376
377 if (fifty_percent())
378 {
379 r.y += r.h / 4;
380 r.x += r.w / 4;
381 r.w /= 2;
382 r.h /= 2;
383 }
384 else if (seventyfive_percent())
385 {
386 r.y += r.h / 8;
387 r.x += r.w / 8;
388 r.w = r.w * 3 / 4;
389 r.h = r.h * 3 / 4;
390 }
391
392 return r;
393 }
394
map_rect()395 SDL_Rect Screen::map_rect()
396 {
397 SDL_Rect r;
398 if (lua_hud())
399 {
400 r.x = lua_map_rect.x + (width() - window_width()) / 2;
401 r.y = lua_map_rect.y + (height() - window_height()) / 2;
402 r.w = MIN(lua_map_rect.w, window_width() - lua_map_rect.x);
403 r.h = MIN(lua_map_rect.h, window_height() - lua_map_rect.y);
404 return r;
405 }
406 if (map_is_translucent())
407 return view_rect();
408
409 r.w = window_width();
410 r.h = window_height();
411 if (hud())
412 r.h -= hud_rect().h;
413
414 r.x = (width() - window_width()) / 2;
415 r.y = (height() - window_height()) / 2;
416
417 return r;
418 }
419
term_rect()420 SDL_Rect Screen::term_rect()
421 {
422 int wh = window_height();
423 int ww = window_width();
424 int wx = (width() - ww)/2;
425 int wy = (height() - wh)/2;
426
427 if (lua_hud())
428 {
429 wx += lua_term_rect.x;
430 wy += lua_term_rect.y;
431 ww = MIN(lua_term_rect.w, ww - lua_term_rect.x);
432 wh = MIN(lua_term_rect.h, wh - lua_term_rect.y);
433 }
434
435 SDL_Rect r;
436
437 int available_height = wh;
438 if (hud() && !lua_hud())
439 available_height -= hud_rect().h;
440
441 screen_rectangle *term_rect = get_interface_rectangle(_terminal_screen_rect);
442 r.w = RECTANGLE_WIDTH(term_rect);
443 r.h = RECTANGLE_HEIGHT(term_rect);
444 float aspect = r.w / static_cast<float>(r.h);
445 switch (screen_mode.term_scale_level)
446 {
447 case 1:
448 if (available_height >= (r.h * 2) && ww >= (r.w * 2))
449 r.w *= 2;
450 break;
451 case 2:
452 r.w = std::min(ww, std::max(static_cast<int>(r.w), static_cast<int>(aspect * available_height)));
453 break;
454 }
455 r.h = r.w / aspect;
456 r.x = wx + (ww - r.w) / 2;
457 r.y = wy + (available_height - r.h) / 2;
458
459 return r;
460 }
461
hud_rect()462 SDL_Rect Screen::hud_rect()
463 {
464 SDL_Rect r;
465 r.w = 640;
466 switch (screen_mode.hud_scale_level)
467 {
468 case 1:
469 if (window_height() >= 960 && window_width() >= 1280)
470 r.w *= 2;
471 break;
472 case 2:
473 r.w = std::min(window_width(), std::max(640, 4 * window_height() / 3));
474 break;
475 }
476 r.h = r.w / 4;
477 r.x = (width() - r.w) / 2;
478 r.y = window_height() - r.h + (height() - window_height()) / 2;
479
480 return r;
481 }
482
bound_screen(bool in_game)483 void Screen::bound_screen(bool in_game)
484 {
485 SDL_Rect r = { 0, 0, in_game ? window_width() : 640, in_game ? window_height() : 480 };
486 bound_screen_to_rect(r, in_game);
487 }
488
bound_screen_to_rect(SDL_Rect & r,bool in_game)489 void Screen::bound_screen_to_rect(SDL_Rect &r, bool in_game)
490 {
491 #ifdef HAVE_OPENGL
492 if (MainScreenIsOpenGL())
493 {
494 int pixw = MainScreenPixelWidth();
495 int pixh = MainScreenPixelHeight();
496 int virw = in_game ? window_width() : 640;
497 int virh = in_game ? window_height() : 480;
498
499 float vscale = MIN(pixw / static_cast<float>(virw), pixh / static_cast<float>(virh));
500 int vpw = static_cast<int>(r.w * vscale + 0.5f);
501 int vph = static_cast<int>(r.h * vscale + 0.5f);
502 int vpx = static_cast<int>(pixw/2.0f - (virw * vscale)/2.0f + (r.x * vscale) + 0.5f);
503 int vpy = static_cast<int>(pixh/2.0f - (virh * vscale)/2.0f + (r.y * vscale) + 0.5f);
504
505 glMatrixMode(GL_PROJECTION);
506 glLoadIdentity();
507 glViewport(vpx, pixh - vph - vpy, vpw, vph);
508 m_viewport_rect.x = vpx;
509 m_viewport_rect.y = pixh - vph - vpy;
510 m_viewport_rect.w = vpw;
511 m_viewport_rect.h = vph;
512 glOrtho(0, r.w, r.h, 0, -1.0, 1.0);
513 m_ortho_rect.x = m_ortho_rect.y = 0;
514 m_ortho_rect.w = r.w;
515 m_ortho_rect.h = r.h;
516 }
517 #endif
518 }
519
scissor_screen_to_rect(SDL_Rect & r)520 void Screen::scissor_screen_to_rect(SDL_Rect &r)
521 {
522 #ifdef HAVE_OPENGL
523 if (MainScreenIsOpenGL())
524 {
525 glEnable(GL_SCISSOR_TEST);
526 glScissor(m_viewport_rect.x + (r.x * m_viewport_rect.w/m_ortho_rect.w),
527 m_viewport_rect.y + ((m_ortho_rect.h - r.y - r.h) * m_viewport_rect.h/m_ortho_rect.h),
528 r.w * m_viewport_rect.w/m_ortho_rect.w,
529 r.h * m_viewport_rect.h/m_ortho_rect.h);
530 }
531 #endif
532 }
533
534
window_to_screen(int & x,int & y)535 void Screen::window_to_screen(int &x, int &y)
536 {
537 #ifdef HAVE_OPENGL
538 if (MainScreenIsOpenGL())
539 {
540 int winw = MainScreenWindowWidth();
541 int winh = MainScreenWindowHeight();
542 int virw = 640;
543 int virh = 480;
544
545 float wina = winw / static_cast<float>(winh);
546 float vira = virw / static_cast<float>(virh);
547
548 if (wina >= vira)
549 {
550 float scale = winh / static_cast<float>(virh);
551 x -= (winw - (virw * scale))/2;
552 x /= scale;
553 y /= scale;
554 }
555 else
556 {
557 float scale = winw / static_cast<float>(virw);
558 y -= (winh - (virh * scale))/2;
559 x /= scale;
560 y /= scale;
561 }
562 }
563 #endif
564 }
565
566 /*
567 * (Re)allocate off-screen buffer
568 */
569
reallocate_world_pixels(int width,int height)570 static void reallocate_world_pixels(int width, int height)
571 {
572 if (world_pixels) {
573 SDL_FreeSurface(world_pixels);
574 world_pixels = NULL;
575 }
576 if (world_pixels_corrected) {
577 SDL_FreeSurface(world_pixels_corrected);
578 world_pixels_corrected = NULL;
579 }
580 SDL_PixelFormat *f = main_surface->format;
581 // world_pixels = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, f->BitsPerPixel, f->Rmask, f->Gmask, f->Bmask, f->Amask);
582 switch (bit_depth)
583 {
584 case 8:
585 world_pixels = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, f->BitsPerPixel, 0, 0, 0, 0);
586 break;
587 case 16:
588 world_pixels = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 16, pixel_format_16.Rmask, pixel_format_16.Gmask, pixel_format_16.Bmask, 0);
589 break;
590 default:
591 world_pixels = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, pixel_format_32.Rmask, pixel_format_32.Gmask, pixel_format_32.Bmask, 0);
592 break;
593
594 }
595
596 if (world_pixels == NULL)
597 alert_out_of_memory();
598 else if (bit_depth == 8) {
599 SDL_Color colors[256];
600 build_sdl_color_table(world_color_table, colors);
601 SDL_SetPaletteColors(world_pixels->format->palette, colors, 0, 256);
602 } else
603 world_pixels_corrected = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, world_pixels->format->BitsPerPixel, world_pixels->format->Rmask, world_pixels->format->Gmask, world_pixels->format->Bmask, 0);
604 }
605
reallocate_map_pixels(int width,int height)606 static void reallocate_map_pixels(int width, int height)
607 {
608 if (Map_Buffer) {
609 SDL_FreeSurface(Map_Buffer);
610 Map_Buffer = NULL;
611 }
612 Map_Buffer = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, world_pixels->format->BitsPerPixel, world_pixels->format->Rmask, world_pixels->format->Gmask, world_pixels->format->Bmask, 0);
613 if (Map_Buffer == NULL)
614 alert_out_of_memory();
615 if (map_is_translucent()) {
616 SDL_SetSurfaceAlphaMod(Map_Buffer, 128);
617 SDL_SetColorKey(Map_Buffer, SDL_TRUE, SDL_MapRGB(Map_Buffer->format, 0, 0, 0));
618 }
619 }
620
621
622 /*
623 * Force reload of view context
624 */
625
ReloadViewContext(void)626 void ReloadViewContext(void)
627 {
628 #ifdef HAVE_OPENGL
629 if (in_game && screen_mode.acceleration != _no_acceleration)
630 OGL_StartRun();
631 #endif
632 }
633
634 /*
635 * Determine if the transparent map is in use
636 * (may be disallowed for network games)
637 */
638
map_is_translucent(void)639 bool map_is_translucent(void)
640 {
641 return (screen_mode.translucent_map && NetAllowOverlayMap());
642 }
643
644 /*
645 * Enter game screen
646 */
647
enter_screen(void)648 void enter_screen(void)
649 {
650 if (world_view->overhead_map_active)
651 set_overhead_map_status(false);
652 if (world_view->terminal_mode_active)
653 set_terminal_status(false);
654
655 // Adding this view-effect resetting here since initialize_world_view() no longer resets it
656 world_view->effect = NONE;
657
658 // Set screen to selected size
659 in_game = true;
660 change_screen_mode(_screentype_level);
661 PrevFullscreen = screen_mode.fullscreen;
662
663 #if defined(HAVE_OPENGL) && !defined(MUST_RELOAD_VIEW_CONTEXT)
664 // if MUST_RELOAD_VIEW_CONTEXT, we know this just happened in
665 // change_screen_mode
666 if (screen_mode.acceleration != _no_acceleration)
667 OGL_StartRun();
668 #endif
669
670 // Reset modifier key status
671 SDL_SetModState(KMOD_NONE);
672
673 Screen *scr = Screen::instance();
674 int w = scr->width();
675 int h = scr->height();
676 int ww = scr->window_width();
677 int wh = scr->window_height();
678
679 scr->lua_clip_rect.x = 0;
680 scr->lua_clip_rect.y = 0;
681 scr->lua_clip_rect.w = w;
682 scr->lua_clip_rect.h = h;
683
684 scr->lua_view_rect.x = scr->lua_map_rect.x = (w - ww) / 2;
685 scr->lua_view_rect.y = scr->lua_map_rect.y = (h - wh) / 2;
686 scr->lua_view_rect.w = scr->lua_map_rect.w = ww;
687 scr->lua_view_rect.h = scr->lua_map_rect.h = wh;
688
689 screen_rectangle *term_rect = get_interface_rectangle(_terminal_screen_rect);
690 scr->lua_term_rect.x = (w - RECTANGLE_WIDTH(term_rect)) / 2;
691 scr->lua_term_rect.y = (h - RECTANGLE_HEIGHT(term_rect)) / 2;
692 scr->lua_term_rect.w = RECTANGLE_WIDTH(term_rect);
693 scr->lua_term_rect.h = RECTANGLE_HEIGHT(term_rect);
694
695 L_Call_HUDResize();
696 }
697
698
699 /*
700 * Exit game screen
701 */
702
exit_screen(void)703 void exit_screen(void)
704 {
705 in_game = false;
706 #ifdef HAVE_OPENGL
707 OGL_StopRun();
708 #endif
709 }
710
711
712 /*
713 * Change screen mode
714 */
715
need_mode_change(int window_width,int window_height,int log_width,int log_height,int depth,bool nogl)716 static bool need_mode_change(int window_width, int window_height,
717 int log_width, int log_height,
718 int depth, bool nogl)
719 {
720 // have we set up any window at all yet?
721 if (main_screen == NULL)
722 return true;
723
724 // are we switching to/from high-dpi?
725 bool current_high_dpi = (SDL_GetWindowFlags(main_screen) & SDL_WINDOW_ALLOW_HIGHDPI);
726 if (screen_mode.high_dpi != current_high_dpi) {
727 return true;
728 }
729
730 // are we switching to/from OpenGL?
731 bool wantgl = false;
732 bool hasgl = MainScreenIsOpenGL();
733 #ifdef HAVE_OPENGL
734 wantgl = !nogl && (screen_mode.acceleration != _no_acceleration);
735 if (wantgl != hasgl)
736 return true;
737 if (wantgl) {
738 // check GL-specific attributes
739 int atval = 0;
740
741 int want_samples = Get_OGL_ConfigureData().Multisamples;
742 if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &atval) == 0) {
743 if (atval != want_samples && !(want_samples == failed_multisamples && atval == 0))
744 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, want_samples);
745 }
746
747 int want_vsync = Get_OGL_ConfigureData().WaitForVSync ? 1 : 0;
748 int has_vsync = SDL_GL_GetSwapInterval();
749 if ((has_vsync == 0) != (want_vsync == 0))
750 SDL_GL_SetSwapInterval(want_vsync);
751 }
752 #endif
753
754 // are we switching to/from fullscreen?
755 bool current_fullscreen = (SDL_GetWindowFlags(main_screen) & SDL_WINDOW_FULLSCREEN_DESKTOP);
756 if (screen_mode.fullscreen != current_fullscreen) {
757 SDL_SetWindowFullscreen(main_screen, screen_mode.fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
758 }
759
760 // are we switching resolution?
761 if (!screen_mode.fullscreen) {
762 int w, h;
763 SDL_GetWindowSize(main_screen, &w, &h);
764 if (w != window_width || h != window_height) {
765 SDL_SetWindowSize(main_screen, window_width, window_height);
766 SDL_SetWindowPosition(main_screen, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
767 }
768 }
769 if (!hasgl) {
770 int w, h;
771 SDL_RenderGetLogicalSize(main_render, &w, &h);
772 if (w != log_width || h != log_height) {
773 SDL_RenderSetLogicalSize(main_render, log_width, log_height);
774 }
775 }
776
777 // force rebuild of main_surface and/or main_texture, if necessary
778 if (main_surface != NULL && (main_surface->w != log_width || main_surface->h != log_height)) {
779 SDL_FreeSurface(main_surface);
780 main_surface = NULL;
781 }
782 if (main_texture != NULL) {
783 int w, h;
784 SDL_QueryTexture(main_texture, NULL, NULL, &w, &h);
785 if (w != log_width || h != log_height) {
786 SDL_DestroyTexture(main_texture);
787 main_texture = NULL;
788 }
789 }
790
791 // reset title, since SDL forgets sometimes
792 SDL_SetWindowTitle(main_screen, get_application_name().c_str());
793
794 return false;
795 }
796
change_window_filter(void * ctx,SDL_Event * event)797 static int change_window_filter(void *ctx, SDL_Event *event)
798 {
799 Uint32 *window_id = static_cast<Uint32 *>(ctx);
800
801 if (event->type == SDL_WINDOWEVENT &&
802 event->window.event == SDL_WINDOWEVENT_FOCUS_LOST &&
803 event->window.windowID == *window_id)
804 return 0;
805 return 1;
806 }
807
change_screen_mode(int width,int height,int depth,bool nogl,bool force_menu)808 static void change_screen_mode(int width, int height, int depth, bool nogl, bool force_menu)
809 {
810 int prev_width = 0;
811 int prev_height = 0;
812 if (main_surface)
813 {
814 prev_width = main_surface->w;
815 prev_width = main_surface->h;
816 }
817
818 int vmode_height = height;
819 int vmode_width = width;
820 uint32 flags = (screen_mode.fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
821 if (screen_mode.high_dpi)
822 flags |= SDL_WINDOW_ALLOW_HIGHDPI;
823
824 int sdl_width = (flags & SDL_WINDOW_FULLSCREEN_DESKTOP) ? 0 : vmode_width;
825 int sdl_height = (flags & SDL_WINDOW_FULLSCREEN_DESKTOP) ? 0 : vmode_height;
826 if (force_menu)
827 {
828 vmode_width = 640;
829 vmode_height = 480;
830 }
831
832 //#ifdef HAVE_OPENGL
833 // if (!context_created && !nogl && screen_mode.acceleration != _no_acceleration) {
834 // SDL_GL_CreateContext(main_screen);
835 // context_created = true;
836 // }
837 //#endif
838 // if (nogl || screen_mode.acceleration == _no_acceleration) {
839 // main_render = SDL_CreateRenderer(main_screen, -1, 0);
840 // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
841 // SDL_RenderSetLogicalSize(main_render, vmode_width, vmode_height);
842 // main_texture = SDL_CreateTexture(main_render, pixel_format_32.format, SDL_TEXTUREACCESS_STREAMING, vmode_width, vmode_height);
843 // }
844 // main_surface = SDL_CreateRGBSurface(SDL_SWSURFACE, vmode_width, vmode_height, 32, pixel_format_32.Rmask, pixel_format_32.Gmask, pixel_format_32.Bmask, 0);
845
846
847 if (nogl || screen_mode.acceleration == _no_acceleration) {
848 switch (graphics_preferences->software_sdl_driver) {
849 case _sw_driver_none:
850 SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
851 break;
852 case _sw_driver_opengl:
853 SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
854 break;
855 case _sw_driver_direct3d:
856 SDL_SetHint(SDL_HINT_RENDER_DRIVER, "direct3d");
857 break;
858 case _sw_driver_default:
859 default:
860 SDL_SetHint(SDL_HINT_RENDER_DRIVER, "");
861 break;
862 }
863 }
864
865 if (need_mode_change(sdl_width, sdl_height, vmode_width, vmode_height, depth, nogl)) {
866 #ifdef HAVE_OPENGL
867 if (!nogl && screen_mode.acceleration != _no_acceleration) {
868 passed_shader = false;
869 flags |= SDL_WINDOW_OPENGL;
870 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
871 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
872 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
873 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
874 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
875 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
876 if (Get_OGL_ConfigureData().Multisamples > 0) {
877 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
878 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, Get_OGL_ConfigureData().Multisamples);
879 } else {
880 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
881 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
882 }
883 SDL_GL_SetSwapInterval(Get_OGL_ConfigureData().WaitForVSync ? 1 : 0);
884 }
885 #endif
886
887
888 if (main_surface != NULL) {
889 SDL_FreeSurface(main_surface);
890 main_surface = NULL;
891 }
892 if (main_texture != NULL) {
893 SDL_DestroyTexture(main_texture);
894 main_texture = NULL;
895 }
896 if (main_render != NULL) {
897 SDL_DestroyRenderer(main_render);
898 main_render = NULL;
899 }
900 if (main_screen != NULL) {
901 Uint32 window_id = SDL_GetWindowID(main_screen);
902 SDL_DestroyWindow(main_screen);
903 main_screen = NULL;
904 SDL_FilterEvents(change_window_filter, &window_id);
905 }
906 main_screen = SDL_CreateWindow(get_application_name().c_str(),
907 SDL_WINDOWPOS_CENTERED,
908 SDL_WINDOWPOS_CENTERED,
909 sdl_width, sdl_height,
910 flags);
911
912 #ifdef HAVE_OPENGL
913 bool context_created = false;
914 if (main_screen == NULL && !nogl && screen_mode.acceleration != _no_acceleration && Get_OGL_ConfigureData().Multisamples > 0) {
915 // retry with multisampling off
916 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
917 SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0);
918 main_screen = SDL_CreateWindow(get_application_name().c_str(),
919 SDL_WINDOWPOS_CENTERED,
920 SDL_WINDOWPOS_CENTERED,
921 sdl_width, sdl_height,
922 flags);
923 if (main_screen)
924 failed_multisamples = Get_OGL_ConfigureData().Multisamples;
925 }
926 #endif
927 if (main_screen == NULL && !nogl && screen_mode.acceleration != _no_acceleration) {
928 fprintf(stderr, "WARNING: Failed to initialize OpenGL with 24 bit depth\n");
929 fprintf(stderr, "WARNING: Retrying with 16 bit depth\n");
930 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
931 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0);
932 main_screen = SDL_CreateWindow(get_application_name().c_str(),
933 SDL_WINDOWPOS_CENTERED,
934 SDL_WINDOWPOS_CENTERED,
935 sdl_width, sdl_height,
936 flags);
937 if (main_screen)
938 logWarning("Stencil buffer is not available");
939 }
940 if (main_screen != NULL && !nogl && screen_mode.acceleration == _opengl_acceleration)
941 {
942 // see if we can actually run shaders
943 if (!context_created) {
944 SDL_GL_CreateContext(main_screen);
945 context_created = true;
946 }
947 #ifdef __WIN32__
948 glewInit();
949 #endif
950 if (!OGL_CheckExtension("GL_ARB_vertex_shader") || !OGL_CheckExtension("GL_ARB_fragment_shader") || !OGL_CheckExtension("GL_ARB_shader_objects") || !OGL_CheckExtension("GL_ARB_shading_language_100"))
951 {
952 logWarning("OpenGL (Shader) renderer is not available");
953 fprintf(stderr, "WARNING: Failed to initialize OpenGL renderer\n");
954 fprintf(stderr, "WARNING: Retrying with Software renderer\n");
955 screen_mode.acceleration = graphics_preferences->screen_mode.acceleration = _no_acceleration;
956 main_screen = SDL_CreateWindow(get_application_name().c_str(),
957 SDL_WINDOWPOS_CENTERED,
958 SDL_WINDOWPOS_CENTERED,
959 sdl_width, sdl_height,
960 flags);
961 }
962 else
963 {
964 passed_shader = true;
965 }
966 }
967 //#endif
968
969 if (main_screen == NULL) {
970 fprintf(stderr, "Can't open video display (%s)\n", SDL_GetError());
971 #ifdef HAVE_OPENGL
972 fprintf(stderr, "WARNING: Failed to initialize OpenGL with 24 bit colour\n");
973 fprintf(stderr, "WARNING: Retrying with 16 bit colour\n");
974 logWarning("Trying OpenGL 16-bit mode");
975
976 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
977 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
978 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
979
980 main_screen = SDL_CreateWindow(get_application_name().c_str(),
981 SDL_WINDOWPOS_CENTERED,
982 SDL_WINDOWPOS_CENTERED,
983 sdl_width, sdl_height,
984 flags);
985 #endif
986 }
987 if (main_screen == NULL && (flags & SDL_WINDOW_FULLSCREEN_DESKTOP)) {
988 fprintf(stderr, "Can't open video display (%s)\n", SDL_GetError());
989 fprintf(stderr, "WARNING: Trying in windowed mode");
990 logWarning("Trying windowed mode");
991 uint32 tempflags = flags & SDL_WINDOW_FULLSCREEN_DESKTOP;
992 main_screen = SDL_CreateWindow(get_application_name().c_str(),
993 SDL_WINDOWPOS_CENTERED,
994 SDL_WINDOWPOS_CENTERED,
995 vmode_width, vmode_height,
996 tempflags);
997 if (main_screen) {
998 screen_mode.fullscreen = graphics_preferences->screen_mode.fullscreen = false;
999 }
1000 }
1001 if (main_screen == NULL && (flags & SDL_WINDOW_OPENGL)) {
1002 fprintf(stderr, "Can't open video display (%s)\n", SDL_GetError());
1003 fprintf(stderr, "WARNING: Trying in software mode");
1004 logWarning("Trying software mode");
1005 uint32 tempflags = (flags & ~SDL_WINDOW_OPENGL) | SDL_SWSURFACE;
1006 main_screen = SDL_CreateWindow(get_application_name().c_str(),
1007 SDL_WINDOWPOS_CENTERED,
1008 SDL_WINDOWPOS_CENTERED,
1009 sdl_width, sdl_height,
1010 tempflags);
1011 if (main_screen) {
1012 screen_mode.acceleration = graphics_preferences->screen_mode.acceleration = _no_acceleration;
1013 }
1014 }
1015 if (main_screen == NULL && (flags & (SDL_WINDOW_FULLSCREEN_DESKTOP|SDL_WINDOW_OPENGL))) {
1016 fprintf(stderr, "Can't open video display (%s)\n", SDL_GetError());
1017 fprintf(stderr, "WARNING: Trying in software windowed mode");
1018 logWarning("Trying software windowed mode");
1019 uint32 tempflags = (flags & ~(SDL_WINDOW_OPENGL|SDL_WINDOW_FULLSCREEN_DESKTOP)) | SDL_SWSURFACE;
1020 main_screen = SDL_CreateWindow(get_application_name().c_str(),
1021 SDL_WINDOWPOS_CENTERED,
1022 SDL_WINDOWPOS_CENTERED,
1023 vmode_width, vmode_height,
1024 tempflags);
1025 if (main_screen) {
1026 screen_mode.acceleration = graphics_preferences->screen_mode.acceleration = _no_acceleration;
1027 screen_mode.fullscreen = graphics_preferences->screen_mode.fullscreen = false;
1028 }
1029 }
1030 if (main_screen == NULL) {
1031 fprintf(stderr, "Can't open video display (%s)\n", SDL_GetError());
1032 fprintf(stderr, "ERROR: Unable to find working display mode");
1033 logWarning("Unable to find working display mode; exiting");
1034 vhalt("Cannot find a working video mode.");
1035 }
1036 #ifdef HAVE_OPENGL
1037 if (!context_created && !nogl && screen_mode.acceleration != _no_acceleration) {
1038 SDL_GL_CreateContext(main_screen);
1039 context_created = true;
1040 }
1041 #endif
1042 } // end if need_window
1043 if (nogl || screen_mode.acceleration == _no_acceleration) {
1044 if (!main_render) {
1045 main_render = SDL_CreateRenderer(main_screen, -1, 0);
1046 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
1047 SDL_RenderSetLogicalSize(main_render, vmode_width, vmode_height);
1048 main_texture = SDL_CreateTexture(main_render, pixel_format_32.format, SDL_TEXTUREACCESS_STREAMING, vmode_width, vmode_height);
1049 } else if (!main_texture) {
1050 main_texture = SDL_CreateTexture(main_render, pixel_format_32.format, SDL_TEXTUREACCESS_STREAMING, vmode_width, vmode_height);
1051 }
1052 }
1053 if (!main_surface) {
1054 main_surface = SDL_CreateRGBSurface(SDL_SWSURFACE, vmode_width, vmode_height, 32, pixel_format_32.Rmask, pixel_format_32.Gmask, pixel_format_32.Bmask, 0);
1055 }
1056 #ifdef MUST_RELOAD_VIEW_CONTEXT
1057 if (!nogl && screen_mode.acceleration != _no_acceleration)
1058 ReloadViewContext();
1059 #endif
1060 if (depth == 8) {
1061 SDL_Color colors[256];
1062 build_sdl_color_table(interface_color_table, colors);
1063 SDL_SetPaletteColors(main_surface->format->palette, colors, 0, 256);
1064 }
1065 if (HUD_Buffer) {
1066 SDL_FreeSurface(HUD_Buffer);
1067 HUD_Buffer = NULL;
1068 }
1069 if (Term_Buffer) {
1070 SDL_FreeSurface(Term_Buffer);
1071 Term_Buffer = NULL;
1072 }
1073 if (Intro_Buffer) {
1074 SDL_FreeSurface(Intro_Buffer);
1075 Intro_Buffer = NULL;
1076 }
1077 if (Intro_Buffer_corrected) {
1078 SDL_FreeSurface(Intro_Buffer_corrected);
1079 Intro_Buffer_corrected = NULL;
1080 }
1081
1082 screen_rectangle *term_rect = get_interface_rectangle(_terminal_screen_rect);
1083 Term_Buffer = SDL_CreateRGBSurface(SDL_SWSURFACE, RECTANGLE_WIDTH(term_rect), RECTANGLE_HEIGHT(term_rect), 32, pixel_format_32.Rmask, pixel_format_32.Gmask, pixel_format_32.Bmask, pixel_format_32.Amask);
1084
1085 Intro_Buffer = SDL_CreateRGBSurface(SDL_SWSURFACE, 640, 480, 32, pixel_format_32.Rmask, pixel_format_32.Gmask, pixel_format_32.Bmask, 0);
1086 Intro_Buffer_corrected = SDL_CreateRGBSurface(SDL_SWSURFACE, 640, 480, 32, pixel_format_32.Rmask, pixel_format_32.Gmask, pixel_format_32.Bmask, 0);
1087
1088 #ifdef HAVE_OPENGL
1089 if (!nogl && screen_mode.acceleration != _no_acceleration) {
1090 static bool gl_info_printed = false;
1091 if (!gl_info_printed)
1092 {
1093 printf("GL_VENDOR: %s\n", glGetString(GL_VENDOR));
1094 printf("GL_RENDERER: %s\n", glGetString(GL_RENDERER));
1095 printf("GL_VERSION: %s\n", glGetString(GL_VERSION));
1096 // const char *gl_extensions = (const char *)glGetString(GL_EXTENSIONS);
1097 // printf("GL_EXTENSIONS: %s\n", gl_extensions);
1098 gl_info_printed = true;
1099 }
1100 int pixw = MainScreenPixelWidth();
1101 int pixh = MainScreenPixelHeight();
1102 glScissor(0, 0, pixw, pixh);
1103 glViewport(0, 0, pixw, pixh);
1104
1105 OGL_ClearScreen();
1106 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
1107 glEnableClientState(GL_VERTEX_ARRAY);
1108 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
1109 #ifdef __WIN32__
1110 clear_screen();
1111 #endif
1112 }
1113 #endif
1114
1115 if (in_game && screen_mode.hud)
1116 {
1117 if (prev_width != main_surface->w || prev_height != main_surface->h)
1118 {
1119 L_Call_HUDResize();
1120 }
1121 }
1122 }
1123
get_auto_resolution_size(short * w,short * h,struct screen_mode_data * mode)1124 bool get_auto_resolution_size(short *w, short *h, struct screen_mode_data *mode)
1125 {
1126 if (screen_mode.auto_resolution)
1127 {
1128 short width = Screen::instance()->ModeWidth(0);
1129 short height = Screen::instance()->ModeHeight(0);
1130 // in windowed mode, use a window one step down from fullscreen size
1131 if (!screen_mode.fullscreen &&
1132 ((width > 640) || (height > 480)) &&
1133 (Screen::instance()->GetModes().size() > 1))
1134 {
1135 width = Screen::instance()->ModeWidth(1);
1136 height = Screen::instance()->ModeHeight(1);
1137 }
1138 if (w)
1139 *w = width;
1140 if (h)
1141 *h = height;
1142 if (mode)
1143 {
1144 mode->width = width;
1145 mode->height = height;
1146 }
1147 return true;
1148 }
1149 return false;
1150 }
1151
change_screen_mode(struct screen_mode_data * mode,bool redraw)1152 void change_screen_mode(struct screen_mode_data *mode, bool redraw)
1153 {
1154 // Get the screen mode here
1155 screen_mode = *mode;
1156
1157 // "Redraw" change now and clear the screen
1158 if (redraw) {
1159 short w = std::max(mode->width, static_cast<short>(640));
1160 short h = std::max(mode->height, static_cast<short>(480));
1161 if (!in_game)
1162 {
1163 w = 640;
1164 h = 480;
1165 }
1166 else
1167 get_auto_resolution_size(&w, &h, mode);
1168 change_screen_mode(w, h, mode->bit_depth, false, !in_game);
1169 clear_screen();
1170 recenter_mouse();
1171 }
1172
1173 frame_count = frame_index = 0;
1174 }
1175
change_screen_mode(short screentype)1176 void change_screen_mode(short screentype)
1177 {
1178 struct screen_mode_data *mode = &screen_mode;
1179
1180 short w = std::max(mode->width, static_cast<short>(640));
1181 short h = std::max(mode->height, static_cast<short>(480));
1182 if (screentype == _screentype_menu)
1183 {
1184 w = 640;
1185 h = 480;
1186 }
1187 else
1188 get_auto_resolution_size(&w, &h, mode);
1189
1190 bool force_menu_size = (screentype == _screentype_menu || screentype == _screentype_chapter);
1191 change_screen_mode(w, h, mode->bit_depth, false, force_menu_size);
1192 clear_screen();
1193 recenter_mouse();
1194
1195 frame_count = frame_index = 0;
1196 }
1197
toggle_fullscreen(bool fs)1198 void toggle_fullscreen(bool fs)
1199 {
1200 if (fs != screen_mode.fullscreen) {
1201 screen_mode.fullscreen = fs;
1202 if (in_game)
1203 change_screen_mode(&screen_mode, true);
1204 else {
1205 change_screen_mode(&screen_mode, true);
1206 clear_screen();
1207 }
1208 }
1209 }
1210
toggle_fullscreen()1211 void toggle_fullscreen()
1212 {
1213 toggle_fullscreen(! screen_mode.fullscreen);
1214 if (!in_game) {
1215 update_game_window();
1216 }
1217 }
1218
1219
1220 /*
1221 * Render game screen
1222 */
1223
1224 static bool clear_next_screen = false;
1225
render_screen(short ticks_elapsed)1226 void render_screen(short ticks_elapsed)
1227 {
1228 // Make whatever changes are necessary to the world_view structure based on whichever player is frontmost
1229 world_view->ticks_elapsed = ticks_elapsed;
1230 world_view->tick_count = dynamic_world->tick_count;
1231 world_view->yaw = current_player->facing;
1232 world_view->virtual_yaw = (current_player->facing * FIXED_ONE) + virtual_aim_delta().yaw;
1233 world_view->pitch = current_player->elevation;
1234 world_view->virtual_pitch = (current_player->elevation * FIXED_ONE) + virtual_aim_delta().pitch;
1235 world_view->maximum_depth_intensity = current_player->weapon_intensity;
1236 world_view->shading_mode = current_player->infravision_duration ? _shading_infravision : _shading_normal;
1237
1238 bool SwitchedModes = false;
1239
1240 // Suppress the overhead map if desired
1241 if (PLAYER_HAS_MAP_OPEN(current_player) && View_MapActive()) {
1242 if (!world_view->overhead_map_active) {
1243 set_overhead_map_status(true);
1244 SwitchedModes = true;
1245 }
1246 } else {
1247 if (world_view->overhead_map_active) {
1248 set_overhead_map_status(false);
1249 SwitchedModes = true;
1250 }
1251 }
1252
1253 if(player_in_terminal_mode(current_player_index)) {
1254 if (!world_view->terminal_mode_active) {
1255 set_terminal_status(true);
1256 SwitchedModes = true;
1257 }
1258 } else {
1259 if (world_view->terminal_mode_active) {
1260 set_terminal_status(false);
1261 SwitchedModes = true;
1262 }
1263 }
1264
1265 // Set rendering-window bounds for the current sort of display to render
1266 screen_mode_data *mode = &screen_mode;
1267
1268 SDL_Rect HUD_DestRect = Screen::instance()->hud_rect();
1269 SDL_Rect ViewRect, MapRect, TermRect;
1270
1271 bool ViewChangedSize = false;
1272 bool MapChangedSize = false;
1273
1274 // Switching fullscreen mode requires much the same reinitialization as switching the screen size
1275 if (mode->fullscreen != PrevFullscreen) {
1276 PrevFullscreen = mode->fullscreen;
1277 ViewChangedSize = true;
1278 MapChangedSize = true;
1279 }
1280
1281 // Each kind of display needs its own size
1282 ViewRect = Screen::instance()->view_rect();
1283 MapRect = Screen::instance()->map_rect();
1284 TermRect = Screen::instance()->term_rect();
1285
1286 static SDL_Rect PrevViewRect = { 0, 0, 0, 0 };
1287 if (memcmp(&PrevViewRect, &ViewRect, sizeof(SDL_Rect)))
1288 {
1289 ViewChangedSize = true;
1290 PrevViewRect = ViewRect;
1291 }
1292
1293 static SDL_Rect PrevMapRect = { 0, 0, 0, 0 };
1294 if (memcmp(&PrevMapRect, &MapRect, sizeof(SDL_Rect)))
1295 {
1296 MapChangedSize = true;
1297 PrevMapRect = MapRect;
1298 }
1299
1300 static bool PrevTransparent = false;
1301 bool MapIsTranslucent = map_is_translucent();
1302 if (PrevTransparent != MapIsTranslucent)
1303 {
1304 MapChangedSize = true;
1305 PrevTransparent = MapIsTranslucent;
1306 }
1307
1308 static bool PrevHighRes = true;
1309 bool HighResolution = mode->high_resolution;
1310 if (PrevHighRes != HighResolution)
1311 {
1312 ViewChangedSize = true;
1313 PrevHighRes = HighResolution;
1314 }
1315
1316 static short PrevDepth = 0;
1317 if (PrevDepth != mode->bit_depth)
1318 {
1319 ViewChangedSize = true;
1320 PrevDepth = mode->bit_depth;
1321 }
1322
1323 SDL_Rect BufferRect = {0, 0, ViewRect.w, ViewRect.h};
1324 // Now the buffer rectangle; be sure to shrink it as appropriate
1325 if (!HighResolution && screen_mode.acceleration == _no_acceleration) {
1326 BufferRect.w >>= 1;
1327 BufferRect.h >>= 1;
1328 }
1329
1330 // Set up view data appropriately
1331 world_view->screen_width = BufferRect.w;
1332 world_view->screen_height = BufferRect.h;
1333 world_view->standard_screen_width = 2 * BufferRect.h;
1334 initialize_view_data(world_view);
1335
1336 bool update_full_screen = false;
1337 if (ViewChangedSize || MapChangedSize || SwitchedModes) {
1338 clear_screen_margin();
1339 update_full_screen = true;
1340 if (Screen::instance()->hud() && !Screen::instance()->lua_hud())
1341 draw_interface();
1342
1343 // Reallocate the drawing buffer
1344 if (ViewChangedSize)
1345 reallocate_world_pixels(BufferRect.w, BufferRect.h);
1346 if (MapChangedSize)
1347 reallocate_map_pixels(MapRect.w, MapRect.h);
1348
1349 dirty_terminal_view(current_player_index);
1350 }
1351 else if (screen_mode.acceleration != _no_acceleration && clear_next_screen)
1352 {
1353 clear_screen(false);
1354 update_full_screen = true;
1355 if (Screen::instance()->hud() && !Screen::instance()->lua_hud())
1356 draw_interface();
1357
1358 clear_next_screen = false;
1359 }
1360
1361 switch (screen_mode.acceleration) {
1362 case _opengl_acceleration:
1363 // If we're using the overhead map, fall through to no acceleration
1364 if (!world_view->overhead_map_active && !world_view->terminal_mode_active)
1365 break;
1366 case _no_acceleration:
1367 world_pixels_structure->width = world_view->screen_width;
1368 world_pixels_structure->height = world_view->screen_height;
1369 world_pixels_structure->bytes_per_row = world_pixels->pitch;
1370 world_pixels_structure->flags = 0;
1371 world_pixels_structure->bit_depth = bit_depth;
1372 world_pixels_structure->row_addresses[0] = (pixel8 *)world_pixels->pixels;
1373
1374 //!! set world_pixels to VoidColor to avoid smearing?
1375
1376 precalculate_bitmap_row_addresses(world_pixels_structure);
1377 break;
1378 default:
1379 assert(false);
1380 break;
1381 }
1382
1383 world_view->origin = current_player->camera_location;
1384 if (!graphics_preferences->screen_mode.camera_bob)
1385 world_view->origin.z -= current_player->step_height;
1386 world_view->origin_polygon_index = current_player->camera_polygon_index;
1387
1388 // Script-based camera control
1389 if (!UseLuaCameras())
1390 world_view->show_weapons_in_hand = !ChaseCam_GetPosition(world_view->origin, world_view->origin_polygon_index, world_view->yaw, world_view->pitch);
1391
1392 #ifdef HAVE_OPENGL
1393 // Is map to be drawn with OpenGL?
1394 if (OGL_IsActive() && world_view->overhead_map_active)
1395 OGL_MapActive = true;
1396 else
1397 OGL_MapActive = false;
1398
1399 // Set OpenGL viewport to world view
1400 Rect sr = MakeRect(0, 0, Screen::instance()->height(), Screen::instance()->width());
1401 Rect vr = MakeRect(ViewRect);
1402 Screen::instance()->bound_screen_to_rect(ViewRect);
1403 OGL_SetWindow(sr, vr, true);
1404
1405 #endif
1406
1407 // clear drawing from previous frame
1408 // (GL must do this before render_view)
1409 if (screen_mode.acceleration != _no_acceleration)
1410 clear_screen_margin();
1411
1412 // Render world view
1413 render_view(world_view, world_pixels_structure);
1414
1415 // clear Lua drawing from previous frame
1416 // (SDL is slower if we do this before render_view)
1417 if (screen_mode.acceleration == _no_acceleration &&
1418 (MapIsTranslucent || Screen::instance()->lua_hud()))
1419 clear_screen_margin();
1420
1421 // Render crosshairs
1422 if (!world_view->overhead_map_active && !world_view->terminal_mode_active)
1423 if (NetAllowCrosshair())
1424 if (Crosshairs_IsActive())
1425 #ifdef HAVE_OPENGL
1426 if (!OGL_RenderCrosshairs())
1427 #endif
1428 Crosshairs_Render(world_pixels);
1429
1430 SDL_Surface *disp_pixels = world_pixels;
1431 if (world_view->overhead_map_active)
1432 disp_pixels = Map_Buffer;
1433
1434 // Display FPS and position
1435 if (!world_view->terminal_mode_active) {
1436 extern bool chat_input_mode;
1437 if (!chat_input_mode){
1438 update_fps_display(disp_pixels);
1439 }
1440 DisplayPosition(disp_pixels);
1441 DisplayNetMicStatus(disp_pixels);
1442 DisplayScores(disp_pixels);
1443 }
1444 DisplayMessages(disp_pixels);
1445 DisplayInputLine(disp_pixels);
1446
1447 #ifdef HAVE_OPENGL
1448 // Set OpenGL viewport to whole window (so HUD will be in the right position)
1449 Screen::instance()->bound_screen();
1450 OGL_SetWindow(sr, sr, true);
1451 #endif
1452
1453
1454 // If the main view is not being rendered in software but OpenGL is active,
1455 // then blit the software rendering to the screen
1456 if (screen_mode.acceleration != _no_acceleration) {
1457 #ifdef HAVE_OPENGL
1458 if (Screen::instance()->hud()) {
1459 if (Screen::instance()->lua_hud())
1460 Lua_DrawHUD(ticks_elapsed);
1461 else {
1462 Rect dr = MakeRect(HUD_DestRect);
1463 OGL_DrawHUD(dr, ticks_elapsed);
1464 }
1465 }
1466
1467 if (world_view->terminal_mode_active) {
1468 // Copy 2D rendering to screen
1469
1470 if (Term_RenderRequest) {
1471 SDL_SetSurfaceBlendMode(Term_Buffer, SDL_BLENDMODE_NONE);
1472 Term_Blitter.Load(*Term_Buffer);
1473 Term_RenderRequest = false;
1474 }
1475 Term_Blitter.Draw(TermRect);
1476 }
1477
1478 #endif
1479 } else {
1480 // Update world window
1481 if (!world_view->terminal_mode_active &&
1482 (!world_view->overhead_map_active || MapIsTranslucent))
1483 update_screen(BufferRect, ViewRect, HighResolution);
1484
1485 // Update map
1486 if (world_view->overhead_map_active) {
1487 SDL_Rect src_rect = { 0, 0, MapRect.w, MapRect.h };
1488 DrawSurface(Map_Buffer, MapRect, src_rect);
1489 }
1490
1491 // Update HUD
1492 if (Screen::instance()->lua_hud())
1493 {
1494 Lua_DrawHUD(ticks_elapsed);
1495 }
1496 else if (HUD_RenderRequest) {
1497 SDL_Rect src_rect = { 0, 320, 640, 160 };
1498 DrawSurface(HUD_Buffer, HUD_DestRect, src_rect);
1499 HUD_RenderRequest = false;
1500 }
1501
1502 // Update terminal
1503 if (world_view->terminal_mode_active) {
1504 if (Term_RenderRequest || Screen::instance()->lua_hud()) {
1505 SDL_Rect src_rect = { 0, 0, Term_Buffer->w, Term_Buffer->h };
1506 DrawSurface(Term_Buffer, TermRect, src_rect);
1507 Term_RenderRequest = false;
1508 }
1509 }
1510
1511 if (update_full_screen || Screen::instance()->lua_hud())
1512 {
1513 MainScreenUpdateRect(0, 0, 0, 0);
1514 }
1515 else if ((!world_view->overhead_map_active || MapIsTranslucent) &&
1516 !world_view->terminal_mode_active)
1517 {
1518 MainScreenUpdateRects(1, &ViewRect);
1519 }
1520 }
1521
1522 #ifdef HAVE_OPENGL
1523 // Swap OpenGL double-buffers
1524 if (screen_mode.acceleration != _no_acceleration)
1525 OGL_SwapBuffers();
1526 #endif
1527
1528 Movie::instance()->AddFrame(Movie::FRAME_NORMAL);
1529 }
1530
1531 /*
1532 * Blit world view to screen
1533 */
1534
1535 template <class T>
quadruple_surface(const T * src,int src_pitch,T * dst,int dst_pitch,const SDL_Rect & dst_rect)1536 static inline void quadruple_surface(const T *src, int src_pitch, T *dst, int dst_pitch, const SDL_Rect &dst_rect)
1537 {
1538 int width = dst_rect.w / 2;
1539 int height = dst_rect.h / 2;
1540 dst += dst_rect.y * dst_pitch / sizeof(T) + dst_rect.x;
1541 T *dst2 = dst + dst_pitch / sizeof(T);
1542
1543 while (height-- > 0) {
1544 for (int x=0; x<width; x++) {
1545 T p = src[x];
1546 dst[x * 2] = dst[x * 2 + 1] = p;
1547 dst2[x * 2] = dst2[x * 2 + 1] = p;
1548 }
1549 src += src_pitch / sizeof(T);
1550 dst += dst_pitch * 2 / sizeof(T);
1551 dst2 += dst_pitch * 2 / sizeof(T);
1552 }
1553 }
1554
apply_gamma(SDL_Surface * src,SDL_Surface * dst)1555 static void apply_gamma(SDL_Surface *src, SDL_Surface *dst)
1556 {
1557 if (SDL_MUSTLOCK(dst)) {
1558 if (SDL_LockSurface(dst) < 0) return;
1559 }
1560 uint32 px, dst_px;
1561 uint8 src_r, src_g, src_b;
1562 uint8 dst_r, dst_g, dst_b;
1563
1564 uint32 srm = src->format->Rmask, sgm = src->format->Gmask, sbm = src->format->Bmask;
1565 uint32 drm = dst->format->Rmask, dgm = dst->format->Gmask, dbm = dst->format->Bmask;
1566 uint32 srs = src->format->Rshift, sgs = src->format->Gshift, sbs = src->format->Bshift;
1567 uint32 drs = dst->format->Rshift, dgs = dst->format->Gshift, dbs = dst->format->Bshift;
1568 uint32 srl = src->format->Rloss, sgl = src->format->Gloss, sbl = src->format->Bloss;
1569 uint32 drl = dst->format->Rloss, dgl = dst->format->Gloss, dbl = dst->format->Bloss;
1570
1571 int sbpp = src->format->BytesPerPixel;
1572 int dbpp = dst->format->BytesPerPixel;
1573 uint8 *sptr = static_cast<uint8*>(src->pixels);
1574 uint8 *dptr = static_cast<uint8*>(dst->pixels);
1575 size_t numpixels = src->w * src->h;
1576 for (size_t i = 0; i < numpixels; ++i) {
1577 switch (sbpp) {
1578 case 2:
1579 px = reinterpret_cast<uint16*>(sptr)[i];
1580 break;
1581 case 4:
1582 px = reinterpret_cast<uint32*>(sptr)[i];
1583 break;
1584 default:
1585 return;
1586 }
1587
1588 src_r = ((px & srm) >> srs) << srl;
1589 src_g = ((px & sgm) >> sgs) << sgl;
1590 src_b = ((px & sbm) >> sbs) << sbl;
1591 dst_r = current_gamma_r[src_r] >> 8;
1592 dst_g = current_gamma_g[src_g] >> 8;
1593 dst_b = current_gamma_b[src_b] >> 8;
1594 dst_px = (((dst_r >> drl) << drs) & drm) |
1595 (((dst_g >> dgl) << dgs) & dgm) |
1596 (((dst_b >> dbl) << dbs) & dbm);
1597
1598 switch (dbpp) {
1599 case 2:
1600 reinterpret_cast<uint16*>(dptr)[i] = dst_px;
1601 break;
1602 case 4:
1603 reinterpret_cast<uint32*>(dptr)[i] = dst_px;
1604 break;
1605 default:
1606 return;
1607 }
1608 }
1609 if (SDL_MUSTLOCK(dst))
1610 SDL_UnlockSurface(dst);
1611 }
1612
pixel_formats_equal(SDL_PixelFormat * a,SDL_PixelFormat * b)1613 static inline bool pixel_formats_equal(SDL_PixelFormat* a, SDL_PixelFormat* b)
1614 {
1615 return (a->BytesPerPixel == b->BytesPerPixel &&
1616 a->Rmask == b->Rmask &&
1617 a->Gmask == b->Gmask &&
1618 a->Bmask == b->Bmask);
1619 }
1620
update_screen(SDL_Rect & source,SDL_Rect & destination,bool hi_rez)1621 static void update_screen(SDL_Rect &source, SDL_Rect &destination, bool hi_rez)
1622 {
1623 SDL_Surface *s = world_pixels;
1624 if (!using_default_gamma && bit_depth > 8) {
1625 apply_gamma(world_pixels, world_pixels_corrected);
1626 s = world_pixels_corrected;
1627 }
1628
1629 if (hi_rez)
1630 {
1631 SDL_BlitSurface(s, NULL, main_surface, &destination);
1632 }
1633 else
1634 {
1635 SDL_Surface* intermediary = 0;
1636 if (SDL_MUSTLOCK(main_surface))
1637 {
1638 if (SDL_LockSurface(main_surface) < 0) return;
1639 }
1640
1641 if (s->format->BytesPerPixel != 1 && !pixel_formats_equal(s->format, main_surface->format))
1642 {
1643 intermediary = SDL_ConvertSurface(s, main_surface->format, s->flags);
1644 s = intermediary;
1645 }
1646
1647 switch (s->format->BytesPerPixel)
1648 {
1649 case 1:
1650 quadruple_surface((pixel8 *)s->pixels, s->pitch, (pixel8 *)main_surface->pixels, main_surface->pitch, destination);
1651 break;
1652 case 2:
1653 quadruple_surface((pixel16 *)s->pixels, s->pitch, (pixel16 *)main_surface->pixels, main_surface->pitch, destination);
1654 break;
1655 case 4:
1656 quadruple_surface((pixel32 *)s->pixels, s->pitch, (pixel32 *)main_surface->pixels, main_surface->pitch, destination);
1657 break;
1658 }
1659
1660 if (SDL_MUSTLOCK(main_surface)) {
1661 SDL_UnlockSurface(main_surface);
1662 }
1663
1664 if (intermediary)
1665 {
1666 SDL_FreeSurface(intermediary);
1667 }
1668 }
1669 // SDL_UpdateRects(main_surface, 1, &destination);
1670 }
1671
1672
1673 /*
1674 * Update game display if it was overdrawn
1675 */
1676
update_screen_window(void)1677 void update_screen_window(void)
1678 {
1679 draw_interface();
1680 assert_world_color_table(interface_color_table, world_color_table);
1681 }
1682
1683
1684 /*
1685 * Color table handling
1686 */
1687
build_sdl_color_table(const color_table * color_table,SDL_Color * colors)1688 static void build_sdl_color_table(const color_table *color_table, SDL_Color *colors)
1689 {
1690 const rgb_color *src = color_table->colors;
1691 SDL_Color *dst = colors;
1692 for (int i=0; i<color_table->color_count; i++) {
1693 dst->r = src->red >> 8;
1694 dst->g = src->green >> 8;
1695 dst->b = src->blue >> 8;
1696 dst->a = 0xff;
1697 src++; dst++;
1698 }
1699 }
1700
initialize_gamma(void)1701 void initialize_gamma(void)
1702 {
1703 if (!default_gamma_inited) {
1704 default_gamma_inited = true;
1705 for (int i = 0; i < 256; ++i) {
1706 default_gamma_r[i] = default_gamma_g[i] = default_gamma_b[i] = i << 8;
1707 }
1708 memcpy(current_gamma_r, default_gamma_r, sizeof(current_gamma_r));
1709 memcpy(current_gamma_g, default_gamma_g, sizeof(current_gamma_g));
1710 memcpy(current_gamma_b, default_gamma_b, sizeof(current_gamma_b));
1711 }
1712 }
1713
build_direct_color_table(struct color_table * color_table,short bit_depth)1714 void build_direct_color_table(struct color_table *color_table, short bit_depth)
1715 {
1716 if (!option_nogamma && !default_gamma_inited)
1717 initialize_gamma();
1718 color_table->color_count = 256;
1719 rgb_color *color = color_table->colors;
1720 bool force_software = Movie::instance()->IsRecording();
1721 for (int i=0; i<256; i++, color++)
1722 {
1723 color->red = force_software ? i << 8 : default_gamma_r[i];
1724 color->green = force_software ? i << 8 : default_gamma_g[i];
1725 color->blue = force_software ? i << 8 : default_gamma_b[i];
1726 }
1727 }
1728
change_interface_clut(struct color_table * color_table)1729 void change_interface_clut(struct color_table *color_table)
1730 {
1731 memcpy(interface_color_table, color_table, sizeof(struct color_table));
1732 }
1733
change_screen_clut(struct color_table * color_table)1734 void change_screen_clut(struct color_table *color_table)
1735 {
1736 build_direct_color_table(uncorrected_color_table, bit_depth);
1737 memcpy(interface_color_table, uncorrected_color_table, sizeof(struct color_table));
1738
1739 gamma_correct_color_table(uncorrected_color_table, world_color_table, screen_mode.gamma_level);
1740 memcpy(visible_color_table, world_color_table, sizeof(struct color_table));
1741
1742 assert_world_color_table(interface_color_table, world_color_table);
1743 }
1744
animate_screen_clut(struct color_table * color_table,bool full_screen)1745 void animate_screen_clut(struct color_table *color_table, bool full_screen)
1746 {
1747 for (int i=0; i<color_table->color_count; i++) {
1748 current_gamma_r[i] = color_table->colors[i].red;
1749 current_gamma_g[i] = color_table->colors[i].green;
1750 current_gamma_b[i] = color_table->colors[i].blue;
1751 }
1752 using_default_gamma = !memcmp(color_table, uncorrected_color_table, sizeof(struct color_table));
1753 }
1754
assert_world_color_table(struct color_table * interface_color_table,struct color_table * world_color_table)1755 void assert_world_color_table(struct color_table *interface_color_table, struct color_table *world_color_table)
1756 {
1757 if (interface_bit_depth == 8) {
1758 SDL_Color colors[256];
1759 build_sdl_color_table(interface_color_table, colors);
1760 SDL_SetPaletteColors(main_surface->format->palette, colors, 0, 256);
1761 if (HUD_Buffer)
1762 SDL_SetPaletteColors(HUD_Buffer->format->palette, colors, 0, 256);
1763 }
1764 if (world_color_table)
1765 animate_screen_clut(world_color_table, false);
1766 }
1767
1768
1769 /*
1770 * Render terminal
1771 */
1772
render_computer_interface(struct view_data * view)1773 void render_computer_interface(struct view_data *view)
1774 {
1775 _set_port_to_term();
1776 _render_computer_interface();
1777 _restore_port();
1778 }
1779
1780
1781 /*
1782 * Render overhead map
1783 */
1784
render_overhead_map(struct view_data * view)1785 void render_overhead_map(struct view_data *view)
1786 {
1787 #ifdef HAVE_OPENGL
1788 if (OGL_IsActive()) {
1789 // Set OpenGL viewport to world view
1790 Rect sr = MakeRect(0, 0, Screen::instance()->height(), Screen::instance()->width());
1791 SDL_Rect MapRect = Screen::instance()->map_rect();
1792 Rect mr = MakeRect(MapRect);
1793 Screen::instance()->bound_screen_to_rect(MapRect);
1794 OGL_SetWindow(sr, mr, true);
1795 }
1796 #endif
1797 struct overhead_map_data overhead_data;
1798 SDL_FillRect(Map_Buffer, NULL, SDL_MapRGB(Map_Buffer->format, 0, 0, 0));
1799
1800 SDL_Rect maprect = Screen::instance()->map_rect();
1801 overhead_data.half_width = maprect.w >> 1;
1802 overhead_data.half_height = maprect.h >> 1;
1803 overhead_data.width = maprect.w;
1804 overhead_data.height = maprect.h;
1805 overhead_data.top = overhead_data.left = 0;
1806
1807 overhead_data.scale = view->overhead_map_scale;
1808 overhead_data.mode = _rendering_game_map;
1809 overhead_data.origin.x = view->origin.x;
1810 overhead_data.origin.y = view->origin.y;
1811
1812 _set_port_to_map();
1813 _render_overhead_map(&overhead_data);
1814 _restore_port();
1815 }
1816
1817
1818 /*
1819 * Get world view destination frame for given screen size
1820 */
1821
calculate_destination_frame(short size,bool high_resolution,Rect * frame)1822 void calculate_destination_frame(short size, bool high_resolution, Rect *frame)
1823 {
1824 frame->left = frame->top = 0;
1825
1826 // Calculate destination frame
1827 switch (size) {
1828 case _full_screen:
1829 frame->right = DESIRED_SCREEN_WIDTH;
1830 frame->bottom = DESIRED_SCREEN_HEIGHT;
1831 break;
1832 case _100_percent:
1833 frame->right = DEFAULT_WORLD_WIDTH;
1834 frame->bottom = DEFAULT_WORLD_HEIGHT;
1835 break;
1836 case _75_percent:
1837 frame->right = 3 * DEFAULT_WORLD_WIDTH / 4;
1838 frame->bottom = 3 * DEFAULT_WORLD_HEIGHT / 4;
1839 break;
1840 case _50_percent:
1841 frame->right = DEFAULT_WORLD_WIDTH / 2;
1842 frame->bottom = DEFAULT_WORLD_HEIGHT / 2;
1843 break;
1844 }
1845
1846 if (size != _full_screen) {
1847 int dx = (DEFAULT_WORLD_WIDTH - frame->right) / 2;
1848 int dy = (DEFAULT_WORLD_HEIGHT - frame->bottom) / 2;
1849 frame->top += dy;
1850 frame->left += dx;
1851 frame->bottom += dy;
1852 frame->right += dx;
1853 }
1854 }
1855
1856
1857 /*
1858 * Draw dithered black pattern over world window
1859 */
1860
1861 template <class T>
draw_pattern_rect(T * p,int pitch,uint32 pixel,const SDL_Rect & r)1862 static inline void draw_pattern_rect(T *p, int pitch, uint32 pixel, const SDL_Rect &r)
1863 {
1864 p += r.y * pitch / sizeof(T) + r.x;
1865 for (int y=0; y<r.h; y++) {
1866 for (int x=y&1; x<r.w; x+=2)
1867 p[x] = pixel;
1868 p += pitch / sizeof(T);
1869 }
1870 }
1871
darken_world_window(void)1872 void darken_world_window(void)
1873 {
1874 // Get world window bounds
1875 SDL_Rect r = Screen::instance()->window_rect();
1876
1877 #ifdef HAVE_OPENGL
1878 if (MainScreenIsOpenGL()) {
1879
1880 // Save current state
1881 glPushAttrib(GL_ALL_ATTRIB_BITS);
1882
1883 // Disable everything but alpha blending
1884 glDisable(GL_DEPTH_TEST);
1885 glDisable(GL_ALPHA_TEST);
1886 glEnable(GL_BLEND);
1887 glDisable(GL_TEXTURE_2D);
1888 glDisable(GL_FOG);
1889 glDisable(GL_SCISSOR_TEST);
1890 glDisable(GL_STENCIL_TEST);
1891
1892 // Direct projection
1893 glMatrixMode(GL_PROJECTION);
1894 glPushMatrix();
1895 glLoadIdentity();
1896 glOrtho(0.0, GLdouble(main_surface->w), GLdouble(main_surface->h), 0.0, 0.0, 1.0);
1897 glMatrixMode(GL_MODELVIEW);
1898 glPushMatrix();
1899 glLoadIdentity();
1900
1901 // Draw 50% black rectangle
1902 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1903 glColor4f(0.0, 0.0, 0.0, 0.5);
1904 OGL_RenderRect(r);
1905
1906 // Restore projection and state
1907 glPopMatrix();
1908 glMatrixMode(GL_PROJECTION);
1909 glPopMatrix();
1910 glPopAttrib();
1911
1912 MainScreenSwap();
1913 return;
1914 }
1915 #endif
1916
1917 // Get black pixel value
1918 uint32 pixel = SDL_MapRGB(main_surface->format, 0, 0, 0);
1919
1920 // Lock surface
1921 if (SDL_MUSTLOCK(main_surface))
1922 if (SDL_LockSurface(main_surface) < 0)
1923 return;
1924
1925 // Draw pattern
1926 switch (main_surface->format->BytesPerPixel) {
1927 case 1:
1928 draw_pattern_rect((pixel8 *)main_surface->pixels, main_surface->pitch, pixel, r);
1929 break;
1930 case 2:
1931 draw_pattern_rect((pixel16 *)main_surface->pixels, main_surface->pitch, pixel, r);
1932 break;
1933 case 4:
1934 draw_pattern_rect((pixel32 *)main_surface->pixels, main_surface->pitch, pixel, r);
1935 break;
1936 }
1937
1938 // Unlock surface
1939 if (SDL_MUSTLOCK(main_surface))
1940 SDL_UnlockSurface(main_surface);
1941
1942 MainScreenUpdateRects(1, &r);
1943 }
1944
1945
1946 /*
1947 * Validate world window
1948 */
1949
validate_world_window(void)1950 void validate_world_window(void)
1951 {
1952 RequestDrawingTerm();
1953 }
1954
1955
1956 /*
1957 * Draw the HUD or terminal (non-OpenGL)
1958 */
1959
DrawSurface(SDL_Surface * s,SDL_Rect & dest_rect,SDL_Rect & src_rect)1960 void DrawSurface(SDL_Surface *s, SDL_Rect &dest_rect, SDL_Rect &src_rect)
1961 {
1962 if (s) {
1963 SDL_Rect new_src_rect = {src_rect.x, src_rect.y, src_rect.w, src_rect.h};
1964 SDL_Surface *surface = s;
1965 if (dest_rect.w != src_rect.w || dest_rect.h != src_rect.h)
1966 {
1967 double x_scale = dest_rect.w / (double) src_rect.w;
1968 double y_scale = dest_rect.h / (double) src_rect.h;
1969 surface = rescale_surface(s, static_cast<int>(s->w * x_scale), static_cast<int>(s->h * y_scale));
1970 new_src_rect.x = static_cast<Sint16>(new_src_rect.x * x_scale);
1971 new_src_rect.y = static_cast<Sint16>(new_src_rect.y * y_scale);
1972 new_src_rect.w = static_cast<Uint16>(new_src_rect.w * x_scale);
1973 new_src_rect.h = static_cast<Uint16>(new_src_rect.h * y_scale);
1974 }
1975 SDL_BlitSurface(surface, &new_src_rect, main_surface, &dest_rect);
1976 if (!Screen::instance()->lua_hud() || (get_game_state() != _game_in_progress))
1977 MainScreenUpdateRects(1, &dest_rect);
1978
1979 if (surface != s)
1980 SDL_FreeSurface(surface);
1981 }
1982 }
1983
draw_intro_screen(void)1984 void draw_intro_screen(void)
1985 {
1986 if (fade_blacked_screen())
1987 return;
1988
1989 SDL_Rect src_rect = { 0, 0, Intro_Buffer->w, Intro_Buffer->h };
1990 SDL_Rect dst_rect = { 0, 0, src_rect.w, src_rect.h};
1991
1992 #ifdef HAVE_OPENGL
1993 if (OGL_IsActive()) {
1994 if (intro_buffer_changed) {
1995 SDL_SetSurfaceBlendMode(Intro_Buffer, SDL_BLENDMODE_NONE);
1996 Intro_Blitter.Load(*Intro_Buffer);
1997 intro_buffer_changed = false;
1998 }
1999 OGL_Blitter::BoundScreen();
2000 OGL_ClearScreen();
2001 Intro_Blitter.Draw(dst_rect);
2002
2003 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
2004 glEnableClientState(GL_VERTEX_ARRAY);
2005 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
2006 OGL_DoFades(dst_rect.x, dst_rect.y, dst_rect.x + dst_rect.w, dst_rect.y + dst_rect.h);
2007 OGL_SwapBuffers();
2008 } else
2009 #endif
2010 {
2011 SDL_Surface *s = Intro_Buffer;
2012 if (!using_default_gamma && bit_depth > 8) {
2013 apply_gamma(Intro_Buffer, Intro_Buffer_corrected);
2014 SDL_SetSurfaceBlendMode(Intro_Buffer_corrected, SDL_BLENDMODE_NONE);
2015 s = Intro_Buffer_corrected;
2016 }
2017 DrawSurface(s, dst_rect, src_rect);
2018 intro_buffer_changed = false;
2019 }
2020 }
2021
2022 /*
2023 * Clear screen
2024 */
2025
clear_screen(bool update)2026 void clear_screen(bool update)
2027 {
2028 #ifdef HAVE_OPENGL
2029 if (MainScreenIsOpenGL()) {
2030 OGL_ClearScreen();
2031 if (update) {
2032 MainScreenSwap();
2033 OGL_ClearScreen();
2034 }
2035 } else
2036 #endif
2037 {
2038 SDL_FillRect(main_surface, NULL, SDL_MapRGB(main_surface->format, 0, 0, 0));
2039 if (update) MainScreenUpdateRect(0, 0, 0, 0);
2040 }
2041
2042 clear_next_screen = true;
2043 }
2044
clear_screen_margin()2045 void clear_screen_margin()
2046 {
2047 #ifdef HAVE_OPENGL
2048 if (MainScreenIsOpenGL()) {
2049 OGL_ClearScreen();
2050 return;
2051 }
2052 #endif
2053 SDL_Rect r, wr, dr;
2054 wr = Screen::instance()->window_rect();
2055 if (world_view->terminal_mode_active)
2056 dr = Screen::instance()->term_rect();
2057 else if (world_view->overhead_map_active && !map_is_translucent())
2058 dr = Screen::instance()->map_rect();
2059 else
2060 dr = Screen::instance()->view_rect();
2061
2062 dr.x -= wr.x;
2063 dr.y -= wr.y;
2064 if (Screen::instance()->hud() && !Screen::instance()->lua_hud())
2065 wr.h -= Screen::instance()->hud_rect().h;
2066
2067 if (dr.x > 0)
2068 {
2069 r.x = wr.x;
2070 r.y = wr.y;
2071 r.w = dr.x;
2072 r.h = wr.h;
2073 SDL_FillRect(main_surface, &r, SDL_MapRGB(main_surface->format, 0, 0, 0));
2074 }
2075 if ((dr.x + dr.w) < wr.w)
2076 {
2077 r.x = wr.x + dr.x + dr.w;
2078 r.y = wr.y;
2079 r.w = wr.w - (dr.x + dr.w);
2080 r.h = wr.h;
2081 SDL_FillRect(main_surface, &r, SDL_MapRGB(main_surface->format, 0, 0, 0));
2082 }
2083 if (dr.y > 0)
2084 {
2085 r.x = wr.x + dr.x;
2086 r.y = wr.y;
2087 r.w = dr.x + dr.w;
2088 r.h = dr.y;
2089 SDL_FillRect(main_surface, &r, SDL_MapRGB(main_surface->format, 0, 0, 0));
2090 }
2091 if ((dr.y + dr.h) < wr.h)
2092 {
2093 r.x = wr.x + dr.x;
2094 r.y = wr.y + dr.y + dr.h;
2095 r.w = dr.x + dr.w;
2096 r.h = wr.h - (dr.y + dr.h);
2097 SDL_FillRect(main_surface, &r, SDL_MapRGB(main_surface->format, 0, 0, 0));
2098 }
2099 }
2100
MainScreenVisible()2101 bool MainScreenVisible()
2102 {
2103 return (main_screen != NULL);
2104 }
MainScreenLogicalWidth()2105 int MainScreenLogicalWidth()
2106 {
2107 return (main_surface ? main_surface->w : 0);
2108 }
MainScreenLogicalHeight()2109 int MainScreenLogicalHeight()
2110 {
2111 return (main_surface ? main_surface->h : 0);
2112 }
MainScreenWindowWidth()2113 int MainScreenWindowWidth()
2114 {
2115 int w = 0;
2116 SDL_GetWindowSize(main_screen, &w, NULL);
2117 return w;
2118 }
MainScreenWindowHeight()2119 int MainScreenWindowHeight()
2120 {
2121 int h = 0;
2122 SDL_GetWindowSize(main_screen, NULL, &h);
2123 return h;
2124 }
MainScreenPixelWidth()2125 int MainScreenPixelWidth()
2126 {
2127 int w = 0;
2128 #ifdef HAVE_OPENGL
2129 if (MainScreenIsOpenGL())
2130 SDL_GL_GetDrawableSize(main_screen, &w, NULL);
2131 else
2132 #endif
2133 SDL_GetRendererOutputSize(main_render, &w, NULL);
2134 return w;
2135 }
MainScreenPixelHeight()2136 int MainScreenPixelHeight()
2137 {
2138 int h = 0;
2139 #ifdef HAVE_OPENGL
2140 if (MainScreenIsOpenGL())
2141 SDL_GL_GetDrawableSize(main_screen, NULL, &h);
2142 else
2143 #endif
2144 SDL_GetRendererOutputSize(main_render, NULL, &h);
2145 return h;
2146 }
MainScreenPixelScale()2147 float MainScreenPixelScale()
2148 {
2149 return MainScreenPixelWidth() / static_cast<float>(MainScreenWindowWidth());
2150 }
MainScreenIsOpenGL()2151 bool MainScreenIsOpenGL()
2152 {
2153 return (main_screen && !main_render);
2154 }
MainScreenSwap()2155 void MainScreenSwap()
2156 {
2157 SDL_GL_SwapWindow(main_screen);
2158 }
MainScreenCenterMouse()2159 void MainScreenCenterMouse()
2160 {
2161 int w, h;
2162 SDL_GetWindowSize(main_screen, &w, &h);
2163 SDL_WarpMouseInWindow(main_screen, w/2, h/2);
2164 }
MainScreenSurface()2165 SDL_Surface *MainScreenSurface()
2166 {
2167 return main_surface;
2168 }
MainScreenUpdateRect(int x,int y,int w,int h)2169 void MainScreenUpdateRect(int x, int y, int w, int h)
2170 {
2171 SDL_Rect r;
2172 r.x = x;
2173 r.y = y;
2174 r.w = w;
2175 r.h = h;
2176 MainScreenUpdateRects(1, &r);
2177 }
MainScreenUpdateRects(size_t count,const SDL_Rect * rects)2178 void MainScreenUpdateRects(size_t count, const SDL_Rect *rects)
2179 {
2180 SDL_UpdateTexture(main_texture, NULL, main_surface->pixels, main_surface->pitch);
2181 SDL_RenderClear(main_render);
2182 SDL_RenderCopy(main_render, main_texture, NULL, NULL);
2183 // for (size_t i = 0; i < count; ++i) {
2184 // SDL_RenderCopy(main_render, main_texture, &rects[i], &rects[i]);
2185 // }
2186 SDL_RenderPresent(main_render);
2187 }
2188