Search code examples
c#openglfullscreenopentk

Setting my GameWindow to fullscreen will stretch it to the desktop resolution


Setting my GameWindow to fullscreen stretches it, how do I set it fullscreen without losing the original window resolution with the use of black bars?

This is my code:

using System;
using System.Collections.Generic;
using System.Text;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.GraphicsLibraryFramework;
using OpenTK.Windowing.Desktop;
using System.Drawing;

namespace OnlineGame
{
    public class Game : GameWindow
    {
        public Game(GameWindowSettings gameWindowSettings, NativeWindowSettings nativeWindowSettings)
             : base(gameWindowSettings, nativeWindowSettings)
        {
            WindowState = WindowState.Fullscreen;
        }

        protected override void OnUpdateFrame(FrameEventArgs e)
        {
            if (KeyboardState.IsKeyDown(Keys.Escape))
            {
                Close();
            }

            base.OnUpdateFrame(e);

            GL.Clear(ClearBufferMask.ColorBufferBit);
            GL.ClearColor(Color.CornflowerBlue);

            this.SwapBuffers();
        }
    }
}

Solution

  • Use GL.Viewport to set the viewport rectangle to a sub-area of the window. "Copy" operations as GL.Clear are not affected by the rectangle of the viewport. Therefore, you also need to set a Scissors Test.

    You need to know the current size of the window (current_w, current_h) and the original size of the window (original_w, original_h). Compute the aspect ration of the current window (current_aspect) and the aspect ratio of the original window (original_aspect):

    double current_aspect = (double)current_w / current_h;
    double original_aspect = (double)original_w / original_h;
    

    Compute the sub-area and set the viewport and scissor rectnagle:

    int w = (int)(current_w * original_aspect / current_aspect);
    int x = (current_w - w) / 2;
    GL.Scissor(x, 0, w, this.Size.Y);
    GL.Viewport(x, 0, w, this.Size.Y);
    

    Clear the entire window with the black color. Then restrict the viewport rectangle and enable the scissors test.
    Note you must set the clear color (GL.ClearColor) before the GL.Clear instruction.

    protected override void OnUpdateFrame(FrameEventArgs e)
    {
        if (KeyboardState.IsKeyDown(Keys.Escape))
        {
            Close();
        }
    
        base.OnUpdateFrame(e);
    
        int original_w = ...;
        int original_h = ...;
        int current_w = this.Size.X;
        int current_h = this.Size.Y;
        double current_aspect = (double)current_w / current_h;
        double original_aspect = (double)original_w / original_h;
    
        GL.Disable(EnableCap.ScissorTest);
        GL.Viewport(0, 0, current_w, current_h);
        GL.ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        GL.Clear(ClearBufferMask.ColorBufferBit);
    
        GL.Enable(EnableCap.ScissorTest);
        if (current_aspect > original_aspect)
        {
            int w = (int)(current_w * original_aspect / current_aspect);
            int x = (current_w - w) / 2;
            GL.Scissor(x, 0, w, this.Size.Y);
            GL.Viewport(x, 0, w, this.Size.Y);
        }
        else
        {
            int h = (int)(current_h * current_aspect / original_aspect);
            int y = (current_h - h) / 2;
            GL.Scissor(0, y, this.Size.X, h);
            GL.Viewport(0, y, this.Size.X, h);
        }
        
        GL.ClearColor(Color.CornflowerBlue);
        GL.Clear(ClearBufferMask.ColorBufferBit);
    
        // [...]    
    
        this.SwapBuffers();
    }