Batch issues

61 views
Skip to first unread message

Zombie Mariachis

unread,
Jul 14, 2011, 2:40:58 PM7/14/11
to pyglet-users
The code below is giving me the following error. It's just a static
sprite that I scroll an image across. It works fine when drawn by
itself, but when I include it in a batch the 'wrong type' error pops
up. Any ideas?

File "C:\Python26\lib\site-packages\pyglet\sprite.py", line 143, in
set_state
glBlendFunc(self.blend_src, self.blend_dest)
ctypes.ArgumentError: argument 1: <type 'exceptions.TypeError'>: wrong
type


#####My code:######

asteroid_belt_batch = pyglet.graphics.Batch()

class Level_1(pyglet.sprite.Sprite):
def __init__(self, img, x, y, batch):
super(Level_1, self).__init__(img, x, y, batch)
self.x = 0
self.y = Window_Height / 2
self.img = img
self.gx = x
self.gy = y
self.batch = batch

def update(self, dt):
self.dx = 40 / (space_quotient * 5)
self.x -= self.dx * dt

def draw(self):
glMatrixMode(GL_TEXTURE)
glPushMatrix()
glTranslatef(self.x, self.y, -100.0)
self.img.blit(self.gx, self.gy, 0)
glPopMatrix()
glMatrixMode(GL_MODELVIEW)

asteroid_level_1_texture =
pyglet.resource.image('small_asteroids.png')
asteroid_level_1 = Level_1(asteroid_level_1_texture, batch =
asteroid_belt_batch, x = 0, y = (Window_Height / 2) - 256)

Michael Red

unread,
Jul 14, 2011, 6:55:11 PM7/14/11
to pyglet...@googlegroups.com

--
You received this message because you are subscribed to the Google Groups "pyglet-users" group.
To post to this group, send email to pyglet...@googlegroups.com.
To unsubscribe from this group, send email to pyglet-users...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/pyglet-users?hl=en.


It's getting a wrong type for argument 1. From what I can tell, this means that when you're initialising the base Sprite, it's getting something else for the blend function. Looking at the code, I suggest changing the super call to this:

  super(Level_1, self).__init__(img, x=x, y=y, batch=batch)

I'm not sure if that will error and I can't test now (it shouldn't). If it does, do this:

  super(Level_1, self).__init__(img, x, y, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, batch)

after importing * or the two GL_ things from pyglet.gl.

The reason is that YOUR sprite class has the order of __init__ variables (img, x, y, batch), but if you look at a normal sprite, it goes (img, x, y, blend_src, blend_dest, batch, ...). So you have to always remember to compensate for that in your code.


Zombie Mariachis

unread,
Jul 14, 2011, 7:32:26 PM7/14/11
to pyglet-users
Changing the super to "super(Level_1, self).__init__(img, x=x, y=y,
batch=batch)" cleared up the wrong type issue. Thank you!

However the sprite's specific def draw(self): instructions aren't
being followed.

Michael Red

unread,
Jul 15, 2011, 12:40:32 AM7/15/11
to pyglet...@googlegroups.com

--
You received this message because you are subscribed to the Google Groups "pyglet-users" group.
To post to this group, send email to pyglet...@googlegroups.com.
To unsubscribe from this group, send email to pyglet-users...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/pyglet-users?hl=en.


More likely they are being followed, but not having the expected output. What exactly are you trying to have it do? Because right now, you're blitting an image to the texture at gx, gy. However keep in mind that when you're running __init__, the first thing you do is set x, y = x, y, add the image, then x, y = 0, window_height/2, then gx, gy = x, y. 

This is because when you're doing the super function, you're calling it with x, y and img. This means that it'll do what it always does. That is, set Sprite._x and Sprite._y to the original x and y, rather than 0 and Window_Height/2. And when you want to move it to 0, Window_Height/2, you should be calling self.set_position(0, Window_Height/2).

More importantly, is there really no other way for you to draw this? Because updating the Sprite's texture like this isn't horribly efficient compared to simply drawing the sprite in a different place (I assume the use case will be more complicated than this though). I'm not that good with on-the-fly OpenGL code, so I can only tell you to trial-and-error the numbers in glTranslatef to see if that might be doing it. Try 0, 1, 100, -10, 10, instead of -100.

Besides that, right now you're not really, uh, actually updating a texture, come to think of it. The code in sprite.py is convoluted, but I think the fact that you overwrote its draw(self) routine, then actually blitted an image, rather than letting it draw and texture itself, means that you're doing a transform in the texture matrix, but that isn't actually doing anything to any texture, because there are none. This means you should be calling:

  super(Level_1, self).draw()

