Salajouni
Salajouni

Reputation: 41

Pyglet: blit_into texture and alpha

I've been using pyglet for a while now and I really like it. I've got one thing I'd like to do but have been unable to do so far, however.

I'm working on a 2D roleplaying game and I'd like the characters to be able to look different - that is to say, I wouldn't like use completely prebuilt sprites, but instead I'd like there to be a range of, say, hairstyles and equipment, visible on characters in the game.

So to get this thing working, I thought the most sensible way to go on about it would be to create a texture with pyglet.image.Texture.create() and blit the correct sprite source images on that texture using Texture.blit_into. For example, I could blit a naked human image on the texture, then blit a hair texture on that, etc.

human_base  = pyglet.image.load('x/human_base.png').get_image_data()
hair_style  = pyglet.image.load('x/human_hair1.png').get_image_data()

texture = pyglet.image.Texture.create(width=human_base.width,height=human_base.height)

texture.blit_into(human_base, x=0, y=0, z=0)
texture.blit_into(hair_style, x=0, y=0, z=1)

sprite = pyglet.sprite.Sprite(img=texture, x=0, y=0, batch=my_sprite_batch)

The problem is that blitting the second image into the texture "overwrites" the texture already blitted in. Even though both of the images have an alpha channel, the image below (human_base) is not visible after hair_style is blit on top of it.

One reading this may be wondering why do it this way instead of, say, creating two different pyglet.sprite.Sprite objects, one for human_base and one for hair_style and just move them together. One thing is the draw ordering: the game is tile-based and isometric, so sorting a visible object consisting of multiple sprites with differing layers (or ordered groups, as pyglet calls them) would be a major pain.

So my question is, is there a way to retain alpha when using blit_into with pyglet. If there is no way to do it, please, any suggestions for alternative ways to go on about this would be very much appreciated!

Upvotes: 4

Views: 1561

Answers (2)

Sakkee
Sakkee

Reputation: 11

I ran into the very same problem and couldn't find a proper solution. Apparently blitting two RGBA images/textures overlapping together will remove the image beneath. Another approache I came up with was using every 'clothing image' on every character as an independent sprite attached to batches and groups, but that was far from the optimal and reduced the FPS dramatically.

I got my own solution by using PIL

import pyglet
from PIL import Image
class main(pyglet.window.Window):
    def __init__ (self):
        TILESIZE = 32
        super(main, self).__init__(800, 600, fullscreen = False)
        img1 = Image.open('under.png')
        img2 = Image.open('over.png')
        img1.paste(img2,(0,0),img2.convert('RGBA'))
        img = img1.transpose(Image.FLIP_TOP_BOTTOM)
        raw_image=img.tostring()
        self.image=pyglet.image.ImageData(TILESIZE,TILESIZE,'RGBA',raw_image)

    def run(self):
        while not self.has_exit:
            self.dispatch_events()
            self.clear()
            self.image.blit(0,0)
            self.flip()
x = main()
x.run()

This may well not be the optimal solution, but if you do the loading in scene loading, then it won't matter, and with the result you can do almost almost anything you want to (as long as you don't blit it on another texture, heh). If you want to get just 1 tile (or a column or a row or a rectangular box) out of a tileset with PIL, you can use the crop function.

Upvotes: 1

doxin
doxin

Reputation: 718

setting the blend function correctly should fix this:

pyglet.gl.glBlendFunc(pyglet.gl.GL_SRC_ALPHA,pyglet.gl.GL_ONE_MINUS_SRC_ALPHA)

Upvotes: 3

Related Questions