]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - vid_sdl.c
vid: misc cleanups
[xonotic/darkplaces.git] / vid_sdl.c
index 97e54735ed4c8a291af8ade55a46e3153741b650..8a7a326aaf93a4cca41ce1a8ef6e56781dae417d 100644 (file)
--- a/vid_sdl.c
+++ b/vid_sdl.c
@@ -30,17 +30,20 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include <IOKit/hidsystem/IOHIDLib.h>
 #include <IOKit/hidsystem/IOHIDParameter.h>
 #include <IOKit/hidsystem/event_status_driver.h>
+#if (MAC_OS_X_VERSION_MIN_REQUIRED < 120000)
+       #define IOMainPort IOMasterPort
+#endif
 static cvar_t apple_mouse_noaccel = {CF_CLIENT | CF_ARCHIVE, "apple_mouse_noaccel", "1", "disables mouse acceleration while DarkPlaces is active"};
 static qbool vid_usingnoaccel;
 static double originalMouseSpeed = -1.0;
-io_connect_t IN_GetIOHandle(void)
+static io_connect_t IN_GetIOHandle(void)
 {
        io_connect_t iohandle = MACH_PORT_NULL;
        kern_return_t status;
        io_service_t iohidsystem = MACH_PORT_NULL;
        mach_port_t masterport;
 
-       status = IOMasterPort(MACH_PORT_NULL, &masterport);
+       status = IOMainPort(MACH_PORT_NULL, &masterport);
        if(status != KERN_SUCCESS)
                return 0;
 
@@ -69,7 +72,6 @@ static qbool vid_usingmouse = false;
 static qbool vid_usingmouse_relativeworks = false; // SDL2 workaround for unimplemented RelativeMouse mode
 static qbool vid_usinghidecursor = false;
 static qbool vid_hasfocus = false;
-static qbool vid_isfullscreen;
 static qbool vid_usingvsync = false;
 static SDL_Joystick *vid_sdljoystick = NULL;
 static SDL_GameController *vid_sdlgamecontroller = NULL;
@@ -80,12 +82,9 @@ static cvar_t *steelstorm_showing_mousecursor = NULL; // detect but do not creat
 
 static int win_half_width = 50;
 static int win_half_height = 50;
-static int video_bpp;
 
 static SDL_GLContext context;
 static SDL_Window *window;
-static int window_flags;
-static vid_mode_t desktop_mode;
 
 // Input handling
 
@@ -97,7 +96,8 @@ static int MapKey( unsigned int sdlkey )
 {
        switch(sdlkey)
        {
-       default: return 0;
+       // sdlkey can be Unicode codepoint for non-ascii keys, which are valid
+       default:                      return sdlkey & SDLK_SCANCODE_MASK ? 0 : sdlkey;
 //     case SDLK_UNKNOWN:            return K_UNKNOWN;
        case SDLK_RETURN:             return K_ENTER;
        case SDLK_ESCAPE:             return K_ESCAPE;
@@ -368,20 +368,20 @@ qbool VID_ShowingKeyboard(void)
        return SDL_IsTextInputActive() != 0;
 }
 
-void VID_SetMouse(qbool fullscreengrab, qbool relative, qbool hidecursor)
+void VID_SetMouse(qbool relative, qbool hidecursor)
 {
 #ifndef DP_MOBILETOUCH
 #ifdef MACOSX
        if(relative)
                if(vid_usingmouse && (vid_usingnoaccel != !!apple_mouse_noaccel.integer))
-                       VID_SetMouse(false, false, false); // ungrab first!
+                       VID_SetMouse(false, false); // ungrab first!
 #endif
        if (vid_usingmouse != relative)
        {
                vid_usingmouse = relative;
                cl_ignoremousemoves = 2;
                vid_usingmouse_relativeworks = SDL_SetRelativeMouseMode(relative ? SDL_TRUE : SDL_FALSE) == 0;
-//             Con_Printf("VID_SetMouse(%i, %i, %i) relativeworks = %i\n", (int)fullscreengrab, (int)relative, (int)hidecursor, (int)vid_usingmouse_relativeworks);
+//             Con_Printf("VID_SetMouse(%i, %i) relativeworks = %i\n", (int)relative, (int)hidecursor, (int)vid_usingmouse_relativeworks);
 #ifdef MACOSX
                if(relative)
                {
@@ -894,7 +894,7 @@ static void IN_Move_TouchScreen_Quake(void)
                if (!VID_ShowingKeyboard())
                {
                        // user entered a command, close the console now
-                       Con_ToggleConsole_f(&cmd_client);
+                       Con_ToggleConsole_f(cmd_local);
                }
                VID_TouchscreenArea( 0,   0,   0,   0,   0, NULL                         , 0.0f, NULL, NULL, &buttons[15], (keynum_t)0, NULL, 0, 0, 0, true);
                VID_TouchscreenArea( 0,   0,   0,   0,   0, NULL                         , 0.0f, NULL, move, &buttons[0], K_MOUSE4, NULL, 0, 0, 0, true);
@@ -1056,13 +1056,12 @@ static keynum_t buttonremap[] =
 };
 
 //#define DEBUGSDLEVENTS
-
-// SDL2
-void Sys_SendKeyEvents( void )
+void Sys_SDL_HandleEvents(void)
 {
        static qbool sound_active = true;
        int keycode;
        int i;
+       const char *chp;
        qbool isdown;
        Uchar unicode;
        SDL_Event event;
@@ -1179,7 +1178,7 @@ void Sys_SendKeyEvents( void )
                                                        // so, let's better queue it for next frame
                                                        if(!sdl_needs_restart)
                                                        {
-                                                               Cbuf_AddText(&cmd_client, "\nr_restart\n");
+                                                               Cbuf_AddText(cmd_local, "\nr_restart\n");
                                                                sdl_needs_restart = true;
                                                        }
 #endif
@@ -1219,9 +1218,14 @@ void Sys_SendKeyEvents( void )
 #endif
                                // convert utf8 string to char
                                // NOTE: this code is supposed to run even if utf8enable is 0
-                               unicode = u8_getchar_utf8_enabled(event.text.text + (int)u8_bytelen(event.text.text, 0), NULL);
-                               Key_Event(K_TEXT, unicode, true);
-                               Key_Event(K_TEXT, unicode, false);
+                               chp = event.text.text;
+                               while (*chp != 0)
+                               {
+                                       // input the chars one by one (there can be multiple chars when e.g. using an "input method")
+                                       unicode = u8_getchar_utf8_enabled(chp, &chp);
+                                       Key_Event(K_TEXT, unicode, true);
+                                       Key_Event(K_TEXT, unicode, false);
+                               }
                                break;
                        case SDL_MOUSEMOTION:
                                break;
@@ -1316,8 +1320,6 @@ qbool GL_ExtensionSupported(const char *name)
        return SDL_GL_ExtensionSupported(name);
 }
 
-static qbool vid_sdl_initjoysticksystem = false;
-
 void VID_Init (void)
 {
 #ifndef __IPHONEOS__
@@ -1336,10 +1338,8 @@ void VID_Init (void)
 
        if (SDL_Init(SDL_INIT_VIDEO) < 0)
                Sys_Error ("Failed to init SDL video subsystem: %s", SDL_GetError());
-       vid_sdl_initjoysticksystem = SDL_InitSubSystem(SDL_INIT_JOYSTICK) >= 0;
-       if (!vid_sdl_initjoysticksystem)
+       if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
                Con_Printf(CON_ERROR "Failed to init SDL joystick subsystem: %s\n", SDL_GetError());
-       vid_isfullscreen = false;
 }
 
 static int vid_sdljoystickindex = -1;
@@ -1462,12 +1462,6 @@ static void AdjustWindowBounds(viddef_mode_t *mode, RECT *rect)
 }
 #endif
 
-extern cvar_t gl_info_vendor;
-extern cvar_t gl_info_renderer;
-extern cvar_t gl_info_version;
-extern cvar_t gl_info_platform;
-extern cvar_t gl_info_driver;
-
 static qbool VID_InitModeGL(viddef_mode_t *mode)
 {
        int windowflags = SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL;
@@ -1477,7 +1471,8 @@ static qbool VID_InitModeGL(viddef_mode_t *mode)
        int yPos = SDL_WINDOWPOS_UNDEFINED;
        int i;
 #ifndef USE_GLES2
-       const char *drivername;
+       // SDL usually knows best
+       const char *drivername = NULL;
 #endif
 
        win_half_width = mode->width>>1;
@@ -1489,9 +1484,6 @@ static qbool VID_InitModeGL(viddef_mode_t *mode)
        VID_OutputVersion();
 
 #ifndef USE_GLES2
-       // SDL usually knows best
-       drivername = NULL;
-
 // COMMANDLINEOPTION: SDL GL: -gl_driver <drivername> selects a GL driver library, default is whatever SDL recommends, useful only for 3dfxogl.dll/3dfxvgl.dll or fxmesa or similar, if you don't know what this is for, you don't need it
        i = Sys_CheckParm("-gl_driver");
        if (i && i < sys.argc - 1)
@@ -1510,40 +1502,41 @@ static qbool VID_InitModeGL(viddef_mode_t *mode)
        windowflags |= SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS;
 #endif
 
-       vid_isfullscreen = false;
+
+       if (mode->fullscreen)
        {
-               if (mode->fullscreen) {
-                       if (vid_desktopfullscreen.integer)
-                       {
-                               vid_mode_t *m = VID_GetDesktopMode();
-                               mode->width = m->width;
-                               mode->height = m->height;
-                               windowflags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
-                       }
-                       else
-                               windowflags |= SDL_WINDOW_FULLSCREEN;
-                       vid_isfullscreen = true;
+               if (vid_desktopfullscreen.integer)
+               {
+                       vid_mode_t m = VID_GetDesktopMode();
+                       mode->width = m.width;
+                       mode->height = m.height;
+                       windowflags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
                }
-               else {
-                       if (vid_borderless.integer)
-                               windowflags |= SDL_WINDOW_BORDERLESS;
+               else
+                       windowflags |= SDL_WINDOW_FULLSCREEN;
+       }
+       else
+       {
+               if (vid_borderless.integer)
+                       windowflags |= SDL_WINDOW_BORDERLESS;
 #ifdef WIN32
-                       if (vid_ignore_taskbar.integer) {
-                               xPos = SDL_WINDOWPOS_CENTERED;
-                               yPos = SDL_WINDOWPOS_CENTERED;
-                       }
-                       else {
-                               RECT rect;
-                               AdjustWindowBounds(mode, &rect);
-                               xPos = rect.left;
-                               yPos = rect.top;
-                       }
-#endif
+               if (vid_ignore_taskbar.integer)
+               {
+                       xPos = SDL_WINDOWPOS_CENTERED;
+                       yPos = SDL_WINDOWPOS_CENTERED;
+               }
+               else
+               {
+                       RECT rect;
+                       AdjustWindowBounds(mode, &rect);
+                       xPos = rect.left;
+                       yPos = rect.top;
                }
+#endif
        }
-       //flags |= SDL_HWSURFACE;
 
-       if (vid_mouse_clickthrough.integer && !vid_isfullscreen)
+
+       if (vid_mouse_clickthrough.integer)
                SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
 
        SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
@@ -1569,12 +1562,13 @@ static qbool VID_InitModeGL(viddef_mode_t *mode)
        SDL_GL_SetAttribute (SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
+       /* Requesting a Core profile and 3.2 minimum is mandatory on macOS and older Mesa drivers.
+        * It works fine on other drivers too except NVIDIA, see HACK below.
+        */
 #endif
 
        SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, (gl_debug.integer > 0 ? SDL_GL_CONTEXT_DEBUG_FLAG : 0));
 
-       video_bpp = mode->bitsperpixel;
-       window_flags = windowflags;
        window = SDL_CreateWindow(gamename, xPos, yPos, mode->width, mode->height, windowflags);
        if (window == NULL)
        {
@@ -1591,10 +1585,39 @@ static qbool VID_InitModeGL(viddef_mode_t *mode)
                return false;
        }
 
+       GL_InitFunctions();
+
+#if !defined(USE_GLES2) && !defined(MACOSX)
+       // NVIDIA hates the Core profile and limits the version to the minimum we specified.
+       // HACK: to detect NVIDIA we first need a context, fortunately replacing it takes a few milliseconds
+       gl_vendor = (const char *)qglGetString(GL_VENDOR);
+       if (strncmp(gl_vendor, "NVIDIA", 6) == 0)
+       {
+               Con_DPrint("The Way It's Meant To Be Played: replacing OpenGL Core profile with Compatibility profile...\n");
+               SDL_GL_DeleteContext(context);
+               SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
+               context = SDL_GL_CreateContext(window);
+               if (context == NULL)
+               {
+                       Con_Printf(CON_ERROR "Failed to initialize OpenGL context: %s\n", SDL_GetError());
+                       VID_Shutdown();
+                       return false;
+               }
+       }
+#endif
+
        SDL_GL_SetSwapInterval(bound(-1, vid_vsync.integer, 1));
        vid_usingvsync = (vid_vsync.integer != 0);
 
-       gl_platform = "SDL";
+       vid_hidden = false;
+       vid_activewindow = true;
+       vid_hasfocus = true;
+       vid_usingmouse = false;
+       vid_usinghidecursor = false;
+
+       // clear to black (loading plaque will be seen over this)
+       GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
+       VID_Finish(); // checks vid_hidden
 
        GL_Setup();
 
@@ -1602,40 +1625,12 @@ static qbool VID_InitModeGL(viddef_mode_t *mode)
        Cvar_SetQuick(&gl_info_vendor, gl_vendor);
        Cvar_SetQuick(&gl_info_renderer, gl_renderer);
        Cvar_SetQuick(&gl_info_version, gl_version);
-       Cvar_SetQuick(&gl_info_platform, gl_platform ? gl_platform : "");
-       Cvar_SetQuick(&gl_info_driver, gl_driver);
-
-       // LadyHavoc: report supported extensions
-       Con_DPrintf("\nQuakeC extensions for server and client:");
-       for (i = 0; vm_sv_extensions[i]; i++)
-               Con_DPrintf(" %s", vm_sv_extensions[i]);
-       Con_DPrintf("\n");
-#ifdef CONFIG_MENU
-       Con_DPrintf("\nQuakeC extensions for menu:");
-       for (i = 0; vm_m_extensions[i]; i++)
-               Con_DPrintf(" %s", vm_m_extensions[i]);
-       Con_DPrintf("\n");
-#endif
+       Cvar_SetQuick(&gl_info_platform, "SDL");
+       Cvar_SetQuick(&gl_info_driver, drivername ? drivername : "");
 
-       // clear to black (loading plaque will be seen over this)
-       GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
-
-       vid_hidden = false;
-       vid_activewindow = false;
-       vid_hasfocus = true;
-       vid_usingmouse = false;
-       vid_usinghidecursor = false;
-               
        return true;
 }
 
-extern cvar_t gl_info_extensions;
-extern cvar_t gl_info_vendor;
-extern cvar_t gl_info_renderer;
-extern cvar_t gl_info_version;
-extern cvar_t gl_info_platform;
-extern cvar_t gl_info_driver;
-
 qbool VID_InitMode(viddef_mode_t *mode)
 {
        // GAME_STEELSTORM specific
@@ -1652,16 +1647,14 @@ qbool VID_InitMode(viddef_mode_t *mode)
 void VID_Shutdown (void)
 {
        VID_EnableJoystick(false);
-       VID_SetMouse(false, false, false);
+       VID_SetMouse(false, false);
 
+       SDL_GL_DeleteContext(context);
+       context = NULL;
        SDL_DestroyWindow(window);
        window = NULL;
 
        SDL_QuitSubSystem(SDL_INIT_VIDEO);
-
-       gl_driver[0] = 0;
-       gl_extensions = "";
-       gl_platform = "";
 }
 
 void VID_Finish (void)
@@ -1696,11 +1689,13 @@ void VID_Finish (void)
        }
 }
 
-vid_mode_t *VID_GetDesktopMode(void)
+vid_mode_t VID_GetDesktopMode(void)
 {
        SDL_DisplayMode mode;
        int bpp;
        Uint32 rmask, gmask, bmask, amask;
+       vid_mode_t desktop_mode;
+
        SDL_GetDesktopDisplayMode(0, &mode);
        SDL_PixelFormatEnumToMasks(mode.format, &bpp, &rmask, &gmask, &bmask, &amask);
        desktop_mode.width = mode.w;
@@ -1712,7 +1707,7 @@ vid_mode_t *VID_GetDesktopMode(void)
        // TODO check whether this actually works, or whether we do still need
        // a read-window-size-after-entering-desktop-fullscreen hack for
        // multiscreen setups.
-       return &desktop_mode;
+       return desktop_mode;
 }
 
 size_t VID_ListModes(vid_mode_t *modes, size_t maxcount)