Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Game video output not recognizing scaled displays. #884

Open
evertvorster opened this issue Sep 25, 2024 · 9 comments
Open

Game video output not recognizing scaled displays. #884

evertvorster opened this issue Sep 25, 2024 · 9 comments

Comments

@evertvorster
Copy link
Contributor

One of my monitors is fairly high resolution, and so it is scaled so that it is usable.
Unfortunately this causes issues with VegaStrike which is strictly pixel based.

SDL has a fairly straightforward way of dealing with this that should not impact non-scaled displays:
https://wiki.libsdl.org/SDL2/SDL_HINT_WINDOWS_DPI_SCALING

@royfalk
Copy link
Contributor

royfalk commented Sep 25, 2024

What happens if you try 1024x768 (or some other low resolution) in full screen?
Why do we have both this and #883 ?

@evertvorster
Copy link
Contributor Author

Maybe a screenshot will show you what I mean. Here I used 1366x768, on a 4K monitor with 125% scaling:
image

@evertvorster
Copy link
Contributor Author

A little nuance here.
When picking a display size of 3840x2160 which is the monitor's native resolution, it displays too big, because the display is being scaled by the window manager.

Obligatory screenshot:
image

To get the properly sized display, I have to get the display resolution from a website that checks this sort of thing, and that says my display size is 3200x1800.
That resolution does not exist in the vesettings, and so I have to edit vegastrike.config, make the resolution, and then only can I get a proper full screen resolution.

If I have to make a new screen resolution for every scaling factor, the amount of resolutions in the config file becomes a little cumbersome.

So, it is a different problem than the full screen not being scaled to the full monitor in fullscreen mode.

@royfalk
Copy link
Contributor

royfalk commented Sep 25, 2024

OK. See if you can find a reference in SDL as well as a discussion or code snippet to implement this. If you can find it, I'll implement this. Contingent on approval by @BenjamenMeyer.

@evertvorster
Copy link
Contributor Author

I asked ChatGPT about it, and here is the response:
In SDL (Simple DirectMedia Layer), handling various screen resolutions and scaled displays involves detecting available screen resolutions, setting the display mode accordingly, and managing proper scaling for different resolutions. Here’s a step-by-step approach to achieve this:

1. Detect Available Screen Resolutions

SDL provides a function to get the available display modes for each connected monitor. You can query the modes and then allow the user to select the preferred resolution.

Here’s an example of how to detect the available screen resolutions:

#include <SDL2/SDL.h>
#include <stdio.h>

void listAvailableResolutions(int displayIndex) {
    int numDisplayModes = SDL_GetNumDisplayModes(displayIndex);
    if (numDisplayModes < 0) {
        printf("SDL_GetNumDisplayModes failed: %s\n", SDL_GetError());
        return;
    }

    printf("Available resolutions for display %d:\n", displayIndex);
    for (int i = 0; i < numDisplayModes; i++) {
        SDL_DisplayMode mode;
        if (SDL_GetDisplayMode(displayIndex, i, &mode) != 0) {
            printf("SDL_GetDisplayMode failed: %s\n", SDL_GetError());
            continue;
        }
        printf("%d x %d @ %dHz\n", mode.w, mode.h, mode.refresh_rate);
    }
}

int main() {
    if (SDL_Init(SDL_INIT_VIDEO) != 0) {
        printf("SDL_Init Error: %s\n", SDL_GetError());
        return 1;
    }

    int numDisplays = SDL_GetNumVideoDisplays();
    if (numDisplays < 0) {
        printf("SDL_GetNumVideoDisplays failed: %s\n", SDL_GetError());
        return 1;
    }

    // List available resolutions for each display
    for (int i = 0; i < numDisplays; i++) {
        listAvailableResolutions(i);
    }

    SDL_Quit();
    return 0;
}

This code initializes SDL, retrieves the available resolutions for each display, and prints them out. You can select a resolution from this list and apply it later.

2. Set Display Mode

Once you've selected a resolution, you can set the SDL window to that resolution. Here’s how you do it:

