Esempio n. 1
0
        public Sdl2PlatformWindow(Size requestEffectiveWindowSize, WindowMode windowMode,
                                  float scaleModifier, int batchSize, int videoDisplay, GLProfile requestProfile, bool enableLegacyGL)
        {
            // Lock the Window/Surface properties until initialization is complete
            lock (syncObject)
            {
                this.scaleModifier = scaleModifier;

                // Disable legacy scaling on Windows
                if (Platform.CurrentPlatform == PlatformType.Windows)
                {
                    SetProcessDPIAware();
                }

                // Decide which OpenGL profile to use.
                // Prefer standard GL over GLES provided by the native driver
                var testProfiles = new List <GLProfile> {
                    GLProfile.ANGLE, GLProfile.Modern, GLProfile.Embedded
                };
                if (enableLegacyGL)
                {
                    testProfiles.Add(GLProfile.Legacy);
                }

                supportedProfiles = testProfiles
                                    .Where(CanCreateGLWindow)
                                    .ToArray();

                if (!supportedProfiles.Any())
                {
                    throw new InvalidOperationException("No supported OpenGL profiles were found.");
                }

                profile = supportedProfiles.Contains(requestProfile) ? requestProfile : supportedProfiles.First();

                // Note: This must be called after the CanCreateGLWindow checks above,
                // which needs to create and destroy its own SDL contexts as a workaround for specific buggy drivers
                SDL.SDL_Init(SDL.SDL_INIT_VIDEO);
                SetSDLAttributes(profile);

                Console.WriteLine("Using SDL 2 with OpenGL ({0}) renderer", profile);
                if (videoDisplay < 0 || videoDisplay >= DisplayCount)
                {
                    videoDisplay = 0;
                }

                SDL.SDL_GetCurrentDisplayMode(videoDisplay, out var display);

                // Windows and Linux define window sizes in native pixel units.
                // Query the display/dpi scale so we can convert our requested effective size to pixels.
                // This is not necessary on macOS, which defines window sizes in effective units ("points").
                if (Platform.CurrentPlatform == PlatformType.Windows)
                {
                    // Launch the game with OPENRA_DISPLAY_SCALE to force a specific scaling factor
                    // Otherwise fall back to Windows's DPI configuration
                    var scaleVariable = Environment.GetEnvironmentVariable("OPENRA_DISPLAY_SCALE");
                    if (scaleVariable == null || !float.TryParse(scaleVariable, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out windowScale) || windowScale <= 0)
                    {
                        if (SDL.SDL_GetDisplayDPI(videoDisplay, out var ddpi, out _, out _) == 0)
                        {
                            windowScale = ddpi / 96;
                        }
                    }
                }
                else if (Platform.CurrentPlatform == PlatformType.Linux)
                {
                    // Launch the game with OPENRA_DISPLAY_SCALE to force a specific scaling factor
                    // Otherwise fall back to GDK_SCALE or parsing the x11 DPI configuration
                    var scaleVariable = Environment.GetEnvironmentVariable("OPENRA_DISPLAY_SCALE") ?? Environment.GetEnvironmentVariable("GDK_SCALE");
                    if (scaleVariable == null || !float.TryParse(scaleVariable, NumberStyles.Float, NumberFormatInfo.InvariantInfo, out windowScale) || windowScale <= 0)
                    {
                        // Attempt to automatically detect DPI
                        try
                        {
                            var psi = new ProcessStartInfo("/usr/bin/xrdb", "-query");
                            psi.UseShellExecute        = false;
                            psi.RedirectStandardOutput = true;
                            var p     = Process.Start(psi);
                            var lines = p.StandardOutput.ReadToEnd().Split('\n');

                            foreach (var line in lines)
                            {
                                if (line.StartsWith("Xft.dpi") && int.TryParse(line.Substring(8), out var dpi))
                                {
                                    windowScale = dpi / 96f;
                                }
                            }
                        }
                        catch { }
                    }
                }

                Console.WriteLine("Desktop resolution: {0}x{1}", display.w, display.h);
                if (requestEffectiveWindowSize.Width == 0 && requestEffectiveWindowSize.Height == 0)
                {
                    Console.WriteLine("No custom resolution provided, using desktop resolution");
                    surfaceSize = windowSize = new Size(display.w, display.h);
                }
                else
                {
                    surfaceSize = windowSize = new Size((int)(requestEffectiveWindowSize.Width * windowScale), (int)(requestEffectiveWindowSize.Height * windowScale));
                }

                Console.WriteLine("Using resolution: {0}x{1}", windowSize.Width, windowSize.Height);

                var windowFlags = SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL | SDL.SDL_WindowFlags.SDL_WINDOW_ALLOW_HIGHDPI;

                // HiDPI doesn't work properly on OSX with (legacy) fullscreen mode
                if (Platform.CurrentPlatform == PlatformType.OSX && windowMode == WindowMode.Fullscreen)
                {
                    SDL.SDL_SetHint(SDL.SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1");
                }

                window = SDL.SDL_CreateWindow("OpenRA", SDL.SDL_WINDOWPOS_CENTERED_DISPLAY(videoDisplay), SDL.SDL_WINDOWPOS_CENTERED_DISPLAY(videoDisplay),
                                              windowSize.Width, windowSize.Height, windowFlags);

                if (Platform.CurrentPlatform == PlatformType.Linux)
                {
                    // The KDE task switcher limits itself to the 128px icon unless we
                    // set an X11 _KDE_NET_WM_DESKTOP_FILE property on the window
                    var currentDesktop  = Environment.GetEnvironmentVariable("XDG_CURRENT_DESKTOP");
                    var desktopFilename = Environment.GetEnvironmentVariable("OPENRA_DESKTOP_FILENAME");
                    if (desktopFilename != null && currentDesktop == "KDE")
                    {
                        try
                        {
                            var info = default(SDL.SDL_SysWMinfo);
                            SDL.SDL_VERSION(out info.version);
                            SDL.SDL_GetWindowWMInfo(Window, ref info);

                            var d        = info.info.x11.display;
                            var w        = info.info.x11.window;
                            var property = XInternAtom(d, "_KDE_NET_WM_DESKTOP_FILE", false);
                            var type     = XInternAtom(d, "UTF8_STRING", false);

                            XChangeProperty(d, w, property, type, 8, IntPtr.Zero, desktopFilename, desktopFilename.Length + 1);
                            XFlush(d);
                        }
                        catch
                        {
                            Log.Write("debug", "Failed to set _KDE_NET_WM_DESKTOP_FILE");
                            Console.WriteLine("Failed to set _KDE_NET_WM_DESKTOP_FILE");
                        }
                    }
                }

                // Enable high resolution rendering for Retina displays
                if (Platform.CurrentPlatform == PlatformType.OSX)
                {
                    // OSX defines the window size in "points", with a device-dependent number of pixels per point.
                    // The window scale is simply the ratio of GL pixels / window points.
                    SDL.SDL_GL_GetDrawableSize(Window, out var width, out var height);
                    surfaceSize = new Size(width, height);
                    windowScale = width * 1f / windowSize.Width;
                }
                else
                {
                    windowSize = new Size((int)(surfaceSize.Width / windowScale), (int)(surfaceSize.Height / windowScale));
                }

                Console.WriteLine("Using window scale {0:F2}", windowScale);

                if (Game.Settings.Game.LockMouseWindow)
                {
                    GrabWindowMouseFocus();
                }
                else
                {
                    ReleaseWindowMouseFocus();
                }

                if (windowMode == WindowMode.Fullscreen)
                {
                    SDL.SDL_SetWindowFullscreen(Window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN);

                    // Fullscreen mode on OSX will ignore the configured display resolution
                    // and instead always picks an arbitrary scaled resolution choice that may
                    // not match the window size, leading to graphical and input issues.
                    // We work around this by force disabling HiDPI and resetting the window and
                    // surface sizes to match the size that is forced by SDL.
                    // This is usually not what the player wants, but is the best we can consistently do.
                    if (Platform.CurrentPlatform == PlatformType.OSX)
                    {
                        SDL.SDL_GetWindowSize(Window, out var width, out var height);
                        windowSize  = surfaceSize = new Size(width, height);
                        windowScale = 1;
                    }
                }
                else if (windowMode == WindowMode.PseudoFullscreen)
                {
                    SDL.SDL_SetWindowFullscreen(Window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP);
                    SDL.SDL_SetHint(SDL.SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
                }
            }

            // Run graphics rendering on a dedicated thread.
            // The calling thread will then have more time to process other tasks, since rendering happens in parallel.
            // If the calling thread is the main game thread, this means it can run more logic and render ticks.
            // This is disabled when running in windowed mode on Windows because it breaks the ability to minimize/restore the window.
            if (Platform.CurrentPlatform == PlatformType.Windows && windowMode == WindowMode.Windowed)
            {
                var ctx = new Sdl2GraphicsContext(this);
                ctx.InitializeOpenGL();
                context = ctx;
            }
            else
            {
                context = new ThreadedGraphicsContext(new Sdl2GraphicsContext(this), batchSize);
            }

            context.SetVSyncEnabled(Game.Settings.Graphics.VSync);

            SDL.SDL_SetModState(SDL.SDL_Keymod.KMOD_NONE);
            input = new Sdl2Input();
        }
        public Sdl2GraphicsDevice(Size windowSize, WindowMode windowMode)
        {
            Console.WriteLine("Using SDL 2 with OpenGL renderer");
            WindowSize = windowSize;

            SDL.SDL_Init(SDL.SDL_INIT_NOPARACHUTE | SDL.SDL_INIT_VIDEO);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_DOUBLEBUFFER, 1);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_RED_SIZE, 8);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_GREEN_SIZE, 8);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_BLUE_SIZE, 8);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_ALPHA_SIZE, 0);

            SDL.SDL_DisplayMode display;
            SDL.SDL_GetCurrentDisplayMode(0, out display);

            Console.WriteLine("Desktop resolution: {0}x{1}", display.w, display.h);
            if (WindowSize.Width == 0 && WindowSize.Height == 0)
            {
                Console.WriteLine("No custom resolution provided, using desktop resolution");
                WindowSize = new Size(display.w, display.h);
            }

            Console.WriteLine("Using resolution: {0}x{1}", WindowSize.Width, WindowSize.Height);

            window = SDL.SDL_CreateWindow("OpenRA", SDL.SDL_WINDOWPOS_CENTERED, SDL.SDL_WINDOWPOS_CENTERED,
                                          WindowSize.Width, WindowSize.Height, SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL);

            if (Game.Settings.Game.LockMouseWindow)
            {
                GrabWindowMouseFocus();
            }
            else
            {
                ReleaseWindowMouseFocus();
            }

            if (windowMode == WindowMode.Fullscreen)
            {
                SDL.SDL_SetWindowFullscreen(window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN);
            }
            else if (windowMode == WindowMode.PseudoFullscreen)
            {
                // Work around a visual glitch in OSX: the window is offset
                // partially offscreen if the dock is at the left of the screen
                if (Platform.CurrentPlatform == PlatformType.OSX)
                {
                    SDL.SDL_SetWindowPosition(window, 0, 0);
                }

                SDL.SDL_SetWindowFullscreen(window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP);
                SDL.SDL_SetHint(SDL.SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
            }

            context = SDL.SDL_GL_CreateContext(window);
            if (context == IntPtr.Zero || SDL.SDL_GL_MakeCurrent(window, context) < 0)
            {
                throw new InvalidOperationException("Can not create OpenGL context. (Error: {0})".F(SDL.SDL_GetError()));
            }

            OpenGL.Initialize();

            OpenGL.glEnableVertexAttribArray(Shader.VertexPosAttributeIndex);
            OpenGL.CheckGLError();
            OpenGL.glEnableVertexAttribArray(Shader.TexCoordAttributeIndex);
            OpenGL.CheckGLError();
            OpenGL.glEnableVertexAttribArray(Shader.TexMetadataAttributeIndex);
            OpenGL.CheckGLError();

            SDL.SDL_SetModState(SDL.SDL_Keymod.KMOD_NONE);
            input = new Sdl2Input();
        }
