Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SDL2: How to keep aspect ratio when resizing the window

Tags:

c++

linux

sdl

sdl-2

I am trying to create a SDL window which keeps its aspect ratio when resize event happens. If user widens the window, the height is increased and vice versa. I catch the SDL_WINDOWEVENT_RESIZED event, calculate new width or height which maintains the aspect ratio and then call SDL_SetWindowSize() with calculated values.

The problem is that calling the SDL_SetWindowSize() function inside the event polling loop does nothing on the screen. SDL does update the window size variables (calling SDL_GetWindowSize() in my main loop returns the updated window dimensions). However, the actual window is not updated.

The only way I can get this to work is to call constantly SDL_SetWindowSize() in the main loop, but I think that is the wrong way of doing things. The code below illustrates my problem. Is there a better and cleaner way to get this to work?

I am using SDL 2.0.3 and 64-bit Ubuntu Linux with GNOME desktop.

#include <SDL2/SDL.h>

static const float ASPECT_RATIO = 16.f/9.f;

SDL_Window* window;
SDL_Renderer* renderer;

uint32_t windowID;
SDL_Rect screen;
bool done = false;
bool resizeDone = false;

void handle_events()
{
    SDL_Event e;
    while (SDL_PollEvent(&e)) {
        switch (e.type) {

        case SDL_WINDOWEVENT: 
            if(e.window.windowID == windowID) {
                switch(e.window.event) {
                    case SDL_WINDOWEVENT_RESIZED: { 
                        int width = e.window.data1;
                        int height = e.window.data2;
                        float aspectRatio = (float)width/(float)height;

                        if(aspectRatio != ASPECT_RATIO) {
                            if(aspectRatio > ASPECT_RATIO) {
                                height = (1.f / ASPECT_RATIO) * width; 
                            }
                            else {
                                width = ASPECT_RATIO * height; 
                            }

                            printf("Setting window size to %d, %d, aspect ratio: %f\n", 
                                width, height, (float)width/(float)height);
                    }
                    screen.w = width;
                    screen.h = height; 

                    SDL_SetWindowSize(window, width, height); // <-- does not work
                    resizeDone = true;
                    break;
                    }
                }
             }
             break;

        case SDL_QUIT:
            done = true;
            break;

        default:
            break;
        }
    }   
}

void run() {
    while(!done) {
        //SDL_SetWindowSize(window, screen.w, screen.h); // <-- works
        handle_events();
        SDL_RenderClear(renderer);
        SDL_RenderPresent(renderer);

        if(resizeDone) {
            int w, h;
            SDL_GetWindowSize(window, &w, &h);
            printf("SDL_GetWindowSize: %d, %d\n", w, h);
            resizeDone = false;
        }
    }
}

int main(int, char**) {
    SDL_Init(SDL_INIT_VIDEO);
    uint32_t window_flags = SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE;
    window = SDL_CreateWindow("Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags);
    windowID = SDL_GetWindowID(window);
    renderer = SDL_CreateRenderer(window, -1, 0);
    SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
    run();
    SDL_Quit();
    return 0;
}
like image 441
Scam Avatar asked Oct 19 '22 17:10

Scam


1 Answers

Some window managers seems to ignore resize requests made while WM itself resizes window (e.g. while mouse button held). On contrary, SDL_GetWindowSize returns cached values, which in that specific case sometimes happens to be wrong.

I see no platform-independent way to achieve that, other than constantly calling SDL_SetWindowSize on each frame, just in case. It could be achieved using platform-specific APIs, though (like SDL_GetWindowSysWMInfo and then using Xlib).

like image 161
keltar Avatar answered Nov 02 '22 11:11

keltar