0

I have taken code from this post here. My main objective is to draw my entire PyGame project in OpenGL so that it is able to run better. The issue that I am having is that I have a somewhat transparent image and it looks like it is being drawn infinitely and loses colour and opacity. I have also tried other non-transparent images and it appears to be doing the same thing.

Link for the transparent image I am using.

Code:

import pygame
from OpenGL.GL import *
from pygame.locals import *

pygame.init()
pygame.display.set_mode((1900, 900), OPENGL | DOUBLEBUF | pygame.OPENGLBLIT)
pygame.display.init()
info = pygame.display.Info()

# basic opengl configuration
glViewport(0, 0, info.current_w, info.current_h)
glDepthRange(0, 1)
glMatrixMode(GL_PROJECTION)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glShadeModel(GL_SMOOTH)
glClearColor(0.0, 0.0, 0.0, 0.0)
glClearDepth(1.0)
glDisable(GL_DEPTH_TEST)
glDisable(GL_LIGHTING)
glDepthFunc(GL_LEQUAL)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
glEnable(GL_BLEND)

# Images
sun = pygame.image.load("menuimages/sun.png").convert_alpha()

texID = glGenTextures(1)
def surfaceToTexture( pygame_surface ):
    global texID
    rgb_surface = pygame.image.tostring(pygame_surface, 'RGB')
    glBindTexture(GL_TEXTURE_2D, texID)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
    surface_rect = pygame_surface.get_rect()
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, surface_rect.width, surface_rect.height, 0, GL_RGB, GL_UNSIGNED_BYTE, rgb_surface)
    glGenerateMipmap(GL_TEXTURE_2D)
    glBindTexture(GL_TEXTURE_2D, 0)


clock = pygame.time.Clock()

# make an offscreen surface for drawing PyGame to
offscreen_surface = pygame.Surface((info.current_w, info.current_h))

while True:
    offscreen_surface.blit(sun, (50, 250))

    # prepare to render the texture-mapped rectangle
    glClear(GL_COLOR_BUFFER_BIT)
    glLoadIdentity()
    glDisable(GL_LIGHTING)
    glEnable(GL_TEXTURE_2D)

    #draw texture openGL Texture
    surfaceToTexture( offscreen_surface )
    glBindTexture(GL_TEXTURE_2D, texID)
    glBegin(GL_QUADS)
    glTexCoord2f(0, 0); glVertex2f(-1, 1)
    glTexCoord2f(0, 1); glVertex2f(-1, -1)
    glTexCoord2f(1, 1); glVertex2f(1, -1)
    glTexCoord2f(1, 0); glVertex2f(1, 1)
    glEnd()

    pygame.display.flip()
    clock.tick(60)

Any help is appreciated.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
ahmedquran12
  • 164
  • 1
  • 6
  • 19

1 Answers1

0

ITt is not necessary to call surfaceToTexture in the application loop. Call it once before the loop, but bind the texture in the loop.

Additionally you have to handle the events in the application loop. See pygame.event.get() respectively pygame.event.pump():

For each frame of your game, you will need to make some sort of call to the event queue. This ensures your program can internally interact with the rest of the operating system.

offscreen_surface.blit(sun, (50, 250))
surfaceToTexture( offscreen_surface )

run = True
while run:
    for event in pygame.event.get():
        if event.type == QUIT:
            run = False

    # prepare to render the texture-mapped rectangle
    glClear(GL_COLOR_BUFFER_BIT)
    glLoadIdentity()
    glDisable(GL_LIGHTING)
    glEnable(GL_TEXTURE_2D)

    #draw texture openGL Texture
    glBindTexture(GL_TEXTURE_2D, texID)
    glBegin(GL_QUADS)
    glTexCoord2f(0, 0); glVertex2f(-1, 1)
    glTexCoord2f(0, 1); glVertex2f(-1, -1)
    glTexCoord2f(1, 1); glVertex2f(1, -1)
    glTexCoord2f(1, 0); glVertex2f(1, 1)
    glEnd()

    pygame.display.flip()
    clock.tick(60)

An existing texture object (texID) can be changed with glTexSubImage2D:

def updateTexture(pygame_surface, texID):
    rgb_surface = pygame.image.tostring(pygame_surface, 'RGB')
    surface_rect = pygame_surface.get_rect()
    glBindTexture(GL_TEXTURE_2D, texID)
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, surface_rect.width, surface_rect.height, GL_RGB, GL_UNSIGNED_BYTE, rgb_surface)

When you want to move the you should prefer just to draw and move the "small" image. Setup a Orthographic projection with glOrtho and specify the quad vertices with window coordinates.

See also Render pygame sprites with pyopengl or PyGame and OpenGL immediate mode (Legacy OpenGL)

Complete example:

import pygame
from OpenGL.GL import *
from pygame.locals import *

pygame.init()
screen = pygame.display.set_mode((1900, 900), OPENGL | DOUBLEBUF | pygame.OPENGLBLIT)
pygame.display.init()
info = pygame.display.Info()

# basic opengl configuration
glViewport(0, 0, info.current_w, info.current_h)
glDepthRange(0, 1)
glMatrixMode(GL_PROJECTION)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glShadeModel(GL_SMOOTH)
glClearColor(0.0, 0.0, 0.0, 0.0)
glClearDepth(1.0)
glDisable(GL_LIGHTING)
glDepthFunc(GL_LEQUAL)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)

# Images
sun = pygame.image.load("menuimages/sun.png").convert_alpha()

def surfaceToTexture(pygame_surface):
    texID = glGenTextures(1)
    rgb_surface = pygame.image.tostring(pygame_surface, 'RGBA')
    glBindTexture(GL_TEXTURE_2D, texID)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
    surface_rect = pygame_surface.get_rect()
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surface_rect.width, surface_rect.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgb_surface)
    glGenerateMipmap(GL_TEXTURE_2D)
    glBindTexture(GL_TEXTURE_2D, 0)
    return texID

def drawTextureImage(textureId, rect):
    glEnable(GL_TEXTURE_2D)
    glBindTexture(GL_TEXTURE_2D, textureId)
    glBegin(GL_QUADS)
    glTexCoord2f(0, 0); glVertex2f(rect.left, rect.bottom)
    glTexCoord2f(0, 1); glVertex2f(rect.left, rect.top)
    glTexCoord2f(1, 1); glVertex2f(rect.right, rect.top)
    glTexCoord2f(1, 0); glVertex2f(rect.right, rect.bottom)
    glEnd()
    glDisable(GL_TEXTURE_2D)

clock = pygame.time.Clock()

sun_x = 0
texID = surfaceToTexture(sun)

run = True
while run:
    for event in pygame.event.get():
        if event.type == QUIT:
            run = False

    sun_x = (sun_x + 1) % screen.get_width()
    sun_rect = sun.get_rect(topleft = (sun_x, 250))

    glViewport(0, 0, screen.get_width(), screen.get_height())
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    glOrtho(0, screen.get_width(), 0, screen.get_height(), -1, 1)
    glMatrixMode(GL_MODELVIEW)

    # prepare to render the texture-mapped rectangle
    glClear(GL_COLOR_BUFFER_BIT)
    glLoadIdentity()
    glDisable(GL_LIGHTING)
    glDisable(GL_DEPTH_TEST)
    glEnable(GL_BLEND)
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

    #draw texture openGL Texture
    drawTextureImage(texID, sun_rect)

    pygame.display.flip()
    clock.tick(60)
Rabbid76
  • 202,892
  • 27
  • 131
  • 174