void setDisplayMode(int displayIndex, int width, int height) {
    SDL_Window *window = SDL_CreateWindow("Game Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_FULLSCREEN_DESKTOP);
    if (!window) {
        printf("SDL_CreateWindow failed: %s\n", SDL_GetError());
        return;
    }

    SDL_DisplayMode displayMode;
    if (SDL_GetCurrentDisplayMode(displayIndex, &displayMode) != 0) {
        printf("SDL_GetCurrentDisplayMode failed: %s\n", SDL_GetError());
    } else {
        SDL_SetWindowDisplayMode(window, &displayMode);
    }

    // Game loop and rendering goes here...

    SDL_DestroyWindow(window);
}

Here, SDL_CreateWindow sets the window to fullscreen with the desktop resolution, and then you apply the selected display mode using SDL_SetWindowDisplayMode.

3. Handle Scaled Displays

If you are working with different resolutions, SDL provides an easy way to render at a consistent resolution, regardless of the screen size, using the SDL_RenderSetLogicalSize() function. This function scales the rendering output to match the window’s resolution.

Example for handling scaling:

void setLogicalScaling(SDL_Renderer *renderer, int logicalWidth, int logicalHeight) {
    SDL_RenderSetLogicalSize(renderer, logicalWidth, logicalHeight);
}

int main() {
    SDL_Window *window;
    SDL_Renderer *renderer;

    SDL_Init(SDL_INIT_VIDEO);

    // Create window at some base resolution, here 1920x1080
    window = SDL_CreateWindow("Game Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1920, 1080, SDL_WINDOW_SHOWN);

    // Create renderer
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

    // Set logical size to scale rendering to 1920x1080 regardless of window resolution
    setLogicalScaling(renderer, 1920, 1080);

    // Rendering loop
    int running = 1;
    SDL_Event event;
    while (running) {
        while (SDL_PollEvent(&event)) {
            if (event.type == SDL_QUIT) {
                running = 0;
            }
        }

        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
        SDL_RenderClear(renderer);

        // Your game rendering logic here...

        SDL_RenderPresent(renderer);
    }

    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
    
    return 0;
}

4. Fullscreen and Windowed Mode Handling

To switch between fullscreen and windowed modes dynamically, you can use SDL_SetWindowFullscreen:

void toggleFullscreen(SDL_Window *window) {
    Uint32 fullscreenFlag = SDL_WINDOW_FULLSCREEN_DESKTOP;
    int isFullscreen = SDL_GetWindowFlags(window) & fullscreenFlag;
    SDL_SetWindowFullscreen(window, isFullscreen ? 0 : fullscreenFlag);
}

Summary:

  • Detect available resolutions: Use SDL_GetNumDisplayModes and SDL_GetDisplayMode.
  • Set display mode: Use SDL_SetWindowDisplayMode and SDL_CreateWindow.
  • Handle scaled displays: Use SDL_RenderSetLogicalSize to scale rendering for different screen resolutions.
  • Fullscreen handling: Use SDL_SetWindowFullscreen to toggle fullscreen mode.

By combining these techniques, your game engine can detect and adapt to various screen resolutions and handle proper scaling across different display setups.

@royfalk
Copy link
Contributor

royfalk commented Sep 25, 2024

OK. That looks good.
Let's give Ben a chance to think about this.

@BenjamenMeyer
Copy link
Member

  1. We probably need to take a stance about AI generators (Copilot, Gemini, ChatGPT, etc); most open source projects have bans on them (namely due to liability issues). So while the comment above is helpful and informative we should use it as a reference and not directly to code. We probably should open a separate discussion about AI generators.
  2. We should have something in VS Settings sooner than later. I'm good with that. Ultimately I think we should integrate VS Settings into the game itself so you don't have to leave the game to change things.
  3. We should probably scale the fonts separate from the resolution so we can support small/medium/large/extra large fonts to avoid issues with either fonts being too small or too large. Mapping it to the resolution does not necessarily resolve that.

@royfalk
Copy link
Contributor

royfalk commented Sep 29, 2024

  1. We probably need to take a stance about AI generators (Copilot, Gemini, ChatGPT, etc); most open source projects have bans on them (namely due to liability issues). So while the comment above is helpful and informative we should use it as a reference and not directly to code. We probably should open a separate discussion about AI generators.

That's a good point. I wasn't about to plug this in as is anyhow. However, I did not consider this as I've been out of a job for a while now. No doubt my old job would have had a training session regarding this.

2. We should have something in VS Settings sooner than later. I'm good with that. Ultimately I think we should integrate VS Settings into the game itself so you don't have to leave the game to change things.

The big block here is the GUI. I don't want to tackle any GUI development using the home-grown stuff they wrote. Once we figure out something else, this should be reasonably easy.

3. We should probably scale the fonts separate from the resolution so we can support small/medium/large/extra large fonts to avoid issues with either fonts being too small or too large. Mapping it to the resolution does not necessarily resolve that.

I'm running the game in windowed 2k and the fonts are tiny. I just live with it until we can get to the GUI side of things.

@BenjamenMeyer
Copy link
Member

  1. We probably need to take a stance about AI generators (Copilot, Gemini, ChatGPT, etc); most open source projects have bans on them (namely due to liability issues). So while the comment above is helpful and informative we should use it as a reference and not directly to code. We probably should open a separate discussion about AI generators.

That's a good point. I wasn't about to plug this in as is anyhow. However, I did not consider this as I've been out of a job for a while now. No doubt my old job would have had a training session regarding this.

Yeah, my current employer introduced me to sum of the intricacies of this. I have a Copilot licences for work; but the liability for the license only extends to who paid for it. There's also not much protection on it from cross-using licenses so...I'll start a separate discussion on the topic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants