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.