On Wednesday, August 7, 2013 1:31:38 AM UTC+2, Richard Jones wrote:
>
> Hi Fred, 
>
> Sorry for the delayed response, but I've only just found time :-) 
>

You don't have to apologize :) Thanks for sharing my problems.

>
> There's a few things going on here, but the crux of sprites in pyglet 
> is that they're implemented as textured quads in OpenGL. That's 
> important because it means that sprites are basically: 
>
> 1. a set of 4 vertices, 
> 2. a set of 4 colour values to blend into the texture (typically only 
> used for alpha fading control), 
> 3. a reference to a texture ID, and 
> 4. a set of texture coordinates. 
>
> The optimal way of animating a pyglet sprite is to: 
>
> 1. ensure the animation images are all in one texture, and 
> 2. modify those texture coordinates at point 4 each frame the image 
> needs to change. 
>
> A third point, which can complicate things, is to only do the updates 
> for those sprites on screen. But that's an optimisation to add in 
> after you've done the rest. 
>
> To achieve point 1, you use a texture atlas. The pyglet image module 
> has these for you, but also note that if you use pyglet.resource.image 
> to load your images (which is a good idea since pyglet's resource 
> handling is quite neat and deals with platform stuff) then the images 
> will automatically be added to a texture atlas. The reason to use a 
> texture atlas is so that your sprites all share the same texture ID 
> and there's a single batch rendering call (which means vertex buffer 
> (VBO) render call at the OpenGL level) which is much faster. Texture 
> swapping (requiring multiple VBO render calls) can slow things down a 
> lot as it means a separate pyglet->OpenGL call for each texture. 
>
> The easiest way of managing a texture atlas for your purposes is to 
> use an Animation, as it manages the frames for you (and timing, if you 
> ask it to). 
>
>
Thanks for the technical background. I'm currently trying to learn OpenGL, 
and your explanations are helpful.

I wrote a test using sprites + animations to make an idea of the 
performances I get. Here's the code :

import pyglet, time

window = pyglet.window.Window() 

sheet = pyglet.image.load('anim.png')
images = pyglet.image.TextureGrid(pyglet.image.ImageGrid(sheet, 8, 8))
animation = pyglet.image.Animation([pyglet.image.AnimationFrame(images[i], 
5/60.0) for i in range(16)])
batch = pyglet.graphics.Batch()

for i in range(100):# several values tested here 
    sprite = pyglet.sprite.Sprite(animation, (i % 40)*32, (i / 40)*32, 
batch = batch)

frame_counter = 0

def update(dt): 
    global frame_counter
    
    frame_counter += 1
    if frame_counter == 1000:
        print time.time() - time_start
        pyglet.app.exit()

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

pyglet.clock.schedule_interval(update, 1/60.0) 
time_start = time.time()
pyglet.app.run() 


The performances are low :
for 400 sprites : 215s (i.e. around 5 fps)
for 100 sprites (which will be typical in the game) : 25s (40 fps)
for 10 sprites : 20s (50 fps)
for 1 sprite : same result

Note that, even for 1 sprite, I don't get 60 fps, which was what I 
specified with the line :
pyglet.clock.schedule_interval(update, 1/60.0).

And there's still nothing else from the engine interfering (like collisions 
tests, or others effects to the map).

But I must know first if I'm doing it the right way. 

To achieve point 2 it's enough to identify the image object in the 
> atlas you wish to use and then just: "sprite.image = new_image_frame" 
> and pyglet is smart enough to do the rest. 
>
> Note that pyglet's Animation class does pretty much all of this for 
> you - it's what it's for. Could you please indicate where you saw 
> people recommending against using pyglet.app.run() because that 
> certainly complicates things a lot, and does explain why your 
> animation isn't playing (and other pyglet.clock scheduling also won't 
> work). 
>

I must confess I didn't find the link back. I've read this discussion 
(https://groups.google.com/d/msg/pyglet-users/4Kb3EwFkEa4/vvQXm5_mJiAJ) 
where the author says he coded its own way of handling an animation, not 
using pyglet scheduling), but I was sure I've read someone telling that he 
wrote its own loop. Mine is just something like :

        clock.set_fps_limit(60)
        window.push_handlers(self.clock)

        while True:
            clock.tick()
            window.dispatch_events()

            # get controls (keyboard or joystick)
            # update all elements, sharing the same batch

            pyglet.gl.glLoadIdentity()
            pyglet.gl.glTranslatef(-screen_left, -screen_bottom, 0)
            batch.draw()            
            window.flip()

But of course, going back to a classical app.run() will be no problem. 

>
> Except for some special effects work you almost never want to be 
> copying OpenGL texture image data around during program running. 
>
>
I will try to be more precise as to what I want to achieve. Basically, I 
want to remake the scene you can see on this video : 
http://www.youtube.com/watch?v=CpepE1tdbKc&list=PL8BFDA9CBD4C347AF (from 
7:23). You'll notice a palette cycling on the red lights on top of walls 
(easier to see when the player doesn't move but I didn't find another 
video).

I didn't see anything about indexed colors images on pyglet, so I wrote a 
function that, given an indexed colors image and its palette, generate an 
atlas with all the tiles obtained from cycling palette on the source image. 
You see why I say that there are many sprites (one per tile, around 100 on 
some screens) but a few image (most of the tiles look the same. In fact, in 
the tilesheet, there are only 16 images with the palette cycling). That's 
why I wondered if I could use this redundancy to find a faster way to 
achieve my goal.
 

> I hope this helps, 
>
>     Richard 
>

It did. But I still need help! :)

 

>
> On 5 August 2013 07:53, Fred <[email protected] <javascript:>> wrote: 
> > Hello, 
> > 
> > I keep on trying to develop my 2D RPG engine, and I face another 
> slowdown 
> > problem. 
> > 
> > The map of the game is made of tiles (32 x 32 px) and some of them (say, 
> > around 30 among 500) are animated. 
> > 
> > I tried to represent each by a sprite, whose image would be an 
> Animation. 
> > But that is too slow. 
> > 
> > Since most of these tiles are actually the same, I thought that, rather 
> than 
> > updating the image attribute of each 30 sprites, it would be more clever 
> to 
> > make those prite.image point to the same texture, and updating this 
> texture 
> > (by blitting the proper "image" regularly). I assumed fact that copying 
> > something to a texture would be quite fast, especially if the 
> "something" is 
> > too a texture. 
> > 
> > Unfortunately, I can't figure out how to blit a TextureRegion in a 
> texture. 
> > blit_to_texture keeps on raising the same error : 
> > pyglet.image.ImageException: Cannot blit <TextureRegion 32x32> to a 
> texture. 
> > 
> > So my two questions : 
> > 1) Is this idea (modify texture rather than sprite) sufficient to 
> improve 
> > performances ? 
> > 2) how to blit a texture on another ? 
> > 
> > Thanks in advance, 
> > 
> > -- 
> > You received this message because you are subscribed to the Google 
> Groups 
> > "pyglet-users" group. 
> > To unsubscribe from this group and stop receiving emails from it, send 
> an 
> > email to [email protected] <javascript:>. 
> > To post to this group, send email to 
> > [email protected]<javascript:>. 
>
> > Visit this group at http://groups.google.com/group/pyglet-users. 
> > For more options, visit https://groups.google.com/groups/opt_out. 
> > 
> > 
>

-- 
You received this message because you are subscribed to the Google Groups 
"pyglet-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/pyglet-users.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to