Esempio n. 3
0
        public Sdl2PlatformWindow(Size requestWindowSize, WindowMode windowMode, int batchSize)
        {
            Console.WriteLine("Using SDL 2 with OpenGL renderer");

            // Lock the Window/Surface properties until initialization is complete
            lock (syncObject)
            {
                windowSize = requestWindowSize;

                // Disable legacy scaling on Windows
                if (Platform.CurrentPlatform == PlatformType.Windows && !Game.Settings.Graphics.DisableWindowsDPIScaling)
                {
                    SetProcessDPIAware();
                }

                SDL.SDL_Init(SDL.SDL_INIT_NOPARACHUTE | SDL.SDL_INIT_VIDEO);
                SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_DOUBLEBUFFER, 1);
                SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_RED_SIZE, 8);
                SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_GREEN_SIZE, 8);
                SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_BLUE_SIZE, 8);
                SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_ALPHA_SIZE, 0);

                SDL.SDL_DisplayMode display;
                SDL.SDL_GetCurrentDisplayMode(0, out display);

                Console.WriteLine("Desktop resolution: {0}x{1}", display.w, display.h);
                if (windowSize.Width == 0 && windowSize.Height == 0)
                {
                    Console.WriteLine("No custom resolution provided, using desktop resolution");
                    windowSize = new Size(display.w, display.h);
                }

                Console.WriteLine("Using resolution: {0}x{1}", windowSize.Width, windowSize.Height);

                var windowFlags = SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL | SDL.SDL_WindowFlags.SDL_WINDOW_ALLOW_HIGHDPI;

                // HiDPI doesn't work properly on OSX with (legacy) fullscreen mode
                if (Platform.CurrentPlatform == PlatformType.OSX && windowMode == WindowMode.Fullscreen)
                {
                    SDL.SDL_SetHint(SDL.SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1");
                }

                window = SDL.SDL_CreateWindow("OpenRA", SDL.SDL_WINDOWPOS_CENTERED, SDL.SDL_WINDOWPOS_CENTERED,
                                              windowSize.Width, windowSize.Height, windowFlags);

                surfaceSize = windowSize;
                windowScale = 1;

                // Enable high resolution rendering for Retina displays
                if (Platform.CurrentPlatform == PlatformType.OSX)
                {
                    // OSX defines the window size in "points", with a device-dependent number of pixels per point.
                    // The window scale is simply the ratio of GL pixels / window points.
                    int width, height;

                    SDL.SDL_GL_GetDrawableSize(Window, out width, out height);
                    surfaceSize = new Size(width, height);
                    windowScale = width * 1f / windowSize.Width;
                }
                else if (Platform.CurrentPlatform == PlatformType.Windows)
                {
                    float ddpi, hdpi, vdpi;
                    if (!Game.Settings.Graphics.DisableWindowsDPIScaling && SDL.SDL_GetDisplayDPI(0, out ddpi, out hdpi, out vdpi) == 0)
                    {
                        windowScale = ddpi / 96;
                        windowSize  = new Size((int)(surfaceSize.Width / windowScale), (int)(surfaceSize.Height / windowScale));
                    }
                }
                else
                {
                    float scale         = 1;
                    var   scaleVariable = Environment.GetEnvironmentVariable("OPENRA_DISPLAY_SCALE");
                    if (scaleVariable != null && float.TryParse(scaleVariable, out scale))
                    {
                        windowScale = scale;
                        windowSize  = new Size((int)(surfaceSize.Width / windowScale), (int)(surfaceSize.Height / windowScale));
                    }
                }

                Console.WriteLine("Using window scale {0:F2}", windowScale);

                if (Game.Settings.Game.LockMouseWindow)
                {
                    GrabWindowMouseFocus();
                }
                else
                {
                    ReleaseWindowMouseFocus();
                }

                if (windowMode == WindowMode.Fullscreen)
                {
                    SDL.SDL_SetWindowFullscreen(Window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN);

                    // Fullscreen mode on OSX will ignore the configured display resolution
                    // and instead always picks an arbitrary scaled resolution choice that may
                    // not match the window size, leading to graphical and input issues.
                    // We work around this by force disabling HiDPI and resetting the window and
                    // surface sizes to match the size that is forced by SDL.
                    // This is usually not what the player wants, but is the best we can consistently do.
                    if (Platform.CurrentPlatform == PlatformType.OSX)
                    {
                        int width, height;
                        SDL.SDL_GetWindowSize(Window, out width, out height);
                        windowSize  = surfaceSize = new Size(width, height);
                        windowScale = 1;
                    }
                }
                else if (windowMode == WindowMode.PseudoFullscreen)
                {
                    // Work around a visual glitch in OSX: the window is offset
                    // partially offscreen if the dock is at the left of the screen
                    if (Platform.CurrentPlatform == PlatformType.OSX)
                    {
                        SDL.SDL_SetWindowPosition(Window, 0, 0);
                    }

                    SDL.SDL_SetWindowFullscreen(Window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP);
                    SDL.SDL_SetHint(SDL.SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
                }
            }

            // Run graphics rendering on a dedicated thread.
            // The calling thread will then have more time to process other tasks, since rendering happens in parallel.
            // If the calling thread is the main game thread, this means it can run more logic and render ticks.
            context = new ThreadedGraphicsContext(new Sdl2GraphicsContext(this), batchSize);

            SDL.SDL_SetModState(SDL.SDL_Keymod.KMOD_NONE);
            input = new Sdl2Input();
        }
