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