either after all your code, instead of (or coupled with) the blitting line, or before it. However it MUST be there in order for you to actually draw the sprite/texture. 

My suggestion, however, would be to either use Sprites as intended, or simply do the OpenGL bits yourself completely, subclass Window and do this in its on_draw() function. It'll work this way (a bit fiddly), but it's not the most clear code, and any slight change in how Sprites draw might affect this.

Michael Red

unread,
Jul 15, 2011, 12:47:35 AM7/15/11
to pyglet...@googlegroups.com
Oh, uh, an idea just popped up. From what I get of the code, you're either trying to somehow draw the sprite (with the texture scrolled to x, y, so that you could theoretically move the texture), or draw an image INTO the texture at (x,y). For the latter, there's blit_into_texture[1]. You could use this on Sprite.texture, however you'd have no real way of rollingback changes past saving the texture at the start of the draw() and restoring it at the end.

Both need you to call the super's .draw() method, and both would require a change in the code of the VERTEX GROUP, which is a transparent thing created by the Sprite, that you have little control over. Inserting code into it usefully is a matter of basically recreating the Sprite and Vertex Group code inside your code, and isn't the best way to go about it.

If you reply with what exactly you're trying to achieve with this code, and why you're doing it this way, rather than another, I'll write up a tutorial to explain either how to do it, or how to do the same thing using actual Sprites.

Michael Red

unread,
Jul 15, 2011, 12:48:34 AM7/15/11
to pyglet...@googlegroups.com
Bleh, forgot the link.


And it was blit_to_texture, rather than into.

Zombie Mariachis

unread,
Jul 15, 2011, 10:21:53 AM7/15/11
to pyglet-users
Thanks a ton for all the info! To better explain what I've gotten the
code to do so far, and what I'm trying to do, I've uploaded some game
play from the project to youtube. http://www.youtube.com/watch?v=zbX9Nj0P1ks

As seen in the video, the background layers shift via the
glTranslatef draw instructions. Right now each layer is just a sprite
with it's own draw being called in the on_draw window event. I'd like
to batch all the draws for the background but when I do the
glTranslatef seems to be ignored. One thought was that each sprite's
'def update' was being ignored, but I don't know, I'm new to all
this.
Message has been deleted

Mike Redhorse

unread,
Jul 15, 2011, 1:51:49 PM7/15/11
to pyglet-users
On Jul 15, 5:21 pm, Zombie Mariachis <squirrelmariac...@yahoo.com>
wrote:
> Thanks a ton for all the info!  To better explain what I've gotten the
> code to do so far, and what I'm trying to do, I've uploaded some game
> play from the project to youtube.http://www.youtube.com/watch?v=zbX9Nj0P1ks
>
>   As seen in the video, the background layers shift via the
> glTranslatef draw instructions.  Right now each layer is just a sprite
> with it's own draw being called in the on_draw window event.  I'd like
> to batch all the draws for the background but when I do the
> glTranslatef seems to be ignored.  One thought was that each sprite's
> 'def update' was being ignored, but I don't know, I'm new to all
> this.


Wow, that looks really good, actually. Do you have an online page for
the project?

Now everything makes a bit more sense, especially after I had a few
hours of sleep. Okay, it should be able to be done, but not in the way
you expect it to be. I'll need to explain some things first, about how
Pyglet does its things. First off, a Sprite contains an image that it
uses for its texture. This is actually converted into a Texture
object, and stored as sprite_name.texture. When you ask a Sprite to
draw itself, it'll do this:

self._vertex_list.draw(GL_QUADS)

This vertex list is actually a graphics.vertex_list. This means that
it contains a whole list of vertices, in various forms. For example, a
vertex list can contain simultaneously, v3f (position in 3 dimensions
stored as floats), t3f (texture coordinates in 3 dimensions as
floats), c4i (vertex color information in RGBA as integers). This
means that when you draw a vertex list, it already has ALL the info it
needs to draw the vertices, textured, colored, whatever. Now THIS
vertex list, actually contains a vertex DOMAIN, which is another
object for management. This domain can contain a lot of different
vertex lists. If you only have a single vertex list, it'll have its
own domain it's actually calling for to draw itself.

This seems complicated, but it's just a way of putting everything into
its own thing. A vertex list contains all the properties needed to
draw one 'shape' (or multiple, I suppose), and a vertex domain
contains any number of vertex lists. In this case, the vertex list is
just one and it's calling its single domain to draw it in GL_QUADS
mode. Looking at the vertex domain draw code, we find out that it's
pretty 1:1. It'll draw the vertex list immediately, with the
properties it's told to. Like the position, texture coordinates and
color specified above.


