1 /*
2 * Seven Kingdoms: Ancient Adversaries
3 *
4 * Copyright 1997,1998 Enlight Software Ltd.
5 * Copyright 2010,2015 Jesse Allen
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 //Filename : OVGA.cpp
23 //Description : VGA management class (SDL version)
24
25 #include <OVGA.h>
26 #include <OMOUSE.h>
27 #include <OCOLTBL.h>
28 #include <OSYS.h>
29 #include <dbglog.h>
30 #include <version.h>
31 #include <FilePath.h>
32 #include <ConfigAdv.h>
33
34 DBGLOG_DEFAULT_CHANNEL(Vga);
35
36 //--------- Declare static functions ---------//
37
38 static void init_dpi();
39 static int init_window_flags();
40 static void init_window_size();
41
42 //------ Define static class member vars ---------//
43
44 char Vga::use_back_buf = 0;
45 char Vga::opaque_flag = 0;
46 VgaBuf* Vga::active_buf = &vga_front; // default: front buffer
47
48 //-------- Begin of function Vga::Vga ----------//
49
Vga()50 Vga::Vga()
51 {
52 memset(game_pal, 0, sizeof(SDL_Color)*VGA_PALETTE_SIZE);
53 custom_pal = NULL;
54 vga_color_table = NULL;
55
56 target = NULL;
57 texture = NULL;
58 renderer = NULL;
59 window = NULL;
60 }
61 //-------- End of function Vga::Vga ----------//
62
63
64 //-------- Begin of function Vga::~Vga ----------//
65
~Vga()66 Vga::~Vga()
67 {
68 deinit();
69 }
70 //-------- End of function Vga::~Vga ----------//
71
72
73 //-------- Begin of function Vga::init ----------//
74
init()75 int Vga::init()
76 {
77 SDL_Surface *icon;
78
79 #ifdef USE_WINDOWS
80 init_dpi();
81 #endif
82
83 win_grab_forced = 0;
84 win_grab_user_mode = 0;
85 mouse_mode = MOUSE_INPUT_ABS;
86 boundary_set = 0;
87
88 if (SDL_Init(SDL_INIT_VIDEO))
89 return 0;
90
91 init_window_size();
92
93 // Save the mouse position to restore after mode change. If we don't do
94 // this, then the old position gets recalculated, with the mode change
95 // affecting the location, causing a jump.
96 int mouse_x, mouse_y;
97 SDL_GetGlobalMouseState(&mouse_x, &mouse_y);
98
99 window = SDL_CreateWindow(WIN_TITLE,
100 SDL_WINDOWPOS_UNDEFINED,
101 SDL_WINDOWPOS_UNDEFINED,
102 config_adv.vga_window_width,
103 config_adv.vga_window_height,
104 init_window_flags());
105 if( !window )
106 return 0;
107
108 if( config_adv.vga_full_screen )
109 set_window_grab(WINGRAB_ON);
110
111 renderer = SDL_CreateRenderer(window, -1, 0);
112 if( !renderer )
113 return 0;
114
115 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
116 SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1");
117 if( config_adv.vga_keep_aspect_ratio )
118 SDL_RenderSetLogicalSize(renderer, VGA_WIDTH, VGA_HEIGHT);
119
120 SDL_WarpMouseGlobal(mouse_x, mouse_y); // warp to initialize mouse by event queue
121
122 Uint32 window_pixel_format = SDL_GetWindowPixelFormat(window);
123 if (window_pixel_format == SDL_PIXELFORMAT_UNKNOWN)
124 {
125 ERR("Unknown pixel format: %s\n", SDL_GetError());
126 return 0;
127 }
128
129 // Cannot use SDL_PIXELFORMAT_INDEX8:
130 // Palettized textures are not supported
131 texture = SDL_CreateTexture(renderer,
132 window_pixel_format,
133 SDL_TEXTUREACCESS_STREAMING,
134 VGA_WIDTH,
135 VGA_HEIGHT);
136 if (!texture)
137 {
138 ERR("Could not create texture: %s\n", SDL_GetError());
139 return 0;
140 }
141
142 int desktop_bpp = 0;
143 if (SDL_PIXELTYPE(window_pixel_format) == SDL_PIXELTYPE_PACKED32)
144 {
145 desktop_bpp = 32;
146 }
147 else if (SDL_PIXELTYPE(window_pixel_format) == SDL_PIXELTYPE_PACKED16)
148 {
149 desktop_bpp = 16;
150 }
151 else if (SDL_PIXELTYPE(window_pixel_format) == SDL_PIXELTYPE_PACKED8)
152 {
153 desktop_bpp = 8;
154 }
155 else
156 {
157 ERR("Unsupported pixel type\n");
158 return 0;
159 }
160
161 target = SDL_CreateRGBSurface(0,
162 VGA_WIDTH,
163 VGA_HEIGHT,
164 desktop_bpp,
165 0, 0, 0, 0);
166 if (!target)
167 {
168 return 0;
169 }
170
171 FilePath icon_path(sys.dir_image);
172 icon_path += "7K_ICON.BMP";
173 icon = SDL_LoadBMP(icon_path);
174 if (icon)
175 {
176 Uint32 colorkey;
177 colorkey = SDL_MapRGB(icon->format, 0, 0, 0);
178 SDL_SetColorKey(icon, SDL_TRUE, colorkey);
179 SDL_SetWindowIcon(window, icon);
180 SDL_FreeSurface(icon);
181 }
182
183 return 1;
184 }
185 //-------- End of function Vga::init ----------//
186
187
188 //-------- Begin of function Vga::deinit ----------//
189
deinit()190 void Vga::deinit()
191 {
192 SDL_SetRelativeMouseMode(SDL_FALSE);
193 mouse_mode = MOUSE_INPUT_ABS;
194
195 vga_back.deinit();
196 if (sys.debug_session)
197 vga_true_front.deinit();
198 vga_front.deinit();
199
200 if (vga_color_table)
201 delete vga_color_table;
202 vga_color_table = NULL;
203 if( custom_pal )
204 mem_del(custom_pal);
205 custom_pal = NULL;
206
207 if( target )
208 SDL_FreeSurface(target);
209 target = NULL;
210 if( texture )
211 SDL_DestroyTexture(texture);
212 texture = NULL;
213 if( renderer )
214 SDL_DestroyRenderer(renderer);
215 renderer = NULL;
216 if( window )
217 SDL_DestroyWindow(window);
218 window = NULL;
219
220 SDL_Quit();
221 }
222 //-------- End of function Vga::deinit ----------//
223
224
225 //--------- Start of function Vga::load_pal ----------//
226 //
227 // Loads the default game palette specified by fileName. Creates the ddraw
228 // palette.
229 //
load_pal(const char * fileName)230 int Vga::load_pal(const char* fileName)
231 {
232 char palBuf[VGA_PALETTE_SIZE][3];
233 File palFile;
234
235 palFile.file_open(fileName);
236 palFile.file_seek(8); // bypass the header info
237 palFile.file_read(palBuf, VGA_PALETTE_SIZE*3);
238 palFile.file_close();
239
240 for (int i = 0; i < VGA_PALETTE_SIZE; i++)
241 {
242 game_pal[i].r = palBuf[i][0];
243 game_pal[i].g = palBuf[i][1];
244 game_pal[i].b = palBuf[i][2];
245 }
246
247 //----- initialize interface color table -----//
248
249 PalDesc palDesc( (unsigned char*) game_pal, sizeof(SDL_Color), VGA_PALETTE_SIZE, 8);
250 vga_color_table = new ColorTable;
251 vga_color_table->generate_table( MAX_BRIGHTNESS_ADJUST_DEGREE, palDesc, ColorTable::bright_func );
252
253 return 1;
254 }
255 //----------- End of function Vga::load_pal ----------//
256
257
258 //-------- Begin of function Vga::activate_pal ----------//
259 //
260 // we are getting the palette focus, select our palette
261 //
activate_pal(VgaBuf * vgaBufPtr)262 void Vga::activate_pal(VgaBuf* vgaBufPtr)
263 {
264 vgaBufPtr->activate_pal(game_pal);
265 }
266 //--------- End of function Vga::activate_pal ----------//
267
268
269 //-------- Begin of function Vga::set_custom_palette ----------//
270 //
271 // Read the custom palette specified by fileName and set to display.
272 //
set_custom_palette(char * fileName)273 int Vga::set_custom_palette(char *fileName)
274 {
275 if (!custom_pal)
276 custom_pal = (SDL_Color*)mem_add(sizeof(SDL_Color)*VGA_PALETTE_SIZE);
277
278 char palBuf[VGA_PALETTE_SIZE][3];
279 File palFile;
280
281 palFile.file_open(fileName);
282 palFile.file_seek(8); // bypass the header info
283 palFile.file_read(palBuf, VGA_PALETTE_SIZE*3);
284 palFile.file_close();
285
286 for(int i=0; i<VGA_PALETTE_SIZE; i++)
287 {
288 custom_pal[i].r = palBuf[i][0];
289 custom_pal[i].g = palBuf[i][1];
290 custom_pal[i].b = palBuf[i][2];
291 }
292
293 vga_front.activate_pal(custom_pal);
294
295 return 1;
296 }
297 //--------- End of function Vga::set_custom_palette ----------//
298
299
300 //--------- Begin of function Vga::free_custom_palette ----------//
301 //
302 // Frees the custom palette and restores the game palette.
303 //
free_custom_palette()304 void Vga::free_custom_palette()
305 {
306 if (custom_pal)
307 {
308 mem_del(custom_pal);
309 custom_pal = NULL;
310 }
311 vga_front.activate_pal(game_pal);
312 }
313 //--------- End of function Vga::free_custom_palette ----------//
314
315
316 //-------- Begin of function Vga::adjust_brightness ----------//
317 //
318 // <int> changeValue - the value to add to the RGB values of
319 // all the colors in the palette.
320 // the value can be from -255 to 255.
321 //
322 // <int> preserveContrast - whether preserve the constrast or not
323 //
adjust_brightness(int changeValue)324 void Vga::adjust_brightness(int changeValue)
325 {
326 //---- find out the maximum rgb value can change without affecting the contrast ---//
327
328 int i;
329 int newRed, newGreen, newBlue;
330 SDL_Color palBuf[VGA_PALETTE_SIZE];
331
332 //------------ change palette now -------------//
333
334 for( i=0 ; i<VGA_PALETTE_SIZE ; i++ )
335 {
336 newRed = (int)game_pal[i].r + changeValue;
337 newGreen = (int)game_pal[i].g + changeValue;
338 newBlue = (int)game_pal[i].b + changeValue;
339
340 palBuf[i].r = MIN(255, MAX(newRed,0));
341 palBuf[i].g = MIN(255, MAX(newGreen,0));
342 palBuf[i].b = MIN(255, MAX(newBlue,0));
343 }
344
345 //------------ set palette ------------//
346
347 vga_front.temp_unlock();
348
349 vga_front.activate_pal(palBuf);
350
351 vga_front.temp_restore_lock();
352 }
353 //--------- End of function Vga::adjust_brightness ----------//
354
355
356 //-------- Begin of function Vga::handle_messages --------//
handle_messages()357 void Vga::handle_messages()
358 {
359 SDL_Event event;
360
361 while( SDL_PollEvent(&event) )
362 {
363 switch (event.type)
364 {
365 case SDL_QUIT:
366 sys.signal_exit_flag = 1;
367 break;
368 case SDL_MULTIGESTURE:
369 if (event.mgesture.numFingers == 2) {
370 mouse.process_scroll(event.mgesture.x, event.mgesture.y);
371 }
372 break;
373 case SDL_FINGERDOWN:
374 mouse.end_scroll();
375 break;
376 case SDL_MOUSEWHEEL:
377 mouse.process_scroll(event.wheel.x, event.wheel.y * -1);
378 break;
379 case SDL_WINDOWEVENT:
380 switch (event.window.event)
381 {
382 case SDL_WINDOWEVENT_EXPOSED:
383 case SDL_WINDOWEVENT_RESIZED:
384 sys.need_redraw_flag = 1;
385 update_mouse_pos();
386 boundary_set = 0;
387 break;
388
389 //case SDL_WINDOWEVENT_ENTER: // Do not respond to mouse focus
390 case SDL_WINDOWEVENT_FOCUS_GAINED:
391 case SDL_WINDOWEVENT_RESTORED:
392 sys.need_redraw_flag = 1;
393 if( !sys.is_mp_game && config_adv.vga_pause_on_focus_loss )
394 sys.unpause();
395
396 // update ctrl/shift/alt key state
397 mouse.update_skey_state();
398 SDL_ShowCursor(SDL_DISABLE);
399 break;
400
401 //case SDL_WINDOWEVENT_LEAVE: // Do not respond to mouse focus
402 case SDL_WINDOWEVENT_FOCUS_LOST:
403 case SDL_WINDOWEVENT_MINIMIZED:
404 if( !sys.is_mp_game && config_adv.vga_pause_on_focus_loss )
405 sys.pause();
406 // turn the system cursor back on to get around a fullscreen
407 // mouse grabbed problem on windows
408 SDL_ShowCursor(SDL_ENABLE);
409 break;
410 }
411 break;
412
413 case SDL_MOUSEMOTION:
414 if( mouse_mode == MOUSE_INPUT_ABS )
415 {
416 int logical_x, logical_y;
417 if( config_adv.vga_keep_aspect_ratio )
418 {
419 logical_x = event.motion.x;
420 logical_y = event.motion.y;
421 }
422 else
423 {
424 float xscale, yscale;
425 get_window_scale(&xscale, &yscale);
426 logical_x = ((float)event.motion.x / xscale);
427 logical_y = ((float)event.motion.y / yscale);
428 }
429 if( win_grab_user_mode || win_grab_forced )
430 {
431 int real_x, real_y, do_warp;
432 SDL_GetMouseState(&real_x, &real_y);
433 do_warp = 0;
434 if( !boundary_set )
435 update_boundary();
436 if( real_x < bound_x1 )
437 {
438 do_warp = 1;
439 real_x = bound_x1;
440 logical_x = mouse.bound_x1;
441 }
442 else if( real_x >= bound_x2 )
443 {
444 do_warp = 1;
445 real_x = bound_x2;
446 logical_x = mouse.bound_x2;
447 }
448 if( real_y < bound_y1 )
449 {
450 do_warp = 1;
451 real_y = bound_y1;
452 logical_y = mouse.bound_y1;
453 }
454 else if( real_y >= bound_y2 )
455 {
456 do_warp = 1;
457 real_y = bound_y2;
458 logical_y = mouse.bound_y2;
459 }
460 if( do_warp )
461 {
462 SDL_WarpMouseInWindow(window, real_x, real_y);
463 }
464 }
465 mouse.process_mouse_motion(logical_x, logical_y);
466 }
467 else
468 {
469 mouse.process_mouse_motion(event.motion.xrel, event.motion.yrel);
470 }
471 break;
472 case SDL_MOUSEBUTTONDOWN:
473 if( event.button.button == SDL_BUTTON_LEFT )
474 {
475 mouse.add_event(LEFT_BUTTON);
476 }
477 else if( event.button.button == SDL_BUTTON_RIGHT )
478 {
479 mouse.add_event(RIGHT_BUTTON);
480 }
481 set_window_grab(WINGRAB_FORCE);
482 break;
483 case SDL_MOUSEBUTTONUP:
484 if( event.button.button == SDL_BUTTON_LEFT )
485 {
486 mouse.add_event(LEFT_BUTTON_RELEASE);
487 mouse.reset_boundary();
488 }
489 else if( event.button.button == SDL_BUTTON_RIGHT )
490 {
491 mouse.add_event(RIGHT_BUTTON_RELEASE);
492 }
493 set_window_grab(WINGRAB_RESTORE);
494 break;
495 case SDL_KEYDOWN:
496 {
497 int bypass = 0;
498 int mod = event.key.keysym.mod &
499 (KMOD_CTRL|KMOD_SHIFT|KMOD_ALT);
500 if( mod == KMOD_LALT || mod == KMOD_RALT )
501 {
502 if( event.key.keysym.sym == SDLK_RETURN )
503 {
504 bypass = 1;
505 sys.toggle_full_screen_flag = 1;
506 }
507 else if( event.key.keysym.sym == SDLK_F4 )
508 {
509 bypass = 1;
510 sys.signal_exit_flag = 1;
511 }
512 else if( event.key.keysym.sym == SDLK_TAB )
513 {
514 bypass = 1;
515 SDL_Window *window = SDL_GetWindowFromID(event.key.windowID);
516 SDL_MinimizeWindow(window);
517 }
518 }
519 else if( mod == KMOD_LCTRL || mod == KMOD_RCTRL )
520 {
521 if( event.key.keysym.sym == SDLK_g )
522 {
523 bypass = 1;
524 set_window_grab(WINGRAB_TOGGLE);
525 }
526 else if( event.key.keysym.sym == SDLK_m )
527 {
528 bypass = 1;
529 if( mouse_mode == MOUSE_INPUT_ABS && !is_input_grabbed() )
530 set_mouse_mode( MOUSE_INPUT_REL_WARP );
531 else if( mouse_mode != MOUSE_INPUT_ABS )
532 set_mouse_mode( MOUSE_INPUT_ABS );
533 }
534 }
535 if( SDL_IsTextInputActive() && event.key.keysym.sym >= SDLK_SPACE && event.key.keysym.sym <= SDLK_z )
536 bypass = 1;
537 if( !bypass )
538 {
539 mouse.update_skey_state();
540 mouse.add_key_event(event.key.keysym.sym, misc.get_time());
541 }
542 break;
543 }
544 case SDL_KEYUP:
545 mouse.update_skey_state();
546 break;
547 case SDL_TEXTINPUT:
548 mouse.add_typing_event(event.text.text, misc.get_time());
549 break;
550 case SDL_TEXTEDITING:
551 case SDL_JOYAXISMOTION:
552 case SDL_JOYBALLMOTION:
553 case SDL_JOYHATMOTION:
554 case SDL_JOYBUTTONDOWN:
555 case SDL_JOYBUTTONUP:
556 default:
557 MSG("unhandled event %d\n", event.type);
558 break;
559 }
560 }
561 }
562 //-------- End of function Vga::handle_messages --------//
563
564 //-------- Begin of function Vga::flag_redraw --------//
flag_redraw()565 void Vga::flag_redraw()
566 {
567 }
568 //-------- End of function Vga::flag_redraw ----------//
569
570
571 //-------- Begin of function Vga::is_full_screen --------//
572 //
is_full_screen()573 int Vga::is_full_screen()
574 {
575 return ((SDL_GetWindowFlags(window) & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_FULLSCREEN_DESKTOP)) != 0);
576 }
577 //-------- End of function Vga::is_full_screen ----------//
578
579
580 //-------- Begin of function Vga::is_input_grabbed --------//
581 //
is_input_grabbed()582 int Vga::is_input_grabbed()
583 {
584 return ((SDL_GetWindowFlags(window) & SDL_WINDOW_INPUT_GRABBED) != 0);
585 }
586 //-------- End of function Vga::is_input_grabbed ----------//
587
588
589 //-------- Begin of function Vga::update_boundary --------//
590 // Uses logical boundary coordinates and scales them to the actual boundary in
591 // the scaled window.
update_boundary()592 void Vga::update_boundary()
593 {
594 float xscale, yscale;
595 SDL_Rect rect;
596 get_window_scale(&xscale, &yscale);
597 SDL_RenderGetViewport(renderer, &rect);
598 bound_x1 = ((float)(mouse.bound_x1 + rect.x) * xscale);
599 bound_x2 = ((float)(mouse.bound_x2 + rect.x) * xscale);
600 bound_y1 = ((float)(mouse.bound_y1 + rect.y) * yscale);
601 bound_y2 = ((float)(mouse.bound_y2 + rect.y) * yscale);
602 boundary_set = 1;
603 }
604 //-------- End of function Vga::update_boundary --------//
605
606
607 //-------- Begin of function Vga::update_mouse_pos ----------//
608 // Updates logical mouse position according to actual mouse state.
update_mouse_pos()609 void Vga::update_mouse_pos()
610 {
611 float xscale, yscale;
612 SDL_Rect rect;
613 int logical_x, logical_y, win_x, win_y, mouse_x, mouse_y;
614
615 if( !window )
616 return;
617
618 get_window_scale(&xscale, &yscale);
619 SDL_RenderGetViewport(renderer, &rect);
620 SDL_GetWindowPosition(window, &win_x, &win_y);
621 SDL_GetGlobalMouseState(&mouse_x, &mouse_y);
622 logical_x = ((float)(mouse_x - win_x) / xscale - rect.x);
623 logical_y = ((float)(mouse_y - win_y) / yscale - rect.y);
624
625 mouse.process_mouse_motion(logical_x, logical_y);
626 }
627 //---------- End of function Vga::update_mouse_pos ----------//
628
629
630 //-------- Begin of function Vga::set_full_screen_mode --------//
631 //
632 // mode -1: toggle
633 // mode 0: windowed
634 // mode 1: full screen without display mode change (stretched to desktop)
set_full_screen_mode(int mode)635 void Vga::set_full_screen_mode(int mode)
636 {
637 int result, mouse_x, mouse_y;
638 uint32_t flags = config_adv.vga_full_screen_desktop ?
639 SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN;
640
641 switch (mode)
642 {
643 case -1:
644 if( is_full_screen() )
645 flags = 0;
646 break;
647 case 0:
648 flags = 0;
649 break;
650 case 1:
651 break;
652 default:
653 err_now("invalid mode");
654 }
655
656 // Save the mouse position to restore after mode change. If we don't do
657 // this, then the old position gets recalculated, with the mode change
658 // affecting the location, causing a jump.
659 SDL_GetGlobalMouseState(&mouse_x, &mouse_y);
660
661 result = SDL_SetWindowFullscreen(window, flags);
662 if (result < 0) {
663 ERR("Could not toggle fullscreen: %s\n", SDL_GetError());
664 return;
665 }
666
667 sys.need_redraw_flag = 1;
668 boundary_set = 0;
669 if( flags ) // went full screen
670 set_window_grab(WINGRAB_ON);
671 else
672 set_window_grab(WINGRAB_OFF);
673
674 SDL_WarpMouseGlobal(mouse_x, mouse_y);
675 }
676 //-------- End of function Vga::set_full_screen_mode ----------//
677
678
679 //-------- Begin of function Vga::set_mouse_mode --------//
set_mouse_mode(MouseInputMode mode)680 void Vga::set_mouse_mode(MouseInputMode mode)
681 {
682 switch( mode )
683 {
684 case MOUSE_INPUT_REL:
685 if( mouse_mode == MOUSE_INPUT_ABS )
686 SDL_SetRelativeMouseMode(SDL_TRUE);
687 SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "0");
688 mouse_mode = MOUSE_INPUT_REL;
689 break;
690 case MOUSE_INPUT_REL_WARP:
691 if( mouse_mode == MOUSE_INPUT_ABS )
692 SDL_SetRelativeMouseMode(SDL_TRUE);
693 SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1");
694 mouse_mode = MOUSE_INPUT_REL_WARP;
695 break;
696 default:
697 // absolute mode
698 if( mouse_mode != MOUSE_INPUT_ABS )
699 SDL_SetRelativeMouseMode(SDL_FALSE);
700 mouse_mode = MOUSE_INPUT_ABS;
701 }
702 }
703 //-------- End of function Vga::set_mouse_mode --------//
704
705
706 //-------- Begin of function Vga::set_window_grab --------//
707 //
708 // WINGRAB_OFF = Turn window grab off, except when forced on
709 // WINGRAB_ON = Turn window grab on
710 // WINGRAB_TOGGLE = Toggle window grab, used for the grab key
711 // WINGRAB_FORCE = Force grab on, even if user has it off
712 // WINGRAB_RESTORE = Disable forcing, and user's option
set_window_grab(WinGrab mode)713 void Vga::set_window_grab(WinGrab mode)
714 {
715 switch( mode )
716 {
717 case WINGRAB_OFF:
718 if( win_grab_user_mode )
719 {
720 win_grab_user_mode = 0;
721 if( !win_grab_forced )
722 {
723 SDL_SetWindowGrab(window, SDL_FALSE);
724 if( mouse_mode != MOUSE_INPUT_ABS )
725 set_mouse_mode(MOUSE_INPUT_ABS);
726 }
727 }
728 break;
729 case WINGRAB_ON:
730 if( !win_grab_user_mode )
731 {
732 win_grab_user_mode = 1;
733 if( !win_grab_forced )
734 {
735 SDL_SetWindowGrab(window, SDL_TRUE);
736 }
737 }
738 break;
739 case WINGRAB_TOGGLE:
740 if( win_grab_user_mode )
741 {
742 win_grab_user_mode = 0;
743 if( !win_grab_forced )
744 {
745 SDL_SetWindowGrab(window, SDL_FALSE);
746 if( mouse_mode != MOUSE_INPUT_ABS )
747 set_mouse_mode(MOUSE_INPUT_ABS);
748 }
749 }
750 else
751 {
752 win_grab_user_mode = 1;
753 if( !win_grab_forced )
754 {
755 SDL_SetWindowGrab(window, SDL_TRUE);
756 }
757 }
758 break;
759 case WINGRAB_FORCE:
760 if( !win_grab_forced )
761 {
762 win_grab_forced = 1;
763 if( !win_grab_user_mode )
764 {
765 SDL_SetWindowGrab(window, SDL_TRUE);
766 }
767 }
768 break;
769 case WINGRAB_RESTORE:
770 if( win_grab_forced )
771 {
772 win_grab_forced = 0;
773 if( !win_grab_user_mode )
774 {
775 SDL_SetWindowGrab(window, SDL_FALSE);
776 if( mouse_mode != MOUSE_INPUT_ABS )
777 set_mouse_mode(MOUSE_INPUT_ABS);
778 }
779 }
780 break;
781 default:
782 err_now("invalid mode");
783 }
784 }
785 //-------- End of function Vga::set_window_grab ----------//
786
787
788 //-------- Beginning of function Vga::flip ----------//
flip()789 void Vga::flip()
790 {
791 static Uint32 ticks = 0;
792 Uint32 cur_ticks;
793
794 if( !is_inited() )
795 return;
796
797 cur_ticks = SDL_GetTicks();
798 if (cur_ticks > ticks + 17 || cur_ticks < ticks) {
799 ticks = cur_ticks;
800 SDL_BlitSurface(vga_front.surface, NULL, target, NULL);
801 SDL_UpdateTexture(texture, NULL, target->pixels, target->pitch);
802 SDL_RenderClear(renderer);
803 SDL_RenderCopy(renderer, texture, NULL, NULL);
804 SDL_RenderPresent(renderer);
805 }
806 }
807 //-------- End of function Vga::flip ----------//
808
809
810 //-------- Beginning of function Vga::save_status_report ----------//
save_status_report()811 void Vga::save_status_report()
812 {
813 FilePath path(sys.dir_config);
814 FILE *file;
815 int num, i;
816 const char *s;
817 SDL_version ver;
818
819 path += "sdl.txt";
820 if( path.error_flag )
821 return;
822
823 file = fopen(path, "w");
824 if( !file )
825 return;
826
827 fprintf(file, "=== Seven Kingdoms " SKVERSION " ===\n");
828 s = SDL_GetPlatform();
829 fprintf(file, "Platform: %s\n", s);
830 if( SDL_BYTEORDER == SDL_BIG_ENDIAN )
831 fprintf(file, "Big endian\n");
832 else
833 fprintf(file, "Little endian\n");
834 #ifndef HAVE_KNOWN_BUILD
835 fprintf(file, "Binary built using unsupported configuration\n");
836 #endif
837
838 s = SDL_GetCurrentVideoDriver();
839 fprintf(file, "Current SDL video driver: %s\n", s);
840 SDL_GetVersion(&ver);
841 fprintf(file, "SDL version: %d.%d.%d\n", ver.major, ver.minor, ver.patch);
842 SDL_VERSION(&ver);
843 fprintf(file, "Compiled SDL version: %d.%d.%d\n\n", ver.major, ver.minor, ver.patch);
844
845 fprintf(file, "-- Video drivers --\n");
846 num = SDL_GetNumVideoDrivers();
847 for( i=0; i<num; i++ )
848 {
849 s = SDL_GetVideoDriver(i);
850 fprintf(file, "%d: %s\n", i, s);
851 }
852 fprintf(file, "\n");
853
854 if( window )
855 {
856 int x, y, w, h = 0;
857 SDL_RendererInfo info;
858 SDL_Renderer *r = SDL_GetRenderer(window);
859
860 fprintf(file, "-- Current window --\n");
861 fprintf(file, "Active on display: %d\n", SDL_GetWindowDisplayIndex(window));
862 SDL_GetWindowPosition(window, &x, &y);
863 SDL_GetWindowSize(window, &w, &h);
864 fprintf(file, "Geometry: %dx%d @ (%d, %d)\n", w, h, x, y);
865 fprintf(file, "Pixel format: %s\n", SDL_GetPixelFormatName(SDL_GetWindowPixelFormat(window)));
866 fprintf(file, "Full screen: %s\n", is_full_screen() ? "yes" : "no");
867 fprintf(file, "Input grabbed: %s\n\n", SDL_GetWindowGrab(window) ? "yes" : "no");
868 if( r )
869 {
870 SDL_RendererInfo info;
871 float xscale, yscale;
872 SDL_Rect rect;
873
874 SDL_GetRendererInfo(r, &info);
875 get_window_scale(&xscale, &yscale);
876 SDL_RenderGetViewport(renderer, &rect);
877 SDL_RenderGetLogicalSize(renderer, &w, &h);
878
879 fprintf(file, "-- Current renderer: %s --\n", info.name);
880 fprintf(file, "Viewport: x=%d,y=%d,w=%d,h=%d\n", rect.x, rect.y, rect.w, rect.h);
881 fprintf(file, "Scale: xscale=%f,yscale=%f\n", xscale, yscale);
882 fprintf(file, "Logical size: w=%d, h=%d\n", w, h);
883 fprintf(file, "Capabilities: %s\n", info.flags & SDL_RENDERER_ACCELERATED ? "hardware accelerated" : "software fallback");
884 fprintf(file, "V-sync: %s\n", info.flags & SDL_RENDERER_PRESENTVSYNC ? "on" : "off");
885 fprintf(file, "Rendering to texture supported: %s\n", info.flags & SDL_RENDERER_TARGETTEXTURE ? "yes" : "no");
886 if( info.max_texture_width || info.max_texture_height )
887 fprintf(file, "Maximum texture size: %dx%d\n", info.max_texture_width, info.max_texture_height);
888 fprintf(file, "Pixel formats:\n");
889 for( unsigned i=0; i<info.num_texture_formats; i++ )
890 fprintf(file, "\t%s\n", SDL_GetPixelFormatName(info.texture_formats[i]));
891 }
892 }
893 fprintf(file, "\n");
894
895 if( texture )
896 {
897 uint32_t format = 0;
898 int w, h = 0;
899 SDL_QueryTexture(texture, &format, NULL, &w, &h);
900 fprintf(file, "-- Streaming texture --\n");
901 fprintf(file, "Size: %dx%d\n", w, h);
902 fprintf(file, "Pixel format: %s\n\n", SDL_GetPixelFormatName(format));
903 }
904
905 num = SDL_GetNumVideoDisplays();
906 for( i=0; i<num; i++ )
907 {
908 SDL_Rect rect;
909 SDL_DisplayMode mode;
910 float ddpi, hdpi, vdpi;
911 fprintf(file, "-- Display %d --\n", i);
912 if( !SDL_GetCurrentDisplayMode(i, &mode) )
913 fprintf(file, "Mode: %dx%dx%ubpp %dHz format=%s driver=%p\n", mode.w, mode.h, SDL_BITSPERPIXEL(mode.format), mode.refresh_rate, SDL_GetPixelFormatName(mode.format), mode.driverdata);
914 if( !SDL_GetDisplayDPI(i, &ddpi, &hdpi, &vdpi) )
915 fprintf(file, "DPI: diag=%f horiz=%f vert=%f\n", ddpi, hdpi, vdpi);
916 if( !SDL_GetDisplayBounds(i, &rect) )
917 fprintf(file, "Bounds: x=%d y=%d w=%d h=%d\n", rect.x, rect.y, rect.w, rect.h);
918 #if SDL_VERSION_ATLEAST(2, 0, 5)
919 if( !SDL_GetDisplayUsableBounds(i, &rect) ) // Note: requires SDL 2.0.5+
920 fprintf(file, "Usable bounds: x=%d y=%d w=%d h=%d\n", rect.x, rect.y, rect.w, rect.h);
921 #endif
922 fprintf(file, "\n");
923 }
924
925 num = SDL_GetNumRenderDrivers();
926 for( i=0; i<num; i++ )
927 {
928 SDL_RendererInfo info;
929 SDL_GetRenderDriverInfo(i, &info);
930 fprintf(file, "-- Renderer %s (%d) --\n", info.name, i);
931 fprintf(file, "Capabilities: %s\n", info.flags & SDL_RENDERER_ACCELERATED ? "hardware accelerated" : "software fallback");
932 fprintf(file, "V-sync capable: %s\n", info.flags & SDL_RENDERER_PRESENTVSYNC ? "on" : "off");
933 fprintf(file, "Rendering to texture supported: %s\n", info.flags & SDL_RENDERER_TARGETTEXTURE ? "yes" : "no");
934 if( info.max_texture_width || info.max_texture_height )
935 fprintf(file, "Maximum texture size: %dx%d\n", info.max_texture_width, info.max_texture_height);
936 fprintf(file, "Pixel formats:\n");
937 for( unsigned j=0; j<info.num_texture_formats; j++ )
938 fprintf(file, "\t%s\n", SDL_GetPixelFormatName(info.texture_formats[j]));
939 fprintf(file, "\n");
940 }
941
942 fclose(file);
943 return;
944 }
945 //-------- End of function Vga::save_status_report ----------//
946
947
948 //-------- Beginning of function Vga::get_window_scale ----------//
get_window_scale(float * xscale,float * yscale)949 void Vga::get_window_scale(float *xscale, float *yscale)
950 {
951 if( config_adv.vga_keep_aspect_ratio )
952 {
953 SDL_RenderGetScale(renderer, xscale, yscale);
954 }
955 else
956 {
957 int w, h;
958 SDL_GetWindowSize(window, &w, &h);
959 *xscale = (float)w / (float)VGA_WIDTH;
960 *yscale = (float)h / (float)VGA_HEIGHT;
961 }
962 }
963 //-------- End of function Vga::get_window_scale ----------//
964
965
966 #ifdef USE_WINDOWS
967
968 #include <windows.h>
969
970 typedef enum PROCESS_DPI_AWARENESS {
971 PROCESS_DPI_UNAWARE = 0,
972 PROCESS_SYSTEM_DPI_AWARE = 1,
973 PROCESS_PER_MONITOR_DPI_AWARE = 2
974 } PROCESS_DPI_AWARENESS;
975
976 BOOL(WINAPI *pSetProcessDPIAware)(void); // Vista and later
977 HRESULT(WINAPI *pSetProcessDpiAwareness)(PROCESS_DPI_AWARENESS dpiAwareness); // Windows 8.1 and later
978
979 // Based on the example provided by Eric Wasylishen
980 // https://discourse.libsdl.org/t/sdl-getdesktopdisplaymode-resolution-reported-in-windows-10-when-using-app-scaling/22389
init_dpi()981 static void init_dpi()
982 {
983 void* userDLL;
984 void* shcoreDLL;
985
986 shcoreDLL = SDL_LoadObject("SHCORE.DLL");
987 if (shcoreDLL)
988 {
989 pSetProcessDpiAwareness = (HRESULT(WINAPI *)(PROCESS_DPI_AWARENESS)) SDL_LoadFunction(shcoreDLL, "SetProcessDpiAwareness");
990 }
991
992 if (pSetProcessDpiAwareness)
993 {
994 /* Try Windows 8.1+ version */
995 HRESULT result = pSetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
996 return;
997 }
998
999 userDLL = SDL_LoadObject("USER32.DLL");
1000 if (userDLL)
1001 {
1002 pSetProcessDPIAware = (BOOL(WINAPI *)(void)) SDL_LoadFunction(userDLL, "SetProcessDPIAware");
1003 }
1004
1005 if (pSetProcessDPIAware)
1006 {
1007 /* Try Vista - Windows 8 version.
1008 This has a constant scale factor for all monitors.
1009 */
1010 BOOL success = pSetProcessDPIAware();
1011 }
1012 }
1013
1014 #endif
1015
init_window_flags()1016 static int init_window_flags()
1017 {
1018 int flags = 0;
1019 if( config_adv.vga_full_screen )
1020 flags |= config_adv.vga_full_screen_desktop ?
1021 SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN;
1022 if( config_adv.vga_allow_highdpi )
1023 flags |= SDL_WINDOW_ALLOW_HIGHDPI;
1024 return flags;
1025 }
1026
init_window_size()1027 static void init_window_size()
1028 {
1029 if( !config_adv.vga_full_screen_desktop )
1030 {
1031 // must match game's native resolution
1032 config_adv.vga_window_width = 800;
1033 config_adv.vga_window_height = 600;
1034 return;
1035 }
1036
1037 if( config_adv.vga_window_width && config_adv.vga_window_height )
1038 return;
1039
1040 #if SDL_VERSION_ATLEAST(2, 0, 5)
1041 int display_idx;
1042 SDL_Window *size_win = SDL_CreateWindow(WIN_TITLE, 0, 0, 1, 1, 0);
1043 if( !size_win )
1044 goto unknown_display;
1045
1046 display_idx = SDL_GetWindowDisplayIndex(size_win);
1047 SDL_DestroyWindow(size_win);
1048 if( display_idx < 0 )
1049 goto unknown_display;
1050
1051 SDL_Rect rect;
1052 if( SDL_GetDisplayUsableBounds(display_idx, &rect)<0 )
1053 goto unknown_display;
1054
1055 if( rect.w >= 1024 && rect.h >= 768 )
1056 {
1057 config_adv.vga_window_width = 1024;
1058 config_adv.vga_window_height = 768;
1059 return;
1060 }
1061
1062 if( rect.w >= 800 && rect.h >= 600 )
1063 {
1064 config_adv.vga_window_width = 800;
1065 config_adv.vga_window_height = 600;
1066 return;
1067 }
1068
1069 config_adv.vga_window_width = 640;
1070 config_adv.vga_window_height = 480;
1071 return;
1072 #endif
1073
1074 unknown_display:
1075 config_adv.vga_window_width = 800;
1076 config_adv.vga_window_height = 600;
1077 return;
1078 }
1079