Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pygame surface.blits when using area argument

I am trying to use surface.blits with the area parameter to improve the performance of my code. When I use the area parameter for blits, I run into the following error:

SystemError: <'method 'blits' of 'pygame.Surface' objects> returned a result with an error set.

If I remove the area parameter, blits work as I would expect. Any ideas on what I could be doing wrong? Attached below is an example code my use case and error.

import sys
import random

import pygame
pygame.init()

tilemap = pygame.image.load('pattern.jpg')

tilesize = 64
size = 4
w, h = size*64, size*64
screen = pygame.display.set_mode((w, h))

while True:
    screen.fill((0, 0, 0))
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    blit_list = []
    for i in range(size):
        for j in range(size):
            xi, yi = random.randint(0, size), random.randint(0, size)
            blit_args = (tilemap, (i*tilesize, j*tilesize),
                        (xi*tilesize, yi*tilesize, tilesize, tilesize))

            # calling screen.blit here works correctly
            screen.blit(*blit_args)

            blit_list.append(blit_args)


    # instead of using multiple blit calls above, calling screen.blits here fails
    # remove the area argument (3rd arg) from each blit_arg tuple works
    # screen.blits(blit_list)

    pygame.display.flip()

    # wait a second
    pygame.time.wait(1000)

Here is the image I used (https://www.behance.net/gallery/19447645/Summer-patterns):

pattern.jpg

like image 984
BradMcDanel Avatar asked Jan 18 '19 21:01

BradMcDanel


People also ask

What does blit () do in pygame?

blit() — blit stands for Block Transfer—and it's going to copy the contents of one Surface onto another Surface . 00:17 The two surfaces in question are the screen that you created and the new Surface . So, . blit() will take that rectangular Surface and put it on top of the screen.

How do I use pygame surface blit?

We need to get this surface (background) and draw it onto the window. To do this we will call screen. blit(background,(x,y)) where (x,y) is the position inside the window where we want the top left of the surface to be. This function says take the background surface and draw it onto the screen and position it at (x,y).

How do I change the surface in pygame?

Creating a surface Creating surfaces in pygame is quite easy. We just have to pass the height and the width with a tuple to pygame. Surface() method. We can use various methods to format our surface as we want.

What is screen blit pygame?

The screen object represents your game screen. It is a thin wrapper around a Pygame surface that allows you to easily draw images to the screen (“blit” them).


1 Answers

This is a bug in the C code. In surface.c line 2258, for surf_blits there is the following test:

    if (dest->flags & SDL_OPENGL &&
        !(dest->flags & (SDL_OPENGLBLIT & ~SDL_OPENGL))) {
        bliterrornum = BLITS_ERR_NO_OPENGL_SURF;
        goto bliterror;
    }

Whereas in surface.c line 2118, for surf_blit the code is:

#if IS_SDLv1
    if (dest->flags & SDL_OPENGL &&
        !(dest->flags & (SDL_OPENGLBLIT & ~SDL_OPENGL)))
        return RAISE(pgExc_SDLError,
                     "Cannot blit to OPENGL Surfaces (OPENGLBLIT is ok)");
#endif /* IS_SDLv1 */

Notice the #if IS_SDLv1.

The problem seems to come from SDL_OPENGLBLIT which is now deprecated.

Do not use the deprecated SDL_OPENGLBLIT mode which used to allow both blitting and using OpenGL. This flag is deprecated, for quite a few reasons. Under numerous circumstances, using SDL_OPENGLBLIT can corrupt your OpenGL state.

Unfortunately, I am no expert at OpenGL and I am not able to explain further. Hopefully someone can post a more precise answer.

What I know for sure is that I can raise the BLITS_ERR_SEQUENCE_SURF just before (by giving a pygame.Rect as the first object in blit_args for example) and I am unable to raise BLITS_ERR_INVALID_DESTINATION just after.

This leads me to think something is going on with the lines above.

EDIT

I can confirm that if I add #if IS_SDLv1 around the test above and recompile pygame, it works. No idea why though! ☺

I raised the issue on GitHub.

like image 94
Jacques Gaudin Avatar answered Nov 02 '22 23:11

Jacques Gaudin