Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pyglet - loading/blitting image with alpha

I'm trying to make a simple application with pyglet. My main problem so far is that I can't seem to blit an image with alpha - all of the transparent pixels are converted into black pixels. I'm not sure whether the problem is with the loading of the image or the blitting. Here is a very basic overview of how I'm trying to render the image:

import pyglet
import pyglet.clock

window = pyglet.window.Window()

window.config.alpha_size = 8

#fancy text
text = pyglet.resource.image("text.png")

#background image
bg = pyglet.resource.image("bg.png")

bg.blit(0, 0)
text.blit(100, 100)

pyglet.app.run()

Any help is appreciated. Thanks in advance.

like image 577
nousername Avatar asked Sep 04 '17 22:09

nousername


1 Answers

You most likely just need to enable GL ALPHA blends.

from pyglet.gl import *
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

But first of all, your code is not able to run. Mostly because you don't declare a window.event function to handle the on_draw where you normally render things.

Secondly, you never clear your window (which will cause a mess).

Here's a minimal working example of your code:

import pyglet
import pyglet.clock

window = pyglet.window.Window()

window.config.alpha_size = 8

#fancy text
text = pyglet.resource.image("text.png")

#background image
bg = pyglet.resource.image("bg.png")

@window.event
def on_draw():
    window.clear()

    bg.blit(0, 0)
    text.blit(100, 100)

pyglet.app.run()

Now this generates this:

enter image description here

And here's a working example of how you use the GL_BLEND feature:

import pyglet
import pyglet.clock
from pyglet.gl import *

window = pyglet.window.Window()

window.config.alpha_size = 8

#fancy text
text = pyglet.resource.image("text.png")

#background image
bg = pyglet.resource.image("bg.png")

@window.event
def on_draw():
    window.clear()
    glEnable(GL_BLEND)

    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
    bg.blit(0, 0)
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
    text.blit(100, 100)

pyglet.app.run()

This yields a result like so:

enter image description here

However, this code will quickly become messy.
So there's two things you can do. You can first, put your images into sprite objects. Secondly, make this a bit more object oriented.

First, we'll use sprites.

self.fancy_background = pyglet.sprite.Sprite(pyglet.image.load('bg.png'))
self.fancy_background.draw()  # not blit!

Sprites automatically uses transparency, which makes your life (and code) a lot easier.

Secondly, we'll put these into a batch.
Batches are made to bunch A LOT of sprites so you can call .draw() on the batch, and all sprites in that batch gets insta-rendered.

self.background = pyglet.graphics.Batch()
self.fancy_background = pyglet.sprite.Sprite(pyglet.image.load('bg.png'), batch=self.background)
self.background.draw() # background, not fancy_background! And also not blit!!

Last and most certainly not least.
We'll put this into a class so we can do cool stuff later on.

import pyglet
import pyglet.clock
from pyglet.gl import *

key = pyglet.window.key

class main(pyglet.window.Window):
    def __init__ (self, width=800, height=600, fps=False, *args, **kwargs):
        super(main, self).__init__(width, height, *args, **kwargs)
        self.x, self.y = 0, 0

        self.background = pyglet.graphics.Batch()
        self.texts = pyglet.graphics.Batch()

        self.fancy_background = pyglet.sprite.Sprite(pyglet.image.load('bg.png'), batch=self.background)
        self.fancy_text = pyglet.sprite.Sprite(pyglet.image.load('text.png'), batch=self.texts)

        self.mouse_x = 0
        self.mouse_y = 0
        self.alive = 1

    def on_draw(self):
        self.render()

    def on_close(self):
        self.alive = 0

    def on_mouse_motion(self, x, y, dx, dy):
        self.mouse_x = x
        self.mouse_y = y

    def on_mouse_press(self, x, y, button, modifiers):
        if button == 1: # Left click
            pass

    def on_key_press(self, symbol, modifiers):
        if symbol == key.ESCAPE: # [ESC]
            self.alive = 0

    def render(self):
        self.clear()

        self.background.draw()
        self.texts.draw()

        self.flip()

    def run(self):
        while self.alive == 1:
            self.render()

            # -----------> This is key <----------
            # This is what replaces pyglet.app.run()
            # but is required for the GUI to not freeze
            #
            event = self.dispatch_events()

if __name__ == '__main__':
    x = main()
    x.run()

enter image description here

BAM.

This code will enable you to create custom functions and custom "player objects" later on for instance. Also you can do collision detection easier and the code just looks a lot more structured (I threw in a little bonus features such as keyboard and mouse events).

Note tho, that the position of the sprites will default to x=0, y=0 as shown in the last picture. You can set the position with x=100 either on the variable/handle or when creating the sprite.

like image 71
Torxed Avatar answered Nov 05 '22 21:11

Torxed