Esempio n. 4
0
        public Sdl2GraphicsDevice(Size windowSize, WindowMode windowMode)
        {
            Console.WriteLine("Using SDL 2 with OpenGL renderer");
            WindowSize = windowSize;

            // Disable legacy scaling on Windows
            if (Platform.CurrentPlatform == PlatformType.Windows && !Game.Settings.Graphics.DisableWindowsDPIScaling)
            {
                SetProcessDPIAware();
            }

            SDL.SDL_Init(SDL.SDL_INIT_NOPARACHUTE | SDL.SDL_INIT_VIDEO);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_DOUBLEBUFFER, 1);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_RED_SIZE, 8);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_GREEN_SIZE, 8);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_BLUE_SIZE, 8);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_ALPHA_SIZE, 0);

            SDL.SDL_DisplayMode display;
            SDL.SDL_GetCurrentDisplayMode(0, out display);

            Console.WriteLine("Desktop resolution: {0}x{1}", display.w, display.h);
            if (WindowSize.Width == 0 && WindowSize.Height == 0)
            {
                Console.WriteLine("No custom resolution provided, using desktop resolution");
                WindowSize = new Size(display.w, display.h);
            }

            Console.WriteLine("Using resolution: {0}x{1}", WindowSize.Width, WindowSize.Height);

            var windowFlags = SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL | SDL.SDL_WindowFlags.SDL_WINDOW_ALLOW_HIGHDPI;

            window = SDL.SDL_CreateWindow("OpenRA", SDL.SDL_WINDOWPOS_CENTERED, SDL.SDL_WINDOWPOS_CENTERED,
                                          WindowSize.Width, WindowSize.Height, windowFlags);

            SurfaceSize = WindowSize;
            WindowScale = 1;

            // Enable high resolution rendering for Retina displays
            if (Platform.CurrentPlatform == PlatformType.OSX)
            {
                // OSX defines the window size in "points", with a device-dependent number of pixels per point.
                // The window scale is simply the ratio of GL pixels / window points.
                int width, height;
                SDL.SDL_GL_GetDrawableSize(window, out width, out height);
                SurfaceSize = new Size(width, height);
                WindowScale = width * 1f / WindowSize.Width;
            }
            else if (Platform.CurrentPlatform == PlatformType.Windows)
            {
                float ddpi, hdpi, vdpi;
                if (!Game.Settings.Graphics.DisableWindowsDPIScaling && SDL.SDL_GetDisplayDPI(0, out ddpi, out hdpi, out vdpi) == 0)
                {
                    WindowScale = ddpi / 96;
                    WindowSize  = new Size((int)(SurfaceSize.Width / WindowScale), (int)(SurfaceSize.Height / WindowScale));
                }
            }
            else
            {
                float scale         = 1;
                var   scaleVariable = Environment.GetEnvironmentVariable("OPENRA_DISPLAY_SCALE");
                if (scaleVariable != null && float.TryParse(scaleVariable, out scale))
                {
                    WindowScale = scale;
                    WindowSize  = new Size((int)(SurfaceSize.Width / WindowScale), (int)(SurfaceSize.Height / WindowScale));
                }
            }

            Console.WriteLine("Using window scale {0:F2}", WindowScale);

            if (Game.Settings.Game.LockMouseWindow)
            {
                GrabWindowMouseFocus();
            }
            else
            {
                ReleaseWindowMouseFocus();
            }

            if (windowMode == WindowMode.Fullscreen)
            {
                SDL.SDL_SetWindowFullscreen(window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN);
            }
            else if (windowMode == WindowMode.PseudoFullscreen)
            {
                // Work around a visual glitch in OSX: the window is offset
                // partially offscreen if the dock is at the left of the screen
                if (Platform.CurrentPlatform == PlatformType.OSX)
                {
                    SDL.SDL_SetWindowPosition(window, 0, 0);
                }

                SDL.SDL_SetWindowFullscreen(window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP);
                SDL.SDL_SetHint(SDL.SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
            }

            context = SDL.SDL_GL_CreateContext(window);
            if (context == IntPtr.Zero || SDL.SDL_GL_MakeCurrent(window, context) < 0)
            {
                throw new InvalidOperationException("Can not create OpenGL context. (Error: {0})".F(SDL.SDL_GetError()));
            }

            OpenGL.Initialize();

            OpenGL.glEnableVertexAttribArray(Shader.VertexPosAttributeIndex);
            OpenGL.CheckGLError();
            OpenGL.glEnableVertexAttribArray(Shader.TexCoordAttributeIndex);
            OpenGL.CheckGLError();
            OpenGL.glEnableVertexAttribArray(Shader.TexMetadataAttributeIndex);
            OpenGL.CheckGLError();

            SDL.SDL_SetModState(SDL.SDL_Keymod.KMOD_NONE);
            input = new Sdl2Input();
        }
