2
\$\begingroup\$

I've been trying to figure out the correct method for changing the resolution/fullscreen state of a GLFW window for a while now, but after searching all I found were references of how to do it with older versions of the library such as this. I suspect you'd just destroy the window object and re-create it, but was not sure because of how some functions such as glfwSetKeyCallback take a GLFWwindow* as a parameter, and I don't know if that'd continue to work after it has been re-created. The documentation also does not have any examples on doing such a thing, so any help would be appreciated.

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

To the best of my knowledge, still there isn't a function to toggle between windowed and fullscreen modes. Here is the listing of all functions provided by the library at the current version. Such feature might be added in the future though, if enough requests for it pop up.

However, the window and the OpenGL context are two tightly coupled things, so changing window and video modes like this tends to be complicated and prone to different behaviors (and bugs!) on different systems and implementation of the GL. Perhaps that is why the library is steering clear of these issues.

My advice here would be to do as proposed in the link you've shared: Destroy the current window and create a new fullscreen one with proper video mode. AFAIK, this is how most games that allow this switching do it anyway.

You will have to recreate all GPU related resources too, like textures, buffers and shaders, so plan your code accordingly. Perhaps you might want to have a pair of onContextLost()/onContextRecovered() methods on your resource objects that recreate the OpenGL handles once such window destruction/re-creation happens. With GLFW, the safest approach would be to also fully shutdown and re-initialize the library, providing fresh callbacks to it. Again, this is not a big issue if you plan your code in a way to facilitate this rebooting. If you have a Window object of sorts that wraps GLFW, that would be just a matter of destroying the current and creating a new one.

\$\endgroup\$
0
\$\begingroup\$

You are correct that you cannot take the same window with the same GL context and change between fullscreen and windowed.

What I have done is set up my rendering system (and input, etc...) to generically set itself up, and extended that slightly to allow it to re-set itself up without leaking memory. So when the application first launches, everything is loaded and the setup functions are called. Then, if I swap between full-screen and windowed, I just issue another system-wide setup. All the objects maintain their current data (location, orientation, logic time, etc...) they just rebind themselves to the window's context.

It takes a bit of thought up front, but then once it's done everything "just works" as you add new features or object types or whatever into this paradigm. Here is the relevant code from my project:

void Engine::ToggleFullscreen()
{
    bool wasFullscreen = glfwGetWindowMonitor(_window) != nullptr;
    glfwDestroyWindow(_window);

    if (wasFullscreen)
    {
        CreateWindow(false);
    }
    else {
        CreateWindow(true);
    }

    Shaders::RequireRebindAll();

    for (unique_ptr<Scene> &s : _scenes)
    {
        s->RebindObjectsToCurrentContext();

        int w, h;
        glfwGetWindowSize(_window, &w, &h);
        s->ResizeView(w, h);
    }
}

// Private member functions
void Engine::CreateWindow(bool goFullscreen)
{
    GLFWmonitor* monitor = NULL;
    int width = 1280;
    int height = 720;

    if (goFullscreen)
    {
        // actually, try to get the second monitor if there is one, otherwise the primary
        int mon_count = -1;
        GLFWmonitor **mon_list = glfwGetMonitors(&mon_count);

        assert(mon_count > 0);
        if (mon_count > 1)
        {
            monitor = mon_list[1];
        }
        else {
            monitor = mon_list[0];
        }

        width = glfwGetVideoMode(monitor)->width;
        height = glfwGetVideoMode(monitor)->height;
    }

    _window = glfwCreateWindow(width, height, "TEST Windoh", monitor, NULL);
    if (!_window)
    {
        throw "unable to create glfw window";
    }

    glfwSetWindowSizeCallback(_window, &Engine::ViewResized);

    glfwMakeContextCurrent(_window);
    glfwSwapInterval(0);

    glEnable(GL_SCISSOR_TEST);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);

    // glew must be initialized AFTER there is a working gl context
    GLenum err = glewInit();
    if (err != GLEW_OK)
    {
        cout << "Error loading glew: " << glewGetErrorString(err);
    }
}

The function ToggleFullscreen is called by the key command to switch for now, but you could attach it to a UI callback or whatever else you wanted.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .