4
\$\begingroup\$

Code:

import pygame
pygame.init()
#
def Main(display,colors):
    clock =pygame.time.Clock()
    #
    surface = pygame.Surface(surface_resolution) # Create main surface
    surface.fill(colors["RED"])
    pygame.draw.rect(surface,colors["GREEN"],pygame.Rect((0,0),(110,110)))
    pygame.draw.rect(surface,colors["BLUE"],pygame.Rect((10,10),(100,100)))
    #
    while True:
        clock.tick(60)
        #
        for event in pygame.event.get(): # Main event loop
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE: # Exit game with Escape key
                    pygame.quit()
                    return
        #
        display.fill(colors["WHITE"]) # Fill the display white
        display.blit(surface,(display.get_size()[0]/2-surface.get_size()[0]/2,display.get_size()[1]/2-surface.get_size()[1]/2)) # Blit main surface on center of display
        #
        pygame.display.flip()
#
if __name__ in "__main__":
    global resolution
    global surface_resolution
    resolution =         (1920,1080) # Resolution of the display
    surface_resolution = (1536,864)  # Resolution actually seen
    #
    #
    display = pygame.display.set_mode(resolution,pygame.FULLSCREEN) # Create fullscreen display
    #
    colors = {                 # Defign colors
        "WHITE":(255,255,255),
        "RED"  :(255,0,0),
        "GREEN":(0,255,0),
        "BLUE" :(0,0,255),
        "BLACK":(0,0,0)
    }
    #
    Main(display,colors) # Run main loop

I have been experimenting with various resolutions in fullscreen Pygame. My new computers native resolution is 1920x1080 as apposed to my old computers resolution of 1366x768, so I started to test resolutions higher than 1366x768. However, when I run pygame with my native resolution, the highest resolution that fits my monitor is 1536x864 with the rest of the primary display off the screen.

This code creates a red surface with a 110x110 rectangle in the upper left corner and blits it to the center of the display. When I set the surfaces size to anything higher than 1536x864, parts of the 110x110 rectangle are cut off, and when I set the display and the surface size to 1366x768, Pygame stretches the display to fill my moniter.

The pygame display docs say that:

When requesting fullscreen display modes, sometimes an exact match for the requested resolution cannot be made. In these situations pygame will select the closest compatible match. The returned surface will still always match the requested resolution.

However, when I run the following code to get all the available fullscreen resolutions, I see that 1920x1080 is an available resolution.

>>> for mode in pygame.display.list_modes():
        print(mode)
(1920, 1080)
(1680, 1050)
(1600, 900)
(1440, 900)
(1400, 1050)
(1366, 768)
(1360, 768)
(1280, 1024)
(1280, 960)
(1280, 800)
(1280, 768)
(1280, 720)
(1280, 600)
(1152, 864)
(1024, 768)
(800, 600)
(640, 480)
(640, 400)
(512, 384)
(400, 300)
(320, 240)
(320, 200)
>>>

My question is why does this happen, and how can I stop Pygame from stretching the display in this manner? I feel like I'm completely missing the point with this, but I couldn't find anything about this anywhere else.

\$\endgroup\$
3
\$\begingroup\$

I managed to find a commit on the Pygame BitBucket page here that explains the issue and gives an example on how to fix it.

What is happening is that some display environments can be configured to stretch windows so they don't look small on high PPI (Pixels Per Inch) displays. This stretching is what causes displays on larger resolutions to display larger than they actually are.

They provide an example code on the page I linked to showing how to fix this issue.

They fix the issue by importing ctypes and calling this:

ctypes.windll.user32.SetProcessDPIAware()
true_res = (windll.user32.GetSystemMetrics(0),windll.user32.GetSystemMetrics(1))
pygame.display.set_mode(true_res,pygame.Fullscreen)

Calling ctypes.windll.user32.SetProcessDPIAware() will disable the screen stretching. The reason true_res = (windll.user32.GetSystemMetrics(0),windll.user32.GetSystemMetrics(1)) needs to be called and used for the resolution is because there is fullscreen issues when using a resolution that is not native. If one is using a resolution smaller than this, they can simply create a surface for the game to run on and keep the sides black, or he/she can stretch this surface to fit the display size.

They also express that this is a Windows only solution and is available within base Python since Python 2.4. Before that it will need to be installed.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.