Esempio n. 5
0
		public Sdl2GraphicsDevice(Size windowSize, WindowMode windowMode)
		{
			Console.WriteLine("Using SDL 2 with OpenGL renderer");
			WindowSize = windowSize;

			SDL.SDL_Init(SDL.SDL_INIT_NOPARACHUTE | SDL.SDL_INIT_VIDEO);
			SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_DOUBLEBUFFER, 1);
			SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_RED_SIZE, 8);
			SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_GREEN_SIZE, 8);
			SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_BLUE_SIZE, 8);
			SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_ALPHA_SIZE, 0);

			SDL.SDL_DisplayMode display;
			SDL.SDL_GetCurrentDisplayMode(0, out display);

			Console.WriteLine("Desktop resolution: {0}x{1}", display.w, display.h);
			if (WindowSize.Width == 0 && WindowSize.Height == 0)
			{
				Console.WriteLine("No custom resolution provided, using desktop resolution");
				WindowSize = new Size(display.w, display.h);
			}

			Console.WriteLine("Using resolution: {0}x{1}", WindowSize.Width, WindowSize.Height);

			window = SDL.SDL_CreateWindow("OpenRA", SDL.SDL_WINDOWPOS_CENTERED, SDL.SDL_WINDOWPOS_CENTERED,
				WindowSize.Width, WindowSize.Height, SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL);

			if (Game.Settings.Game.LockMouseWindow)
				GrabWindowMouseFocus();
			else
				ReleaseWindowMouseFocus();

			if (windowMode == WindowMode.Fullscreen)
				SDL.SDL_SetWindowFullscreen(window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN);
			else if (windowMode == WindowMode.PseudoFullscreen)
			{
				// Work around a visual glitch in OSX: the window is offset
				// partially offscreen if the dock is at the left of the screen
				if (Platform.CurrentPlatform == PlatformType.OSX)
					SDL.SDL_SetWindowPosition(window, 0, 0);

				SDL.SDL_SetWindowFullscreen(window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP);
				SDL.SDL_SetHint(SDL.SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
			}

			context = SDL.SDL_GL_CreateContext(window);
			if (context == IntPtr.Zero || SDL.SDL_GL_MakeCurrent(window, context) < 0)
				throw new InvalidOperationException("Can not create OpenGL context. (Error: {0})".F(SDL.SDL_GetError()));

			GraphicsContext.CurrentContext = context;

			GL.LoadAll();
			ErrorHandler.CheckGlVersion();
			ErrorHandler.CheckGlError();

			if (SDL.SDL_GL_ExtensionSupported("GL_EXT_framebuffer_object") == SDL.SDL_bool.SDL_FALSE)
			{
				ErrorHandler.WriteGraphicsLog("OpenRA requires the OpenGL extension GL_EXT_framebuffer_object.\n"
					+ "Please try updating your GPU driver to the latest version provided by the manufacturer.");
				throw new InvalidProgramException("Missing OpenGL extension GL_EXT_framebuffer_object. See graphics.log for details.");
			}

			GL.EnableClientState(ArrayCap.VertexArray);
			ErrorHandler.CheckGlError();
			GL.EnableClientState(ArrayCap.TextureCoordArray);
			ErrorHandler.CheckGlError();

			SDL.SDL_SetModState(SDL.SDL_Keymod.KMOD_NONE);
			input = new Sdl2Input();
		}
Esempio n. 6
0
        public Sdl2GraphicsDevice(Size windowSize, WindowMode windowMode)
        {
            Console.WriteLine("Using SDL 2 with OpenGL renderer");
            WindowSize = windowSize;

            SDL.SDL_Init(SDL.SDL_INIT_NOPARACHUTE | SDL.SDL_INIT_VIDEO);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_DOUBLEBUFFER, 1);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_RED_SIZE, 8);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_GREEN_SIZE, 8);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_BLUE_SIZE, 8);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_ALPHA_SIZE, 0);

            SDL.SDL_DisplayMode display;
            SDL.SDL_GetCurrentDisplayMode(0, out display);

            Console.WriteLine("Desktop resolution: {0}x{1}", display.w, display.h);
            if (WindowSize.Width == 0 && WindowSize.Height == 0)
            {
                Console.WriteLine("No custom resolution provided, using desktop resolution");
                WindowSize = new Size(display.w, display.h);
            }

            Console.WriteLine("Using resolution: {0}x{1}", WindowSize.Width, WindowSize.Height);

            window = SDL.SDL_CreateWindow("OpenRA", SDL.SDL_WINDOWPOS_CENTERED, SDL.SDL_WINDOWPOS_CENTERED,
                WindowSize.Width, WindowSize.Height, SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL);

            if (Game.Settings.Game.LockMouseWindow)
                GrabWindowMouseFocus();
            else
                ReleaseWindowMouseFocus();

            if (windowMode == WindowMode.Fullscreen)
                SDL.SDL_SetWindowFullscreen(window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN);
            else if (windowMode == WindowMode.PseudoFullscreen)
            {
                // Work around a visual glitch in OSX: the window is offset
                // partially offscreen if the dock is at the left of the screen
                if (Platform.CurrentPlatform == PlatformType.OSX)
                    SDL.SDL_SetWindowPosition(window, 0, 0);

                SDL.SDL_SetWindowFullscreen(window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP);
                SDL.SDL_SetHint(SDL.SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
            }

            context = SDL.SDL_GL_CreateContext(window);
            if (context == IntPtr.Zero || SDL.SDL_GL_MakeCurrent(window, context) < 0)
                throw new InvalidOperationException("Can not create OpenGL context. (Error: {0})".F(SDL.SDL_GetError()));

            OpenGL.Initialize();

            OpenGL.glEnableVertexAttribArray(Shader.VertexPosAttributeIndex);
            OpenGL.CheckGLError();
            OpenGL.glEnableVertexAttribArray(Shader.TexCoordAttributeIndex);
            OpenGL.CheckGLError();

            SDL.SDL_SetModState(SDL.SDL_Keymod.KMOD_NONE);
            input = new Sdl2Input();
        }
