1 /* Emacs style mode select   -*- C++ -*-
2  *-----------------------------------------------------------------------------
3  *
4  *
5  *  PrBoom: a Doom port merged with LxDoom and LSDLDoom
6  *  based on BOOM, a modified and improved DOOM engine
7  *  Copyright (C) 1999 by
8  *  id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9  *  Copyright (C) 1999-2006 by
10  *  Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11  *  Copyright 2005, 2006 by
12  *  Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13  *
14  *  This program is free software; you can redistribute it and/or
15  *  modify it under the terms of the GNU General Public License
16  *  as published by the Free Software Foundation; either version 2
17  *  of the License, or (at your option) any later version.
18  *
19  *  This program is distributed in the hope that it will be useful,
20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *  GNU General Public License for more details.
23  *
24  *  You should have received a copy of the GNU General Public License
25  *  along with this program; if not, write to the Free Software
26  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27  *  02111-1307, USA.
28  *
29  * DESCRIPTION:
30  *  DOOM graphics stuff for SDL
31  *
32  *-----------------------------------------------------------------------------
33  */
34 
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38 
39 #ifdef _WIN32
40 #define WIN32_LEAN_AND_MEAN
41 #include <windows.h>
42 #endif // _WIN32
43 
44 #include <stdlib.h>
45 
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
49 
50 #include "SDL.h"
51 //e6y
52 #ifdef _WIN32
53 #include <SDL_syswm.h>
54 #endif
55 
56 #include "m_argv.h"
57 #include "doomstat.h"
58 #include "doomdef.h"
59 #include "doomtype.h"
60 #include "v_video.h"
61 #include "r_draw.h"
62 #include "r_things.h"
63 #include "r_plane.h"
64 #include "r_main.h"
65 #include "f_wipe.h"
66 #include "d_main.h"
67 #include "d_event.h"
68 #include "i_joy.h"
69 #include "i_video.h"
70 #include "i_smp.h"
71 #include "z_zone.h"
72 #include "s_sound.h"
73 #include "sounds.h"
74 #include "w_wad.h"
75 #include "st_stuff.h"
76 #include "am_map.h"
77 #include "g_game.h"
78 #include "lprintf.h"
79 
80 #ifdef GL_DOOM
81 #include "gl_struct.h"
82 #endif
83 
84 #include "i_simd.h"
85 #include "r_screenmultiply.h"
86 #include "e6y.h"//e6y
87 
88 //e6y: new mouse code
89 static SDL_Cursor* cursors[2] = {NULL, NULL};
90 
91 dboolean window_focused;
92 
93 // Window resize state.
94 static void ApplyWindowResize(SDL_Event *resize_event);
95 
96 const char *sdl_videodriver;
97 const char *sdl_video_window_pos;
98 
99 static void ActivateMouse(void);
100 static void DeactivateMouse(void);
101 //static int AccelerateMouse(int val);
102 static void CenterMouse(void);
103 static void I_ReadMouse(void);
104 static dboolean MouseShouldBeGrabbed();
105 static void UpdateFocus(void);
106 
107 int gl_colorbuffer_bits=16;
108 int gl_depthbuffer_bits=16;
109 
110 extern void M_QuitDOOM(int choice);
111 #ifdef DISABLE_DOUBLEBUFFER
112 int use_doublebuffer = 0;
113 #else
114 int use_doublebuffer = 1; // Included not to break m_misc, but not relevant to SDL
115 #endif
116 int use_fullscreen;
117 int desired_fullscreen;
118 SDL_Surface *screen;
119 #ifdef GL_DOOM
120 vid_8ingl_t vid_8ingl;
121 int use_gl_surface;
122 #endif
123 
124 ////////////////////////////////////////////////////////////////////////////
125 // Input code
126 int             leds_always_off = 0; // Expected by m_misc, not relevant
127 
128 // Mouse handling
129 extern int     usemouse;        // config file var
130 static dboolean mouse_enabled; // usemouse, but can be overriden by -nomouse
131 
132 int I_GetModeFromString(const char *modestr);
133 
134 /////////////////////////////////////////////////////////////////////////////////
135 // Keyboard handling
136 
137 //
138 //  Translates the key currently in key
139 //
140 
I_TranslateKey(SDL_keysym * key)141 static int I_TranslateKey(SDL_keysym* key)
142 {
143   int rc = 0;
144 
145   switch (key->sym) {
146   case SDLK_LEFT: rc = KEYD_LEFTARROW;  break;
147   case SDLK_RIGHT:  rc = KEYD_RIGHTARROW; break;
148   case SDLK_DOWN: rc = KEYD_DOWNARROW;  break;
149   case SDLK_UP:   rc = KEYD_UPARROW;  break;
150   case SDLK_ESCAPE: rc = KEYD_ESCAPE; break;
151   case SDLK_RETURN: rc = KEYD_ENTER;  break;
152   case SDLK_TAB:  rc = KEYD_TAB;    break;
153   case SDLK_F1:   rc = KEYD_F1;   break;
154   case SDLK_F2:   rc = KEYD_F2;   break;
155   case SDLK_F3:   rc = KEYD_F3;   break;
156   case SDLK_F4:   rc = KEYD_F4;   break;
157   case SDLK_F5:   rc = KEYD_F5;   break;
158   case SDLK_F6:   rc = KEYD_F6;   break;
159   case SDLK_F7:   rc = KEYD_F7;   break;
160   case SDLK_F8:   rc = KEYD_F8;   break;
161   case SDLK_F9:   rc = KEYD_F9;   break;
162   case SDLK_F10:  rc = KEYD_F10;    break;
163   case SDLK_F11:  rc = KEYD_F11;    break;
164   case SDLK_F12:  rc = KEYD_F12;    break;
165   case SDLK_BACKSPACE:  rc = KEYD_BACKSPACE;  break;
166   case SDLK_DELETE: rc = KEYD_DEL;  break;
167   case SDLK_INSERT: rc = KEYD_INSERT; break;
168   case SDLK_PAGEUP: rc = KEYD_PAGEUP; break;
169   case SDLK_PAGEDOWN: rc = KEYD_PAGEDOWN; break;
170   case SDLK_HOME: rc = KEYD_HOME; break;
171   case SDLK_END:  rc = KEYD_END;  break;
172   case SDLK_PAUSE:  rc = KEYD_PAUSE;  break;
173   case SDLK_EQUALS: rc = KEYD_EQUALS; break;
174   case SDLK_MINUS:  rc = KEYD_MINUS;  break;
175   case SDLK_KP0:  rc = KEYD_KEYPAD0;  break;
176   case SDLK_KP1:  rc = KEYD_KEYPAD1;  break;
177   case SDLK_KP2:  rc = KEYD_KEYPAD2;  break;
178   case SDLK_KP3:  rc = KEYD_KEYPAD3;  break;
179   case SDLK_KP4:  rc = KEYD_KEYPAD4;  break;
180   case SDLK_KP5:  rc = KEYD_KEYPAD5;  break;
181   case SDLK_KP6:  rc = KEYD_KEYPAD6;  break;
182   case SDLK_KP7:  rc = KEYD_KEYPAD7;  break;
183   case SDLK_KP8:  rc = KEYD_KEYPAD8;  break;
184   case SDLK_KP9:  rc = KEYD_KEYPAD9;  break;
185   case SDLK_KP_PLUS:  rc = KEYD_KEYPADPLUS; break;
186   case SDLK_KP_MINUS: rc = KEYD_KEYPADMINUS;  break;
187   case SDLK_KP_DIVIDE:  rc = KEYD_KEYPADDIVIDE; break;
188   case SDLK_KP_MULTIPLY: rc = KEYD_KEYPADMULTIPLY; break;
189   case SDLK_KP_ENTER: rc = KEYD_KEYPADENTER;  break;
190   case SDLK_KP_PERIOD:  rc = KEYD_KEYPADPERIOD; break;
191   case SDLK_LSHIFT:
192   case SDLK_RSHIFT: rc = KEYD_RSHIFT; break;
193   case SDLK_LCTRL:
194   case SDLK_RCTRL:  rc = KEYD_RCTRL;  break;
195   case SDLK_LALT:
196   case SDLK_LMETA:
197   case SDLK_RALT:
198   case SDLK_RMETA:  rc = KEYD_RALT;   break;
199   case SDLK_CAPSLOCK: rc = KEYD_CAPSLOCK; break;
200   default:    rc = key->sym;    break;
201   }
202 
203   return rc;
204 
205 }
206 
207 /////////////////////////////////////////////////////////////////////////////////
208 // Main input code
209 
210 /* cph - pulled out common button code logic */
211 //e6y static
I_SDLtoDoomMouseState(Uint8 buttonstate)212 int I_SDLtoDoomMouseState(Uint8 buttonstate)
213 {
214   return 0
215       | (buttonstate & SDL_BUTTON(1) ? 1 : 0)
216       | (buttonstate & SDL_BUTTON(2) ? 2 : 0)
217       | (buttonstate & SDL_BUTTON(3) ? 4 : 0)
218 #if SDL_VERSION_ATLEAST(1, 2, 14)
219       | (buttonstate & SDL_BUTTON(6) ? 8 : 0)
220       | (buttonstate & SDL_BUTTON(7) ? 16 : 0)
221 #endif
222       ;
223 }
224 
I_GetEvent(void)225 static void I_GetEvent(void)
226 {
227   event_t event;
228 
229   SDL_Event SDLEvent;
230   SDL_Event *Event = &SDLEvent;
231 
232   static int mwheeluptic = 0, mwheeldowntic = 0;
233 
234 while (SDL_PollEvent(Event))
235 {
236   switch (Event->type) {
237   case SDL_KEYDOWN:
238 #ifdef MACOSX
239     if (Event->key.keysym.mod & KMOD_META)
240     {
241       // Switch windowed<->fullscreen if pressed <Command-F>
242       if (Event->key.keysym.sym == SDLK_f)
243       {
244         V_ToggleFullscreen();
245         break;
246       }
247     }
248 #else
249     if (Event->key.keysym.mod & KMOD_LALT)
250     {
251       // Prevent executing action on Alt-Tab
252       if (Event->key.keysym.sym == SDLK_TAB)
253       {
254         break;
255       }
256       // Switch windowed<->fullscreen if pressed Alt-Enter
257       else if (Event->key.keysym.sym == SDLK_RETURN)
258       {
259         V_ToggleFullscreen();
260         break;
261       }
262     }
263 #endif
264     event.type = ev_keydown;
265     event.data1 = I_TranslateKey(&Event->key.keysym);
266     D_PostEvent(&event);
267     break;
268 
269   case SDL_KEYUP:
270   {
271     event.type = ev_keyup;
272     event.data1 = I_TranslateKey(&Event->key.keysym);
273     D_PostEvent(&event);
274   }
275   break;
276 
277   case SDL_MOUSEBUTTONDOWN:
278   case SDL_MOUSEBUTTONUP:
279   if (mouse_enabled && window_focused)
280   {
281     event.type = ev_mouse;
282     event.data1 = I_SDLtoDoomMouseState(SDL_GetMouseState(NULL, NULL));
283     event.data2 = event.data3 = 0;
284 
285     if (Event->type == SDL_MOUSEBUTTONDOWN)
286     {
287       switch(Event->button.button)
288       {
289       case SDL_BUTTON_WHEELUP:
290         event.type = ev_keydown;
291         event.data1 = KEYD_MWHEELUP;
292         mwheeluptic = gametic;
293         break;
294       case SDL_BUTTON_WHEELDOWN:
295         event.type = ev_keydown;
296         event.data1 = KEYD_MWHEELDOWN;
297         mwheeldowntic = gametic;
298         break;
299       }
300     }
301 
302     D_PostEvent(&event);
303   }
304   break;
305 
306   //e6y: new mouse code
307   case SDL_ACTIVEEVENT:
308     UpdateFocus();
309     break;
310 
311   case SDL_VIDEORESIZE:
312     ApplyWindowResize(Event);
313     break;
314 
315   case SDL_QUIT:
316     S_StartSound(NULL, sfx_swtchn);
317     M_QuitDOOM(0);
318 
319   default:
320     break;
321   }
322 }
323 
324   if(mwheeluptic && mwheeluptic + 1 < gametic)
325   {
326     event.type = ev_keyup;
327     event.data1 = KEYD_MWHEELUP;
328     D_PostEvent(&event);
329     mwheeluptic = 0;
330   }
331 
332   if(mwheeldowntic && mwheeldowntic + 1 < gametic)
333   {
334     event.type = ev_keyup;
335     event.data1 = KEYD_MWHEELDOWN;
336     D_PostEvent(&event);
337     mwheeldowntic = 0;
338   }
339 }
340 
341 //
342 // I_StartTic
343 //
344 
I_StartTic(void)345 void I_StartTic (void)
346 {
347   I_GetEvent();
348 
349   I_ReadMouse();
350 
351   I_PollJoystick();
352 }
353 
354 //
355 // I_StartFrame
356 //
I_StartFrame(void)357 void I_StartFrame (void)
358 {
359 }
360 
361 //
362 // I_InitInputs
363 //
364 
I_InitInputs(void)365 static void I_InitInputs(void)
366 {
367   static Uint8 empty_cursor_data = 0;
368 
369   int nomouse_parm = M_CheckParm("-nomouse");
370 
371   // check if the user wants to use the mouse
372   mouse_enabled = usemouse && !nomouse_parm;
373 
374   SDL_PumpEvents();
375 
376   // Save the default cursor so it can be recalled later
377   cursors[0] = SDL_GetCursor();
378   // Create an empty cursor
379   cursors[1] = SDL_CreateCursor(&empty_cursor_data, &empty_cursor_data, 8, 1, 0, 0);
380 
381   if (mouse_enabled)
382   {
383     CenterMouse();
384     MouseAccelChanging();
385   }
386 
387   I_InitJoystick();
388 }
389 /////////////////////////////////////////////////////////////////////////////
390 
391 // I_SkipFrame
392 //
393 // Returns true if it thinks we can afford to skip this frame
394 
I_SkipFrame(void)395 inline static dboolean I_SkipFrame(void)
396 {
397   static int frameno;
398 
399   frameno++;
400   switch (gamestate) {
401   case GS_LEVEL:
402     if (!paused)
403       return false;
404   default:
405     // Skip odd frames
406     return (frameno & 1) ? true : false;
407   }
408 }
409 
410 ///////////////////////////////////////////////////////////
411 // Palette stuff.
412 //
I_UploadNewPalette(int pal,int force)413 static void I_UploadNewPalette(int pal, int force)
414 {
415   // This is used to replace the current 256 colour cmap with a new one
416   // Used by 256 colour PseudoColor modes
417 
418   // Array of SDL_Color structs used for setting the 256-colour palette
419   static SDL_Color* colours;
420   static int cachedgamma;
421   static size_t num_pals;
422 
423   if (V_GetMode() == VID_MODEGL)
424     return;
425 
426   if ((colours == NULL) || (cachedgamma != usegamma) || force) {
427     int pplump = W_GetNumForName("PLAYPAL");
428     int gtlump = (W_CheckNumForName)("GAMMATBL",ns_prboom);
429     register const byte * palette = W_CacheLumpNum(pplump);
430     register const byte * const gtable = (const byte *)W_CacheLumpNum(gtlump) + 256*(cachedgamma = usegamma);
431     register int i;
432 
433     num_pals = W_LumpLength(pplump) / (3*256);
434     num_pals *= 256;
435 
436     if (!colours) {
437       // First call - allocate and prepare colour array
438       colours = malloc(sizeof(*colours)*num_pals);
439 #ifdef GL_DOOM
440       vid_8ingl.colours = malloc(sizeof(vid_8ingl.colours[0]) * 4 * num_pals);
441 #endif
442     }
443 
444     // set the colormap entries
445     for (i=0 ; (size_t)i<num_pals ; i++) {
446 #ifdef GL_DOOM
447       if (vid_8ingl.enabled)
448       {
449         if (V_GetMode() == VID_MODE8)
450         {
451           vid_8ingl.colours[i * 4 + 0] = gtable[palette[2]];
452           vid_8ingl.colours[i * 4 + 1] = gtable[palette[1]];
453           vid_8ingl.colours[i * 4 + 2] = gtable[palette[0]];
454           vid_8ingl.colours[i * 4 + 3] = 255;
455         }
456       }
457       else
458 #endif
459       {
460         colours[i].r = gtable[palette[0]];
461         colours[i].g = gtable[palette[1]];
462         colours[i].b = gtable[palette[2]];
463       }
464 
465       palette += 3;
466     }
467 
468     W_UnlockLumpNum(pplump);
469     W_UnlockLumpNum(gtlump);
470     num_pals/=256;
471   }
472 
473 #ifdef RANGECHECK
474   if ((size_t)pal >= num_pals)
475     I_Error("I_UploadNewPalette: Palette number out of range (%d>=%d)",
476       pal, num_pals);
477 #endif
478 
479   // store the colors to the current display
480   // SDL_SetColors(SDL_GetVideoSurface(), colours+256*pal, 0, 256);
481 #ifdef GL_DOOM
482   if (vid_8ingl.enabled)
483   {
484     vid_8ingl.palette = pal;
485   }
486   else
487 #endif
488   {
489     SDL_SetPalette(SDL_GetVideoSurface(),SDL_LOGPAL|SDL_PHYSPAL,colours+256*pal, 0, 256);
490   }
491 }
492 
493 //////////////////////////////////////////////////////////////////////////////
494 // Graphics API
495 
I_ShutdownGraphics(void)496 void I_ShutdownGraphics(void)
497 {
498   SDL_FreeCursor(cursors[1]);
499   DeactivateMouse();
500 }
501 
502 //
503 // I_UpdateNoBlit
504 //
I_UpdateNoBlit(void)505 void I_UpdateNoBlit (void)
506 {
507 }
508 
509 //
510 // I_FinishUpdate
511 //
512 static int newpal = 0;
513 #define NO_PALETTE_CHANGE 1000
514 
I_FinishUpdate(void)515 void I_FinishUpdate (void)
516 {
517   //e6y: new mouse code
518   UpdateGrab();
519 
520   // The screen wipe following pressing the exit switch on a level
521   // is noticably jerkier with I_SkipFrame
522   // if (I_SkipFrame())return;
523 
524 #ifdef MONITOR_VISIBILITY
525   if (!(SDL_GetAppState()&SDL_APPACTIVE)) {
526     return;
527   }
528 #endif
529 
530 #ifdef GL_DOOM
531   if (V_GetMode() == VID_MODEGL) {
532     // proff 04/05/2000: swap OpenGL buffers
533     gld_Finish();
534     return;
535   }
536 #endif
537 
538   if ((screen_multiply > 1) || SDL_MUSTLOCK(screen)) {
539       int h;
540       byte *src;
541       byte *dest;
542 
543       if (SDL_LockSurface(screen) < 0) {
544         lprintf(LO_INFO,"I_FinishUpdate: %s\n", SDL_GetError());
545         return;
546       }
547 
548       // e6y: processing of screen_multiply
549       if (screen_multiply > 1)
550       {
551         R_ProcessScreenMultiply(screens[0].data, screen->pixels,
552           V_GetPixelDepth(), screens[0].byte_pitch, screen->pitch);
553       }
554       else
555       {
556         dest=screen->pixels;
557         src=screens[0].data;
558         h=screen->h;
559         for (; h>0; h--)
560         {
561           memcpy_fast(dest,src,SCREENWIDTH*V_GetPixelDepth()); //e6y
562           dest+=screen->pitch;
563           src+=screens[0].byte_pitch;
564         }
565       }
566 
567       SDL_UnlockSurface(screen);
568   }
569 
570   /* Update the display buffer (flipping video pages if supported)
571    * If we need to change palette, that implicitely does a flip */
572   if (newpal != NO_PALETTE_CHANGE) {
573     I_UploadNewPalette(newpal, false);
574     newpal = NO_PALETTE_CHANGE;
575   }
576 
577 #ifdef GL_DOOM
578   if (vid_8ingl.enabled)
579   {
580     gld_Draw8InGL();
581   }
582   else
583 #endif
584   {
585     SDL_Flip(screen);
586   }
587 }
588 
589 //
590 // I_ScreenShot - moved to i_sshot.c
591 //
592 
593 //
594 // I_SetPalette
595 //
I_SetPalette(int pal)596 void I_SetPalette (int pal)
597 {
598   newpal = pal;
599 }
600 
601 // I_PreInitGraphics
602 
I_ShutdownSDL(void)603 static void I_ShutdownSDL(void)
604 {
605   SDL_Quit();
606   return;
607 }
608 
I_PreInitGraphics(void)609 void I_PreInitGraphics(void)
610 {
611   int p;
612   char *video_driver = strdup(sdl_videodriver);
613 
614   // Initialize SDL
615   unsigned int flags = 0;
616   if (!(M_CheckParm("-nodraw") && M_CheckParm("-nosound")))
617     flags = SDL_INIT_VIDEO;
618 #ifdef PRBOOM_DEBUG
619   flags |= SDL_INIT_NOPARACHUTE;
620 #endif
621 
622   // e6y: Forcing "directx" video driver for Win9x.
623   // The "windib" video driver is the default for SDL > 1.2.9,
624   // to prevent problems with certain laptops, 64-bit Windows, and Windows Vista.
625   // The DirectX driver is still available, and can be selected by setting
626   // the environment variable SDL_VIDEODRIVER to "directx".
627 
628   if ((p = M_CheckParm("-videodriver")) && (p < myargc - 1))
629   {
630     free(video_driver);
631     video_driver = strdup(myargv[p + 1]);
632   }
633 
634   if (strcasecmp(video_driver, "default"))
635   {
636     // videodriver != default
637     char buf[80];
638     strcpy(buf, "SDL_VIDEODRIVER=");
639     strncat(buf, video_driver, sizeof(buf) - sizeof(buf[0]) - strlen(buf));
640     putenv(buf);
641   }
642   else
643   {
644     // videodriver == default
645 #ifdef _WIN32
646     if ((int)GetVersion() < 0 && V_GetMode() != VID_MODEGL ) // win9x
647     {
648       free(video_driver);
649       video_driver = strdup("directx");
650       putenv("SDL_VIDEODRIVER=directx");
651     }
652 #endif
653   }
654 
655   p = SDL_Init(flags);
656 
657   if (p < 0 && strcasecmp(video_driver, "default"))
658   {
659     static const union {
660       const char *c;
661       char *s;
662     } u = { "SDL_VIDEODRIVER=" };
663 
664     //e6y: wrong videodriver?
665     lprintf(LO_ERROR, "Could not initialize SDL with SDL_VIDEODRIVER=%s [%s]\n", video_driver, SDL_GetError());
666 
667     putenv(u.s);
668 
669     p = SDL_Init(flags);
670   }
671 
672   free(video_driver);
673 
674   if (p < 0)
675   {
676     I_Error("Could not initialize SDL [%s]", SDL_GetError());
677   }
678 
679   atexit(I_ShutdownSDL);
680 }
681 
682 // e6y: resolution limitation is removed
I_InitBuffersRes(void)683 void I_InitBuffersRes(void)
684 {
685   R_InitMeltRes();
686   R_InitSpritesRes();
687   R_InitBuffersRes();
688   R_InitPlanesRes();
689   R_InitVisplanesRes();
690 }
691 
692 #define MAX_RESOLUTIONS_COUNT 128
693 const char *screen_resolutions_list[MAX_RESOLUTIONS_COUNT] = {NULL};
694 const char *screen_resolution_lowest;
695 const char *screen_resolution = NULL;
696 
697 //
698 // I_GetScreenResolution
699 // Get current resolution from the config variable (WIDTHxHEIGHT format)
700 // 640x480 if screen_resolution variable has wrong data
701 //
I_GetScreenResolution(void)702 void I_GetScreenResolution(void)
703 {
704   int width, height;
705 
706   desired_screenwidth = 640;
707   desired_screenheight = 480;
708 
709   if (screen_resolution)
710   {
711     if (sscanf(screen_resolution, "%dx%d", &width, &height) == 2)
712     {
713       desired_screenwidth = width;
714       desired_screenheight = height;
715     }
716   }
717 }
718 
719 //
720 // I_FillScreenResolutionsList
721 // Get all the supported screen resolutions
722 // and fill the list with them
723 //
I_FillScreenResolutionsList(void)724 static void I_FillScreenResolutionsList(void)
725 {
726   SDL_Rect **modes;
727   int i, j, list_size, current_resolution_index, count;
728   char mode[256];
729   Uint32 flags;
730 
731   // do it only once
732   if (screen_resolutions_list[0])
733   {
734     return;
735   }
736 
737   if (desired_screenwidth == 0 || desired_screenheight == 0)
738   {
739     I_GetScreenResolution();
740   }
741 
742   flags = SDL_FULLSCREEN;
743 #ifdef GL_DOOM
744   flags |= SDL_OPENGL;
745 #endif
746 
747   // Don't call SDL_ListModes if SDL has not been initialized
748   if (!nodrawers)
749     modes = SDL_ListModes(NULL, flags);
750   else
751     modes = NULL;
752 
753   list_size = 0;
754   current_resolution_index = -1;
755 
756   if (modes)
757   {
758     count = 0;
759     for(i = 0; modes[i]; i++)
760     {
761       count++;
762     }
763     // (-2) is for NULL at the end of list and for custom resolution
764     count = MIN(count, MAX_RESOLUTIONS_COUNT - 2);
765 
766     for(i = count - 1; i >= 0; i--)
767     {
768       int in_list = false;
769 
770       SNPRINTF(mode, sizeof(mode), "%dx%d", modes[i]->w, modes[i]->h);
771 
772       if (i == count - 1)
773       {
774         screen_resolution_lowest = strdup(mode);
775       }
776 
777       for(j = 0; j < list_size; j++)
778       {
779         if (!strcmp(mode, screen_resolutions_list[j]))
780         {
781           in_list = true;
782           break;
783         }
784       }
785 
786       if (!in_list)
787       {
788         screen_resolutions_list[list_size] = strdup(mode);
789 
790         if (modes[i]->w == desired_screenwidth && modes[i]->h == desired_screenheight)
791         {
792           current_resolution_index = list_size;
793         }
794 
795         list_size++;
796       }
797     }
798     screen_resolutions_list[list_size] = NULL;
799   }
800 
801   if (list_size == 0)
802   {
803     SNPRINTF(mode, sizeof(mode), "%dx%d", desired_screenwidth, desired_screenheight);
804     screen_resolutions_list[0] = strdup(mode);
805     current_resolution_index = 0;
806     list_size = 1;
807   }
808 
809   if (current_resolution_index == -1)
810   {
811     SNPRINTF(mode, sizeof(mode), "%dx%d", desired_screenwidth, desired_screenheight);
812 
813     // make it first
814     list_size++;
815     for(i = list_size - 1; i > 0; i--)
816     {
817       screen_resolutions_list[i] = screen_resolutions_list[i - 1];
818     }
819     screen_resolutions_list[0] = strdup(mode);
820     current_resolution_index = 0;
821   }
822 
823   screen_resolutions_list[list_size] = NULL;
824   screen_resolution = screen_resolutions_list[current_resolution_index];
825 }
826 
827 // e6y
828 // GLBoom use this function for trying to set the closest supported resolution if the requested mode can't be set correctly.
829 // For example glboom.exe -geom 1025x768 -nowindow will set 1024x768.
830 // It should be used only for fullscreen modes.
I_ClosestResolution(int * width,int * height,int flags)831 static void I_ClosestResolution (int *width, int *height, int flags)
832 {
833   SDL_Rect **modes;
834   int twidth, theight;
835   int cwidth = 0, cheight = 0;
836   int i;
837   unsigned int closest = UINT_MAX;
838   unsigned int dist;
839 
840   modes = SDL_ListModes(NULL, flags);
841 
842   if (modes == (SDL_Rect **)-1)
843   {
844     // any dimension is okay for the given format
845     return;
846   }
847 
848   if (modes)
849   {
850     for(i=0; modes[i]; ++i)
851     {
852       twidth = modes[i]->w;
853       theight = modes[i]->h;
854 
855       if (twidth == *width && theight == *height)
856         return;
857 
858       //if (iteration == 0 && (twidth < *width || theight < *height))
859       //  continue;
860 
861       dist = (twidth - *width) * (twidth - *width) +
862              (theight - *height) * (theight - *height);
863 
864       if (dist < closest)
865       {
866         closest = dist;
867         cwidth = twidth;
868         cheight = theight;
869       }
870     }
871     if (closest != 4294967295u)
872     {
873       *width = cwidth;
874       *height = cheight;
875       return;
876     }
877   }
878 }
879 
880 int process_affinity_mask;
881 int process_priority;
882 int try_to_reduce_cpu_cache_misses;
883 
884 // e6y
885 // It is a simple test of CPU cache misses.
I_TestCPUCacheMisses(int width,int height,unsigned int mintime)886 unsigned int I_TestCPUCacheMisses(int width, int height, unsigned int mintime)
887 {
888   int i, k;
889   char *s, *d, *ps, *pd;
890   unsigned int tickStart;
891 
892   s = malloc(width * height);
893   d = malloc(width * height);
894 
895   tickStart = SDL_GetTicks();
896   k = 0;
897   do
898   {
899     ps = s;
900     pd = d;
901     for(i = 0; i < height; i++)
902     {
903       pd[0] = ps[0];
904       pd += width;
905       ps += width;
906     }
907     k++;
908   }
909   while (SDL_GetTicks() - tickStart < mintime);
910 
911   free(d);
912   free(s);
913 
914   return k;
915 }
916 
917 // CPhipps -
918 // I_CalculateRes
919 // Calculates the screen resolution, possibly using the supplied guide
I_CalculateRes(int width,int height)920 void I_CalculateRes(int width, int height)
921 {
922 // e6y
923 // GLBoom will try to set the closest supported resolution
924 // if the requested mode can't be set correctly.
925 // For example glboom.exe -geom 1025x768 -nowindow will set 1024x768.
926 // It affects only fullscreen modes.
927   if (V_GetMode() == VID_MODEGL) {
928     if ( desired_fullscreen )
929     {
930       I_ClosestResolution(&width, &height, SDL_OPENGL|SDL_FULLSCREEN);
931     }
932     SCREENWIDTH = width;
933     SCREENHEIGHT = height;
934     SCREENPITCH = SCREENWIDTH;
935   } else {
936     unsigned int count1, count2;
937     int pitch1, pitch2;
938 
939     SCREENWIDTH = width;//(width+15) & ~15;
940     SCREENHEIGHT = height;
941 
942     // e6y
943     // Trying to optimise screen pitch for reducing of CPU cache misses.
944     // It is extremally important for wiping in software.
945     // I have ~20x improvement in speed with using 1056 instead of 1024 on Pentium4
946     // and only ~10% for Core2Duo
947     if (try_to_reduce_cpu_cache_misses)
948     {
949       unsigned int mintime = 100;
950       int w = (width+15) & ~15;
951       pitch1 = w * V_GetPixelDepth();
952       pitch2 = w * V_GetPixelDepth() + 32;
953 
954       count1 = I_TestCPUCacheMisses(pitch1, SCREENHEIGHT, mintime);
955       count2 = I_TestCPUCacheMisses(pitch2, SCREENHEIGHT, mintime);
956 
957       lprintf(LO_INFO, "I_CalculateRes: trying to optimize screen pitch\n");
958       lprintf(LO_INFO, " test case for pitch=%d is processed %d times for %d msec\n", pitch1, count1, mintime);
959       lprintf(LO_INFO, " test case for pitch=%d is processed %d times for %d msec\n", pitch2, count2, mintime);
960 
961       SCREENPITCH = (count2 > count1 ? pitch2 : pitch1);
962 
963       lprintf(LO_INFO, " optimized screen pitch is %d\n", SCREENPITCH);
964     }
965     else
966     {
967       SCREENPITCH = SCREENWIDTH * V_GetPixelDepth();
968     }
969   }
970 
971   // e6y: processing of screen_multiply
972   {
973     int factor = ((V_GetMode() == VID_MODEGL) ? 1 : render_screen_multiply);
974     REAL_SCREENWIDTH = SCREENWIDTH * factor;
975     REAL_SCREENHEIGHT = SCREENHEIGHT * factor;
976     REAL_SCREENPITCH = SCREENPITCH * factor;
977   }
978 }
979 
980 // CPhipps -
981 // I_InitScreenResolution
982 // Sets the screen resolution
983 // e6y: processing of screen_multiply
I_InitScreenResolution(void)984 void I_InitScreenResolution(void)
985 {
986   int i, p, w, h;
987   char c, x;
988   video_mode_t mode;
989   int init = screen == NULL;
990 
991   I_GetScreenResolution();
992 
993   if (init)
994   {
995     //e6y: ability to change screen resolution from GUI
996     I_FillScreenResolutionsList();
997 
998     // Video stuff
999     if ((p = M_CheckParm("-width")))
1000       if (myargv[p+1])
1001         desired_screenwidth = atoi(myargv[p+1]);
1002 
1003     if ((p = M_CheckParm("-height")))
1004       if (myargv[p+1])
1005         desired_screenheight = atoi(myargv[p+1]);
1006 
1007     if ((p = M_CheckParm("-fullscreen")))
1008       use_fullscreen = 1;
1009 
1010     if ((p = M_CheckParm("-nofullscreen")))
1011       use_fullscreen = 0;
1012 
1013     // e6y
1014     // New command-line options for setting a window (-window)
1015     // or fullscreen (-nowindow) mode temporarily which is not saved in cfg.
1016     // It works like "-geom" switch
1017     desired_fullscreen = use_fullscreen;
1018     if ((p = M_CheckParm("-window")))
1019       desired_fullscreen = 0;
1020 
1021     if ((p = M_CheckParm("-nowindow")))
1022       desired_fullscreen = 1;
1023 
1024     // e6y
1025     // change the screen size for the current session only
1026     // syntax: -geom WidthxHeight[w|f]
1027     // examples: -geom 320x200f, -geom 640x480w, -geom 1024x768
1028     w = desired_screenwidth;
1029     h = desired_screenheight;
1030 
1031     if (!(p = M_CheckParm("-geom")))
1032       p = M_CheckParm("-geometry");
1033 
1034     if (p && p + 1 < myargc)
1035     {
1036       int count = sscanf(myargv[p+1], "%d%c%d%c", &w, &x, &h, &c);
1037 
1038       // at least width and height must be specified
1039       // restoring original values if not
1040       if (count < 3 || tolower(x) != 'x')
1041       {
1042         w = desired_screenwidth;
1043         h = desired_screenheight;
1044       }
1045       else
1046       {
1047         if (count >= 4)
1048         {
1049           if (tolower(c) == 'w')
1050             desired_fullscreen = 0;
1051           if (tolower(c) == 'f')
1052             desired_fullscreen = 1;
1053         }
1054       }
1055     }
1056   }
1057   else
1058   {
1059     w = desired_screenwidth;
1060     h = desired_screenheight;
1061   }
1062 
1063   mode = I_GetModeFromString(default_videomode);
1064   if ((i=M_CheckParm("-vidmode")) && i<myargc-1)
1065   {
1066     mode = I_GetModeFromString(myargv[i+1]);
1067   }
1068 
1069   V_InitMode(mode);
1070 
1071   I_CalculateRes(w, h);
1072   V_DestroyUnusedTrueColorPalettes();
1073   V_FreeScreens();
1074 
1075   // set first three to standard values
1076   for (i=0; i<3; i++) {
1077     screens[i].width = REAL_SCREENWIDTH;
1078     screens[i].height = REAL_SCREENHEIGHT;
1079     screens[i].byte_pitch = REAL_SCREENPITCH;
1080     screens[i].short_pitch = REAL_SCREENPITCH / V_GetModePixelDepth(VID_MODE16);
1081     screens[i].int_pitch = REAL_SCREENPITCH / V_GetModePixelDepth(VID_MODE32);
1082   }
1083 
1084   // statusbar
1085   screens[4].width = REAL_SCREENWIDTH;
1086   screens[4].height = REAL_SCREENHEIGHT;
1087   screens[4].byte_pitch = REAL_SCREENPITCH;
1088   screens[4].short_pitch = REAL_SCREENPITCH / V_GetModePixelDepth(VID_MODE16);
1089   screens[4].int_pitch = REAL_SCREENPITCH / V_GetModePixelDepth(VID_MODE32);
1090 
1091   I_InitBuffersRes();
1092 
1093   lprintf(LO_INFO,"I_InitScreenResolution: Using resolution %dx%d\n", REAL_SCREENWIDTH, REAL_SCREENHEIGHT);
1094 }
1095 
1096 //
1097 // Set the window caption
1098 //
1099 
I_SetWindowCaption(void)1100 void I_SetWindowCaption(void)
1101 {
1102   char *buf;
1103 
1104   buf = malloc(strlen(PACKAGE_NAME) + strlen(VERSION) + 10);
1105 
1106   sprintf(buf, "%s %s", PACKAGE_NAME, VERSION);
1107 
1108   SDL_WM_SetCaption(buf, NULL);
1109 
1110   free(buf);
1111 }
1112 
1113 //
1114 // Set the application icon
1115 //
1116 
1117 #include "icon.c"
1118 
I_SetWindowIcon(void)1119 void I_SetWindowIcon(void)
1120 {
1121   static SDL_Surface *surface = NULL;
1122   static Uint8 *mask;
1123   int i;
1124 
1125   // do it only once, because of crash in SDL_InitVideoMode in SDL 1.3
1126   if (!surface)
1127   {
1128     // Generate the mask
1129 
1130     mask = malloc(icon_w * icon_h / 8);
1131     memset(mask, 0, icon_w * icon_h / 8);
1132 
1133     for (i=0; i<icon_w * icon_h; ++i)
1134     {
1135         if (icon_data[i * 3] != 0x00
1136          || icon_data[i * 3 + 1] != 0x00
1137          || icon_data[i * 3 + 2] != 0x00)
1138         {
1139             mask[i / 8] |= 1 << (7 - i % 8);
1140         }
1141     }
1142 
1143     surface = SDL_CreateRGBSurfaceFrom(icon_data,
1144       icon_w, icon_h, 24, icon_w * 3,
1145       0xff << 0, 0xff << 8, 0xff << 16, 0);
1146   }
1147 
1148   if (surface && mask)
1149   {
1150     //SDL_WM_SetIcon(surface, mask);
1151   }
1152 }
1153 
I_InitGraphics(void)1154 void I_InitGraphics(void)
1155 {
1156   static int    firsttime=1;
1157 
1158   if (firsttime)
1159   {
1160     firsttime = 0;
1161 
1162     atexit(I_ShutdownGraphics);
1163     lprintf(LO_INFO, "I_InitGraphics: %dx%d\n", SCREENWIDTH, SCREENHEIGHT);
1164 
1165     /* Set the video mode */
1166     I_UpdateVideoMode();
1167 
1168     //e6y: setup the window title
1169     I_SetWindowCaption();
1170 
1171     //e6y: set the application icon
1172     I_SetWindowIcon();
1173 
1174     /* Initialize the input system */
1175     I_InitInputs();
1176 
1177     //e6y: new mouse code
1178     UpdateFocus();
1179     UpdateGrab();
1180   }
1181 }
1182 
I_GetModeFromString(const char * modestr)1183 int I_GetModeFromString(const char *modestr)
1184 {
1185   video_mode_t mode;
1186 
1187   if (!stricmp(modestr,"15")) {
1188     mode = VID_MODE15;
1189   } else if (!stricmp(modestr,"15bit")) {
1190     mode = VID_MODE15;
1191   } else if (!stricmp(modestr,"16")) {
1192     mode = VID_MODE16;
1193   } else if (!stricmp(modestr,"16bit")) {
1194     mode = VID_MODE16;
1195   } else if (!stricmp(modestr,"32")) {
1196     mode = VID_MODE32;
1197   } else if (!stricmp(modestr,"32bit")) {
1198     mode = VID_MODE32;
1199   } else if (!stricmp(modestr,"gl")) {
1200     mode = VID_MODEGL;
1201   } else if (!stricmp(modestr,"OpenGL")) {
1202     mode = VID_MODEGL;
1203   } else {
1204     mode = VID_MODE8;
1205   }
1206 
1207   return mode;
1208 }
1209 
I_UpdateVideoMode(void)1210 void I_UpdateVideoMode(void)
1211 {
1212   int init_flags;
1213 
1214   if(screen)
1215   {
1216 #ifdef GL_DOOM
1217     if (V_GetMode() == VID_MODEGL)
1218     {
1219       gld_CleanMemory();
1220       // hires patches
1221       gld_CleanStaticMemory();
1222     }
1223 #endif
1224 
1225     I_InitScreenResolution();
1226 
1227     SDL_FreeSurface(screen);
1228     screen = NULL;
1229 
1230 #ifdef GL_DOOM
1231     if (vid_8ingl.surface)
1232     {
1233       SDL_FreeSurface(vid_8ingl.surface);
1234       vid_8ingl.surface = NULL;
1235     }
1236 #endif
1237 
1238     SMP_Free();
1239   }
1240 
1241   // e6y: initialisation of screen_multiply
1242   screen_multiply = render_screen_multiply;
1243 
1244   // Initialize SDL with this graphics mode
1245   if (V_GetMode() == VID_MODEGL) {
1246     init_flags = SDL_OPENGL;
1247   } else {
1248     if (use_doublebuffer)
1249       init_flags = SDL_DOUBLEBUF;
1250     else
1251       init_flags = SDL_SWSURFACE;
1252 #ifndef PRBOOM_DEBUG
1253     init_flags |= SDL_HWPALETTE;
1254 #endif
1255   }
1256 
1257   if ( desired_fullscreen )
1258     init_flags |= SDL_FULLSCREEN;
1259 
1260   // In windowed mode, the window can be resized while the game is
1261   // running.  This feature is disabled on OS X, as it adds an ugly
1262   // scroll handle to the corner of the screen.
1263 #ifndef MACOSX
1264   if (!desired_fullscreen)
1265     init_flags |= SDL_RESIZABLE;
1266 #endif
1267 
1268   if (sdl_video_window_pos && sdl_video_window_pos[0])
1269   {
1270     char buf[80];
1271     strcpy(buf, "SDL_VIDEO_WINDOW_POS=");
1272     strncat(buf, sdl_video_window_pos, sizeof(buf) - sizeof(buf[0]) - strlen(buf));
1273     putenv(buf);
1274   }
1275 
1276 #ifdef GL_DOOM
1277   vid_8ingl.enabled = false;
1278 #endif
1279 
1280   if (V_GetMode() == VID_MODEGL)
1281   {
1282 #ifdef GL_DOOM
1283     SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 0 );
1284     SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 0 );
1285     SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 0 );
1286     SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 0 );
1287     SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 0 );
1288     SDL_GL_SetAttribute( SDL_GL_ACCUM_RED_SIZE, 0 );
1289     SDL_GL_SetAttribute( SDL_GL_ACCUM_GREEN_SIZE, 0 );
1290     SDL_GL_SetAttribute( SDL_GL_ACCUM_BLUE_SIZE, 0 );
1291     SDL_GL_SetAttribute( SDL_GL_ACCUM_ALPHA_SIZE, 0 );
1292     SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
1293     SDL_GL_SetAttribute( SDL_GL_BUFFER_SIZE, gl_colorbuffer_bits );
1294     SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, gl_depthbuffer_bits );
1295     SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 8 );
1296 
1297     //e6y: vertical sync
1298 #if !SDL_VERSION_ATLEAST(1, 3, 0)
1299     SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, (gl_vsync ? 1 : 0));
1300 #endif
1301 
1302     //e6y: anti-aliasing
1303     gld_MultisamplingInit();
1304 
1305     screen = SDL_SetVideoMode(REAL_SCREENWIDTH, REAL_SCREENHEIGHT, gl_colorbuffer_bits, init_flags);
1306     gld_CheckHardwareGamma();
1307 #endif
1308   }
1309   else
1310   {
1311 #ifdef GL_DOOM
1312     if (use_gl_surface)
1313     {
1314       int flags = SDL_OPENGL;
1315 
1316       if ( desired_fullscreen )
1317         flags |= SDL_FULLSCREEN;
1318 
1319       SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
1320       SDL_GL_SetAttribute( SDL_GL_BUFFER_SIZE, gl_colorbuffer_bits );
1321       SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, gl_depthbuffer_bits );
1322       //e6y: vertical sync
1323 #if !SDL_VERSION_ATLEAST(1, 3, 0)
1324       SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, (gl_vsync ? 1 : 0));
1325 #endif
1326 
1327       vid_8ingl.surface = SDL_SetVideoMode(
1328         REAL_SCREENWIDTH, REAL_SCREENHEIGHT,
1329         gl_colorbuffer_bits, flags);
1330 
1331       if(vid_8ingl.surface == NULL)
1332         I_Error("Couldn't set %dx%d video mode [%s]", REAL_SCREENWIDTH, REAL_SCREENHEIGHT, SDL_GetError());
1333 
1334       screen = SDL_CreateRGBSurface(
1335         init_flags & ~SDL_FULLSCREEN,
1336         REAL_SCREENWIDTH, REAL_SCREENHEIGHT,
1337         V_GetNumPixelBits(), 0, 0, 0, 0);
1338 
1339       vid_8ingl.screen = screen;
1340 
1341       vid_8ingl.enabled = true;
1342     }
1343     else
1344 #endif
1345     {
1346       screen = SDL_SetVideoMode(REAL_SCREENWIDTH, REAL_SCREENHEIGHT, V_GetNumPixelBits(), init_flags);
1347     }
1348   }
1349 
1350   if(screen == NULL) {
1351     I_Error("Couldn't set %dx%d video mode [%s]", REAL_SCREENWIDTH, REAL_SCREENHEIGHT, SDL_GetError());
1352   }
1353 
1354   SMP_Init();
1355 
1356 #if SDL_VERSION_ATLEAST(1, 3, 0)
1357 #ifdef GL_DOOM
1358   if (V_GetMode() == VID_MODEGL)
1359   {
1360     SDL_GL_SetSwapInterval((gl_vsync ? 1 : 0));
1361   }
1362 #endif
1363 #endif
1364 
1365 #ifdef GL_DOOM
1366   /*if (V_GetMode() == VID_MODEGL)
1367     gld_MultisamplingCheck();*/
1368 #endif
1369 
1370   lprintf(LO_INFO, "I_UpdateVideoMode: 0x%x, %s, %s\n", init_flags, screen->pixels ? "SDL buffer" : "own buffer", SDL_MUSTLOCK(screen) ? "lock-and-copy": "direct access");
1371 
1372   // Get the info needed to render to the display
1373   if (screen_multiply==1 && !SDL_MUSTLOCK(screen))
1374   {
1375     screens[0].not_on_heap = true;
1376     screens[0].data = (unsigned char *) (screen->pixels);
1377     screens[0].byte_pitch = screen->pitch;
1378     screens[0].short_pitch = screen->pitch / V_GetModePixelDepth(VID_MODE16);
1379     screens[0].int_pitch = screen->pitch / V_GetModePixelDepth(VID_MODE32);
1380   }
1381   else
1382   {
1383     screens[0].not_on_heap = false;
1384   }
1385 
1386   V_AllocScreens();
1387 
1388   R_InitBuffer(SCREENWIDTH, SCREENHEIGHT);
1389 
1390   // e6y: wide-res
1391   // Need some initialisations before level precache
1392   R_ExecuteSetViewSize();
1393 
1394   V_SetPalette(0);
1395   I_UploadNewPalette(0, true);
1396 
1397   ST_SetResolution();
1398   AM_SetResolution();
1399 
1400 #ifdef GL_DOOM
1401   if (V_GetMode() == VID_MODEGL)
1402   {
1403     int temp;
1404     lprintf(LO_INFO,"SDL OpenGL PixelFormat:\n");
1405     SDL_GL_GetAttribute( SDL_GL_RED_SIZE, &temp );
1406     lprintf(LO_INFO,"    SDL_GL_RED_SIZE: %i\n",temp);
1407     SDL_GL_GetAttribute( SDL_GL_GREEN_SIZE, &temp );
1408     lprintf(LO_INFO,"    SDL_GL_GREEN_SIZE: %i\n",temp);
1409     SDL_GL_GetAttribute( SDL_GL_BLUE_SIZE, &temp );
1410     lprintf(LO_INFO,"    SDL_GL_BLUE_SIZE: %i\n",temp);
1411     SDL_GL_GetAttribute( SDL_GL_STENCIL_SIZE, &temp );
1412     lprintf(LO_INFO,"    SDL_GL_STENCIL_SIZE: %i\n",temp);
1413     SDL_GL_GetAttribute( SDL_GL_ACCUM_RED_SIZE, &temp );
1414     lprintf(LO_INFO,"    SDL_GL_ACCUM_RED_SIZE: %i\n",temp);
1415     SDL_GL_GetAttribute( SDL_GL_ACCUM_GREEN_SIZE, &temp );
1416     lprintf(LO_INFO,"    SDL_GL_ACCUM_GREEN_SIZE: %i\n",temp);
1417     SDL_GL_GetAttribute( SDL_GL_ACCUM_BLUE_SIZE, &temp );
1418     lprintf(LO_INFO,"    SDL_GL_ACCUM_BLUE_SIZE: %i\n",temp);
1419     SDL_GL_GetAttribute( SDL_GL_ACCUM_ALPHA_SIZE, &temp );
1420     lprintf(LO_INFO,"    SDL_GL_ACCUM_ALPHA_SIZE: %i\n",temp);
1421     SDL_GL_GetAttribute( SDL_GL_DOUBLEBUFFER, &temp );
1422     lprintf(LO_INFO,"    SDL_GL_DOUBLEBUFFER: %i\n",temp);
1423     SDL_GL_GetAttribute( SDL_GL_BUFFER_SIZE, &temp );
1424     lprintf(LO_INFO,"    SDL_GL_BUFFER_SIZE: %i\n",temp);
1425     SDL_GL_GetAttribute( SDL_GL_DEPTH_SIZE, &temp );
1426     lprintf(LO_INFO,"    SDL_GL_DEPTH_SIZE: %i\n",temp);
1427     SDL_GL_GetAttribute( SDL_GL_MULTISAMPLESAMPLES, &temp );
1428     lprintf(LO_INFO,"    SDL_GL_MULTISAMPLESAMPLES: %i\n",temp);
1429     SDL_GL_GetAttribute( SDL_GL_MULTISAMPLEBUFFERS, &temp );
1430     lprintf(LO_INFO,"    SDL_GL_MULTISAMPLEBUFFERS: %i\n",temp);
1431     SDL_GL_GetAttribute( SDL_GL_STENCIL_SIZE, &temp );
1432     lprintf(LO_INFO,"    SDL_GL_STENCIL_SIZE: %i\n",temp);
1433 
1434     gld_Init(SCREENWIDTH, SCREENHEIGHT);
1435   }
1436 
1437   if (vid_8ingl.enabled)
1438   {
1439     gld_Init8InGLMode();
1440   }
1441 
1442   if (V_GetMode() == VID_MODEGL)
1443   {
1444     M_ChangeFOV();
1445     M_ChangeRenderPrecise();
1446     M_ChangeCompTranslucency();
1447   }
1448 #endif
1449 }
1450 
ActivateMouse(void)1451 static void ActivateMouse(void)
1452 {
1453   SDL_WM_GrabInput(SDL_GRAB_ON);
1454 #if SDL_VERSION_ATLEAST(1, 3, 0)
1455   SDL_ShowCursor(0);
1456 #else
1457   SDL_SetCursor(cursors[1]);
1458   SDL_ShowCursor(1);
1459 #endif
1460 }
1461 
DeactivateMouse(void)1462 static void DeactivateMouse(void)
1463 {
1464   SDL_WM_GrabInput(SDL_GRAB_OFF);
1465 #if !SDL_VERSION_ATLEAST(1, 3, 0)
1466   SDL_SetCursor(cursors[0]);
1467 #endif
1468   SDL_ShowCursor(1);
1469 }
1470 
1471 // Warp the mouse back to the middle of the screen
CenterMouse(void)1472 static void CenterMouse(void)
1473 {
1474   // Warp the the screen center
1475   SDL_WarpMouse((unsigned short)(REAL_SCREENWIDTH/2), (unsigned short)(REAL_SCREENHEIGHT/2));
1476 
1477   // Clear any relative movement caused by warping
1478   SDL_PumpEvents();
1479   SDL_GetRelativeMouseState(NULL, NULL);
1480 }
1481 
1482 //
1483 // Read the change in mouse state to generate mouse motion events
1484 //
1485 // This is to combine all mouse movement for a tic into one mouse
1486 // motion event.
I_ReadMouse(void)1487 static void I_ReadMouse(void)
1488 {
1489   static int mouse_currently_grabbed = true;
1490   int x, y;
1491   event_t ev;
1492 
1493   if (!usemouse)
1494     return;
1495 
1496   if (!MouseShouldBeGrabbed())
1497   {
1498     mouse_currently_grabbed = false;
1499     return;
1500   }
1501 
1502   if (!mouse_currently_grabbed && !desired_fullscreen)
1503   {
1504     CenterMouse();
1505     mouse_currently_grabbed = true;
1506   }
1507 
1508   SDL_GetRelativeMouseState(&x, &y);
1509 
1510   if (x != 0 || y != 0)
1511   {
1512     ev.type = ev_mouse;
1513     ev.data1 = I_SDLtoDoomMouseState(SDL_GetMouseState(NULL, NULL));
1514     ev.data2 = x << 5;
1515     ev.data3 = (-y) << 5;
1516 
1517     D_PostEvent(&ev);
1518   }
1519 
1520   CenterMouse();
1521 }
1522 
MouseShouldBeGrabbed()1523 static dboolean MouseShouldBeGrabbed()
1524 {
1525   // never grab the mouse when in screensaver mode
1526 
1527   //if (screensaver_mode)
1528   //    return false;
1529 
1530   // if the window doesnt have focus, never grab it
1531   if (!window_focused)
1532     return false;
1533 
1534   // always grab the mouse when full screen (dont want to
1535   // see the mouse pointer)
1536   if (desired_fullscreen)
1537     return true;
1538 
1539   // if we specify not to grab the mouse, never grab
1540   if (!mouse_enabled)
1541     return false;
1542 
1543   // always grab the mouse in camera mode when playing levels
1544   // and menu is not active
1545   if (walkcamera.type)
1546     return (demoplayback && gamestate == GS_LEVEL && !menuactive);
1547 
1548   // when menu is active or game is paused, release the mouse
1549   if (menuactive || paused)
1550     return false;
1551 
1552   // only grab mouse when playing levels (but not demos)
1553   return (gamestate == GS_LEVEL) && !demoplayback;
1554 }
1555 
1556 // Update the value of window_focused when we get a focus event
1557 //
1558 // We try to make ourselves be well-behaved: the grab on the mouse
1559 // is removed if we lose focus (such as a popup window appearing),
1560 // and we dont move the mouse around if we aren't focused either.
UpdateFocus(void)1561 static void UpdateFocus(void)
1562 {
1563   Uint8 state;
1564 
1565   state = SDL_GetAppState();
1566 
1567   // We should have input (keyboard) focus and be visible
1568   // (not minimised)
1569   window_focused = (state & SDL_APPINPUTFOCUS) && (state & SDL_APPACTIVE);
1570 
1571   // e6y
1572   // Reuse of a current palette to avoid black screen at software fullscreen modes
1573   // after switching to OS and back
1574   if (desired_fullscreen && window_focused)
1575   {
1576     // currentPaletteIndex?
1577     if (st_palette < 0)
1578       st_palette = 0;
1579 
1580     V_SetPalette(st_palette);
1581   }
1582 
1583 #ifdef GL_DOOM
1584   if (V_GetMode() == VID_MODEGL)
1585   {
1586     if (gl_hardware_gamma)
1587     {
1588       if (!window_focused)
1589       {
1590         // e6y: Restore of startup gamma if window loses focus
1591         gld_SetGammaRamp(-1);
1592       }
1593       else
1594       {
1595         gld_SetGammaRamp(useglgamma);
1596       }
1597     }
1598   }
1599 #endif
1600 
1601   // Should the screen be grabbed?
1602   //    screenvisible = (state & SDL_APPACTIVE) != 0;
1603 }
1604 
UpdateGrab(void)1605 void UpdateGrab(void)
1606 {
1607   static dboolean currently_grabbed = false;
1608   dboolean grab;
1609 
1610   grab = MouseShouldBeGrabbed();
1611 
1612   if (grab && !currently_grabbed)
1613   {
1614     ActivateMouse();
1615   }
1616 
1617   if (!grab && currently_grabbed)
1618   {
1619     DeactivateMouse();
1620   }
1621 
1622   currently_grabbed = grab;
1623 }
1624 
ApplyWindowResize(SDL_Event * resize_event)1625 static void ApplyWindowResize(SDL_Event *resize_event)
1626 {
1627   int i, k;
1628   char mode[80];
1629 
1630   int w = MAX(320, resize_event->resize.w);
1631   int h = MAX(200, resize_event->resize.h);
1632 
1633   if (screen_resolution)
1634   {
1635     if (!(SDL_GetModState() & KMOD_SHIFT))
1636     {
1637       // Find the biggest screen mode that will fall within these
1638       // dimensions, falling back to the smallest mode possible if
1639       // none is found.
1640 
1641       Uint32 flags = SDL_FULLSCREEN;
1642 
1643       if (V_GetMode() == VID_MODEGL)
1644         flags |= SDL_OPENGL;
1645 
1646       I_ClosestResolution(&w, &h, flags);
1647     }
1648 
1649     w = MAX(320, w);
1650     h = MAX(200, h);
1651 
1652     sprintf(mode, "%dx%d", w, h);
1653     screen_resolution = screen_resolutions_list[0];
1654     for (i = 0; i < MAX_RESOLUTIONS_COUNT; i++)
1655     {
1656       if (screen_resolutions_list[i])
1657       {
1658         if (!strcmp(mode, screen_resolutions_list[i]))
1659         {
1660           screen_resolution = screen_resolutions_list[i];
1661           break;
1662         }
1663       }
1664     }
1665 
1666     // custom resolution
1667     if (screen_resolution == screen_resolutions_list[0])
1668     {
1669       if (screen_resolution_lowest &&
1670           !strcmp(screen_resolution_lowest, screen_resolutions_list[0]))
1671       {
1672         // there is no "custom resolution" entry in the list
1673         for(k = MAX_RESOLUTIONS_COUNT - 1; k > 0; k--)
1674         {
1675           screen_resolutions_list[k] = screen_resolutions_list[k - 1];
1676         }
1677         // add it
1678         screen_resolutions_list[0] = strdup(mode);
1679         screen_resolution = screen_resolutions_list[0];
1680       }
1681       else
1682       {
1683         sprintf((char*)screen_resolution, mode);
1684       }
1685     }
1686 
1687     V_ChangeScreenResolution();
1688 
1689     doom_printf("%dx%d", w, h);
1690   }
1691 }
1692