So you want the background to scroll, this can be done in a number of
ways. The Pyglet way, to me, would be to modify this vertex list's
texture coordinates, instead of actually GL_Translate-ing the texture
matrix. This means that every time you want the texture to move a bit,
you go and reassign the 4 vertices' texture coordinates as being a bit
'higher'. This is actually pretty complicated to do properly, and I
believe is prone to bugs. Possibly not, but it just seems like
scratching your right ear with your left arm over your head.

Now, the way you're doing it, it might work. I'm not completely sure
and, again, I'm not in a position to test right now. My solution for
it would be blitting the texture yourself manually. This means looking
at Texture's blit code, and doing it yourself. This might work, but it
might not.

def draw(self):
#first we set everything up like the texture does, but with
modifying references
t = self.texture.tex_coords
x1 = x - self.texture.anchor_x
y1 = y - self.texture.anchor_y
x2 = x1 + (width is None and self.width or width)
y2 = y1 + (height is None and self.height or height)
array = (GLfloat * 32)(
t[0], t[1], t[2], 1.,
x1, y1, z, 1.,
t[3], t[4], t[5], 1.,
x2, y1, z, 1.,
t[6], t[7], t[8], 1.,
x2, y2, z, 1.,
t[9], t[10], t[11], 1.,
x1, y2, z, 1.)
#this is the initialising of data as in Texture.blit(), now we
actually draw everything
glPushAttrib(GL_ENABLE_BIT)
glEnable(self.texture.target)
glBindTexture(self.texture.target, self.texture.id) #keep in
mind this is an EXPENSIVE operation in terms of time, each differing
use
#now we have bound and enabled the texture. This means that we
can do the translation ourselves, and it should work!
glMatrixMode(GL_TEXTURE)
glPushMatrix()
glTranslatef(self.gx,self.gy,-100)
glMatrixMode(GL_MODELVIEW) #without this, pyglet might go nuts,
not sure how it handles it.
#now we draw it like Texture.blit() says.

glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT)
glInterleavedArrays(GL_T4F_V4F, 0, array)
glDrawArrays(GL_QUADS, 0, 4)
glPopClientAttrib()
glPopAttrib()

#now we reset what we changed.
glMatrixMode(GL_TEXTURE)
glPopMatrix()
glMatrixMode(GL_MODELVIEW)


In theory this should work. It's a hack, so to speak, but the (sane)
way involves subclassing Texture, as your own ScrollingTexture object,
and modifying the blit function so it looks like this. But that would
mean blitting would involve an extra variable, gx and gy, so I'm iffy
to request it as a feature. But it's easy to change, so I might
eventually write up a patch to submit (if it actually works, I'm not
so sure it does) and see how it goes.

I tried explaining almost anything interesting in how Pyglet works and
how I actually thought up the solution. If you're unfamiliar with
Pyglet, I suggest doing the following when you're next stuck:

* If there's an error, see what it says, then look in the files it
tells you.
* If you can't make sense of it, try reading up, and following the
line the program would follow, but backwards, up until it makes sense.
* If you're on Linux, the source is in multiple places. 'locate
pyglet' should find it for you. My folder of choice is: /usr/share/
pyshared/pyglet. For Windows, downloading the source itself is a
better idea.
* Try fixing it with what you've learned from the source code,
following the flow of the code until you reach the error. Even simple
trial-and-error things can help you figure out just what it wants from
you.
* If you're still having trouble, read through the API on what's
faililng, there might be better documentation there, you might figure
out a link you didn't notice.
* If it's still not clear, post on here. This doesn't need to be the
last step you try, really. Some problems are just obscure, and can't
be figured out from the source.

Good luck with the thing, and post back if it works the way I
mentioned it (or some other way you might figure out!) so that I can
possibly patch up a ScrollingTexture object eventually.

Zombie Mariachis

unread,
Jul 23, 2011, 10:37:32 PM7/23/11
to pyglet-users
Just giving you an update Mike. I converted the sprites to
rabbyt.Sprites for the time being so I could move on to other areas of
the game.

Once I get some more of it mashed out I'll start completely over with
proper programming practices. My code is a hilarious mess at the
moment, but it works somehow. I'm positive once I get these suckers
properly batched up it will help solve some of my performance issues.

I've got some better and longer game play videos for you to check
out. No project website yet...

http://youtu.be/F_R-WEK_Xfo
http://youtu.be/dXUTT9J_r7o

Michael Red

unread,
Jul 24, 2011, 5:10:35 AM7/24/11
to pyglet...@googlegroups.com
Looking really fine. Good luck with it. 

Jake b

unread,
Jul 25, 2011, 12:17:59 AM7/25/11
to pyglet...@googlegroups.com
I like the video.

--
Jake
Reply all
Reply to author
Forward
0 new messages