Esempio n. 7
0
        public Sdl2PlatformWindow(Size requestWindowSize, WindowMode windowMode, int batchSize)
        {
            // Lock the Window/Surface properties until initialization is complete
            lock (syncObject)
            {
                windowSize = requestWindowSize;

                // Disable legacy scaling on Windows
                if (Platform.CurrentPlatform == PlatformType.Windows && !Game.Settings.Graphics.DisableWindowsDPIScaling)
                {
                    SetProcessDPIAware();
                }

                SDL.SDL_Init(SDL.SDL_INIT_NOPARACHUTE | SDL.SDL_INIT_VIDEO);
                SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_DOUBLEBUFFER, 1);
                SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_RED_SIZE, 8);
                SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_GREEN_SIZE, 8);
                SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_BLUE_SIZE, 8);
                SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_ALPHA_SIZE, 0);

                // Decide between OpenGL and OpenGL ES rendering
                // Test whether we can use the preferred renderer and fall back to the other if that fails
                // If neither works we will throw a graphics error later when trying to create the real window
                bool useGLES;
                if (Game.Settings.Graphics.PreferGLES)
                {
                    useGLES = CanCreateGLWindow(3, 0, SDL.SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_ES);
                }
                else
                {
                    useGLES = !CanCreateGLWindow(3, 2, SDL.SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_CORE);
                }

                var glMajor   = 3;
                var glMinor   = useGLES ? 0 : 2;
                var glProfile = useGLES ? SDL.SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_ES : SDL.SDL_GLprofile.SDL_GL_CONTEXT_PROFILE_CORE;

                SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MAJOR_VERSION, glMajor);
                SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_MINOR_VERSION, glMinor);
                SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_CONTEXT_PROFILE_MASK, (int)glProfile);

                Console.WriteLine("Using SDL 2 with OpenGL{0} renderer", useGLES ? " ES" : "");

                SDL.SDL_DisplayMode display;
                SDL.SDL_GetCurrentDisplayMode(0, out display);

                Console.WriteLine("Desktop resolution: {0}x{1}", display.w, display.h);
                if (windowSize.Width == 0 && windowSize.Height == 0)
                {
                    Console.WriteLine("No custom resolution provided, using desktop resolution");
                    windowSize = new Size(display.w, display.h);
                }

                Console.WriteLine("Using resolution: {0}x{1}", windowSize.Width, windowSize.Height);

                var windowFlags = SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL | SDL.SDL_WindowFlags.SDL_WINDOW_ALLOW_HIGHDPI;

                // HiDPI doesn't work properly on OSX with (legacy) fullscreen mode
                if (Platform.CurrentPlatform == PlatformType.OSX && windowMode == WindowMode.Fullscreen)
                {
                    SDL.SDL_SetHint(SDL.SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1");
                }

                window = SDL.SDL_CreateWindow("OpenRA", SDL.SDL_WINDOWPOS_CENTERED, SDL.SDL_WINDOWPOS_CENTERED,
                                              windowSize.Width, windowSize.Height, windowFlags);

                // Work around an issue in macOS's GL backend where the window remains permanently black
                // (if dark mode is enabled) unless we drain the event queue before initializing GL
                if (Platform.CurrentPlatform == PlatformType.OSX)
                {
                    SDL.SDL_Event e;
                    while (SDL.SDL_PollEvent(out e) != 0)
                    {
                        // We can safely ignore all mouse/keyboard events and window size changes
                        // (these will be caught in the window setup below), but do need to process focus
                        if (e.type == SDL.SDL_EventType.SDL_WINDOWEVENT)
                        {
                            switch (e.window.windowEvent)
                            {
                            case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_LOST:
                                Game.HasInputFocus = false;
                                break;

                            case SDL.SDL_WindowEventID.SDL_WINDOWEVENT_FOCUS_GAINED:
                                Game.HasInputFocus = true;
                                break;
                            }
                        }
                    }
                }

                surfaceSize = windowSize;
                windowScale = 1;

                // Enable high resolution rendering for Retina displays
                if (Platform.CurrentPlatform == PlatformType.OSX)
                {
                    // OSX defines the window size in "points", with a device-dependent number of pixels per point.
                    // The window scale is simply the ratio of GL pixels / window points.
                    int width, height;

                    SDL.SDL_GL_GetDrawableSize(Window, out width, out height);
                    surfaceSize = new Size(width, height);
                    windowScale = width * 1f / windowSize.Width;
                }
                else if (Platform.CurrentPlatform == PlatformType.Windows)
                {
                    float ddpi, hdpi, vdpi;
                    if (!Game.Settings.Graphics.DisableWindowsDPIScaling && SDL.SDL_GetDisplayDPI(0, out ddpi, out hdpi, out vdpi) == 0)
                    {
                        windowScale = ddpi / 96;
                        windowSize  = new Size((int)(surfaceSize.Width / windowScale), (int)(surfaceSize.Height / windowScale));
                    }
                }
                else
                {
                    float scale         = 1;
                    var   scaleVariable = Environment.GetEnvironmentVariable("OPENRA_DISPLAY_SCALE");
                    if (scaleVariable != null && float.TryParse(scaleVariable, out scale))
                    {
                        windowScale = scale;
                        windowSize  = new Size((int)(surfaceSize.Width / windowScale), (int)(surfaceSize.Height / windowScale));
                    }
                }

                Console.WriteLine("Using window scale {0:F2}", windowScale);

                if (Game.Settings.Game.LockMouseWindow)
                {
                    GrabWindowMouseFocus();
                }
                else
                {
                    ReleaseWindowMouseFocus();
                }

                if (windowMode == WindowMode.Fullscreen)
                {
                    SDL.SDL_SetWindowFullscreen(Window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN);

                    // Fullscreen mode on OSX will ignore the configured display resolution
                    // and instead always picks an arbitrary scaled resolution choice that may
                    // not match the window size, leading to graphical and input issues.
                    // We work around this by force disabling HiDPI and resetting the window and
                    // surface sizes to match the size that is forced by SDL.
                    // This is usually not what the player wants, but is the best we can consistently do.
                    if (Platform.CurrentPlatform == PlatformType.OSX)
                    {
                        int width, height;
                        SDL.SDL_GetWindowSize(Window, out width, out height);
                        windowSize  = surfaceSize = new Size(width, height);
                        windowScale = 1;
                    }
                }
                else if (windowMode == WindowMode.PseudoFullscreen)
                {
                    // Work around a visual glitch in OSX: the window is offset
                    // partially offscreen if the dock is at the left of the screen
                    if (Platform.CurrentPlatform == PlatformType.OSX)
                    {
                        SDL.SDL_SetWindowPosition(Window, 0, 0);
                    }

                    SDL.SDL_SetWindowFullscreen(Window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP);
                    SDL.SDL_SetHint(SDL.SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
                }
            }

            // Run graphics rendering on a dedicated thread.
            // The calling thread will then have more time to process other tasks, since rendering happens in parallel.
            // If the calling thread is the main game thread, this means it can run more logic and render ticks.
            // This is disabled on Windows because it breaks the ability to minimize/restore the window from the taskbar for reasons that we dont understand.
            var threadedRenderer = Platform.CurrentPlatform != PlatformType.Windows || !Game.Settings.Graphics.DisableWindowsRenderThread;

            if (!threadedRenderer)
            {
                var ctx = new Sdl2GraphicsContext(this);
                ctx.InitializeOpenGL();
                context = ctx;
            }
            else
            {
                context = new ThreadedGraphicsContext(new Sdl2GraphicsContext(this), batchSize);
            }

            SDL.SDL_SetModState(SDL.SDL_Keymod.KMOD_NONE);
            input = new Sdl2Input();
        }
