Subclassing rabbyt render()

12 views
Skip to first unread message

penguin

unread,
Dec 21, 2009, 12:19:43 AM12/21/09
to Rabbyt
So what I want to do is display a bunch of moving sprites in 3d, using
rabbyt to create the sprites, and have the x and y values be their
values on a map that is parallel to the x-z plane. The end result
would look like sheets of paper popping out of a flat sheet of paper.
I figure the best way to do this is to just translate (x, 0, -y)
instead of doing the (x, y, 0) translation in rabbyt's default sprite
render() method. Now here's where I run into two problems:

1. I have to do this by subclassing sprite and overriding render() -
but doing so is extremely slow, because (I suspect) I do a bunch of
slow python calls to translate instead of using rabbyt's compiled C
code. To make this faster, the easiest way would be to add a line to
the pyrex code and recompile it, but I don't want to distribute a
slightly-modified rabbyt - the users would have to recompile rabbyt
for their platform, and if they're on windows, I don't even know how
to start with that.

2. I'm confused about the transformations which happen when you draw
and texture a quad in immediate mode in _render(). I have this bit of
code that I used (note that I rotate after the translating instead of
translating directly (x, 0, -y), just for fun's sake)


class xzSprite(rabbyt.Sprite):
def render(self):
#Exactly same as normal rabbyt sprite, except y =
z
x = self.x
y = self.y
sx = self.scale_x
sy = self.scale_y
r = self.rot

if x != 0 or y != 0 or sx != 1 or sy != 1 or r !=
0:
glPushMatrix()
try:
glTranslatef(x, y, 0)
glRotatef
(-90,1,0,0)
if r != 0:
glRotatef(r,0,0,1)
if sx != 1 or sy !=
1:
glScalef(sx, sy, 1)
rabbyt.Sprite.render
(self)
glDisable
(GL_TEXTURE_2D)
glBegin
(GL_QUADS)
glColor4f(1, 1, 0,
0.5)
glVertex3f(-50, -50,
0)
glVertex3f(50, -50, 0)
glVertex3f(50, 50,
0)
glVertex3f(-50, 50,
0)
glEnd()
glEnable
(GL_TEXTURE_2D)
finally:
glPopMatrix()
else:
rabbyt.Sprite.render(self)

As you can see, this is almost BaseSprite's render() verbatim. I would
expect the rendered sprites to line up with the yellow quads I drew,
but the sprites go all over the place. I looked at _render() in rabbyt
source and it seems like you do translate the vertices with a line
like

glVertex2f(vert[1].x*sx+x,vert[1].y*sy+y)

So for sprite's render(), it doesn't render after BaseSprite.render()
transforms but instead directly adds the transforms to the vertices.
Just wanted to bring that up, that caught me a bit off guard and I
thought it was strange... I would naively do a super-call and then
draw the quad according to sprite.shape centered at (0,0,0).

Now, the big question is, what's the best way to subclass render() and
preserve speed? Would it be possible to just change
rabbyt._sprites.pyx, turn that into C, and compile it, and have that
replace the sprites module that comes with a default rabbyt
distribution installed somewhere else? It would be nice to have both x
y and z for a rabbyt sprite, but that would probably just confuse
anyone trying to use the library for 2d. Also, since the actual code
that does any rendering on-screen disregards BaseSprite's
transformations, or so it looks to me, what happens to
render_after_transform (this is just me being lazy and not wanting to
try it out right this moment, hoping you would have the answer)?

Matthew Marshall

unread,
Dec 22, 2009, 6:59:53 PM12/22/09
to Rabbyt
Hey penguin,

It sounds like you can do what you're wanting by rotating the
modelview matrix before rendering the sprites:

glPushMatrix()
glRotatef(60, 1, 0, 0)
rabbyt.render_unsorted(sprites)
glPopMatrix()

Sprite.render flattens rendering into a single call without matrix
transformations for speed. (When you only have four vertexes, it's
much faster to do the transformation in software than manipulate the
opengl transformation matrix.)

Hope that helps.

MWM

penguin

unread,
Dec 22, 2009, 10:46:57 PM12/22/09
to Rabbyt
Hmm, I did something similar to that (glRotatef(90, 1, 0, 0)) as a gut
instinct on my first crack at this, but that just ended up displaying
all the sprites on one plane orthogonal to the 'base plane', as
opposed to distributing the sprites across the plane. What I want are
flat quads popping out of a plane, so to use that with rabbyt the y
coordinate has to be used as the z coordinate. The GL_QUADS sequence
in _render() currently draws the quads lying flat on the plane,
because it doesn't make use of the z coordinate. I'd like to be able
to have a cheap and quick solution, but the best I can puzzle out
right now is subclassing render() to do the transform and the render
coordinates differently.

In essence, your suggestion (and my gut instinct) did was:

glBegin(GL_QUADS)
glVertex3f(p0.x*sx+x, 0, p0.y*sy+y)
glVertex3f(p1.x*sx+x, 0, p1.y*sy+y)
glVertex3f(p2.x*sx+x, 0, p2.y*sy+y)
glVertex3f(p3.x*sx+x, 0, p3.y*sy+y)
glEnd()

but this puts all the images on one plane;
my goal is this:

glTransform(x, y, 0)
glRotate(-90, 1, 0, 0)
glBegin(GL_QUADS)
glVertex2f(-WIDTH/2, -HEIGHT/2)
glVertex2f(WIDTH/2, -HEIGHT/2)
glVertex2f(WIDTH/2, HEIGHT/2)
glVertex2f(-WIDTH/2, HEIGHT/2)
glEnd()

so these quads look like they're popping out of the x-z plane. I'd
love to solve this with a simple transform without subclassing. Any
ideas?

Sprite's _render() already does

glVertex2f(-WIDTH/2+x, -HEIGHT/2+y)
glVertex2f(WIDTH/2+x, -HEIGHT/2+y)
glVertex2f(WIDTH/2+x, HEIGHT/2+y)
glVertex2f(-WIDTH/2+x, HEIGHT/2+y)

for me, but the transform comes inconveniently after the rotation
that's supposed to switch the y and z axes... maybe there's a game to
be played with the x and y coordinates?

Thanks for the help.

On Dec 22, 6:59 pm, Matthew Marshall <matt...@matthewmarshall.org>
wrote:

Matthew Marshall

unread,
Dec 24, 2009, 11:05:08 AM12/24/09
to Rabbyt
Hmm, how about something like this?

class PoppingSprite(Sprite):

Matthew Marshall

unread,
Dec 24, 2009, 11:08:54 AM12/24/09
to Rabbyt
Whoops... accidentally hit tab followed by enter...

class PoppingSprite(Sprite):
z = rabbyt.anim_slot()
def render(self):
glPushMatrix()
glTranslate3f(0,0,self.z)
Sprite.render(self)
glPopMatrix()

This will be quite a bit slower than raw rabbyt sprites, but for your
application it might be fast enough.

MWM

On Dec 24, 10:05 am, Matthew Marshall <matt...@matthewmarshall.org>
wrote:

penguin

unread,
Dec 25, 2009, 2:55:28 AM12/25/09
to Rabbyt
Righto! Works like a charm, and faster than my unnecessary render
rewrite. Sometimes the most straightforward solutions are the best ;)

Happy holidays!

On Dec 24, 11:08 am, Matthew Marshall <matt...@matthewmarshall.org>

Reply all
Reply to author
Forward
0 new messages