Esempio n. 8
0
        public Sdl2GraphicsDevice(Size windowSize, WindowMode windowMode)
        {
            Console.WriteLine("Using SDL 2 with OpenGL renderer");
            WindowSize = windowSize;

            SDL.SDL_Init(SDL.SDL_INIT_NOPARACHUTE | SDL.SDL_INIT_VIDEO);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_DOUBLEBUFFER, 1);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_RED_SIZE, 8);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_GREEN_SIZE, 8);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_BLUE_SIZE, 8);
            SDL.SDL_GL_SetAttribute(SDL.SDL_GLattr.SDL_GL_ALPHA_SIZE, 0);

            SDL.SDL_DisplayMode display;
            SDL.SDL_GetCurrentDisplayMode(0, out display);

            Console.WriteLine("Desktop resolution: {0}x{1}", display.w, display.h);
            if (WindowSize.Width == 0 && WindowSize.Height == 0)
            {
                Console.WriteLine("No custom resolution provided, using desktop resolution");
                WindowSize = new Size(display.w, display.h);
            }

            Console.WriteLine("Using resolution: {0}x{1}", WindowSize.Width, WindowSize.Height);

            window = SDL.SDL_CreateWindow("OpenRA", SDL.SDL_WINDOWPOS_CENTERED, SDL.SDL_WINDOWPOS_CENTERED,
                                          WindowSize.Width, WindowSize.Height, SDL.SDL_WindowFlags.SDL_WINDOW_OPENGL);

            if (Game.Settings.Game.LockMouseWindow)
            {
                GrabWindowMouseFocus();
            }
            else
            {
                ReleaseWindowMouseFocus();
            }

            if (windowMode == WindowMode.Fullscreen)
            {
                SDL.SDL_SetWindowFullscreen(window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN);
            }
            else if (windowMode == WindowMode.PseudoFullscreen)
            {
                // Work around a visual glitch in OSX: the window is offset
                // partially offscreen if the dock is at the left of the screen
                if (Platform.CurrentPlatform == PlatformType.OSX)
                {
                    SDL.SDL_SetWindowPosition(window, 0, 0);
                }

                SDL.SDL_SetWindowFullscreen(window, (uint)SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP);
                SDL.SDL_SetHint(SDL.SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
            }

            context = SDL.SDL_GL_CreateContext(window);
            if (context == IntPtr.Zero || SDL.SDL_GL_MakeCurrent(window, context) < 0)
            {
                throw new InvalidOperationException("Can not create OpenGL context. (Error: {0})".F(SDL.SDL_GetError()));
            }

            GraphicsContext.CurrentContext = context;

            GL.LoadAll();
            ErrorHandler.CheckGlVersion();
            ErrorHandler.CheckGlError();

            if (SDL.SDL_GL_ExtensionSupported("GL_EXT_framebuffer_object") == SDL.SDL_bool.SDL_FALSE)
            {
                ErrorHandler.WriteGraphicsLog("OpenRA requires the OpenGL extension GL_EXT_framebuffer_object.\n"
                                              + "Please try updating your GPU driver to the latest version provided by the manufacturer.");
                throw new InvalidProgramException("Missing OpenGL extension GL_EXT_framebuffer_object. See graphics.log for details.");
            }

            GL.EnableClientState(ArrayCap.VertexArray);
            ErrorHandler.CheckGlError();
            GL.EnableClientState(ArrayCap.TextureCoordArray);
            ErrorHandler.CheckGlError();

            SDL.SDL_SetModState(SDL.SDL_Keymod.KMOD_NONE);
            input = new Sdl2Input();
        }