Converting a Label to a Texture

77 views
Skip to first unread message

Jonathan Hartley

unread,
Nov 19, 2009, 2:38:02 PM11/19/09
to pyglet-users
Hi all.

I'm trying to convert convert a Label into an Image, to use as a
sprite image.

I'm trying out some code I found posted by pyalot, here on this list:
http://groups.google.com/group/pyglet-users/browse_thread/thread/b6c0fa3550c37e97/4e3c71bd18df799c

My problem is that the text always comes out black (rather than the
Label.__init__() 'color' param.)
Alex suggests in that post that this can be fixed by changing the
texture creation format from GL_RGBA to GL_ALPHA, but this doesn't
seem to fix the problem for me - even though pyalot reported it worked
for them.

Has anyone got any clues for how I might fix this? Thanks!


The reason I'm doing this is that I want the text on screen to slowly
fade away. It will be used as floaty 'points scored' visual feedback
in the game. I plan to achieve this using the sprite.opacity property.
I was previously doing it by simply using a Label on screen, and
modifying its color every frame to make it gradually more transparent.
But as has been discussed elsewhere on this list, this causes a lot of
work to be done under the covers, and it wasn't fast enough when there
were lots of them on screen. If there are better approaches than the
one I'm trying above, I'd be all ears. Thanks.

Jonathan Hartley

unread,
Nov 19, 2009, 3:06:40 PM11/19/09
to pyglet-users
I just realised I understand even less than I thought I did.

The 'glColor3f(1.0, 0.0, 0.0)' in 'on_draw()', four lines from the
bottom of that linked to code snippet. Modifying it demonstrates that
it controls the color of the texture that then gets blitted to the
screen. How the heck does that work? Surely the color of the pixels in
the texture are already set long before 'on_draw()' gets invoked?


On Nov 19, 7:38 pm, Jonathan Hartley <tart...@tartley.com> wrote:
> Hi all.
>
> I'm trying to convert convert a Label into an Image, to use as a
> sprite image.
>
> I'm trying out some code I found posted by pyalot, here on this list:http://groups.google.com/group/pyglet-users/browse_thread/thread/b6c0...

Tristam MacDonald

unread,
Nov 19, 2009, 3:27:04 PM11/19/09
to pyglet...@googlegroups.com
On Thu, Nov 19, 2009 at 3:06 PM, Jonathan Hartley <tar...@tartley.com> wrote:
I just realised I understand even less than I thought I did.

The 'glColor3f(1.0, 0.0, 0.0)' in 'on_draw()', four lines from the
bottom of that linked to code snippet. Modifying it demonstrates that
it controls the color of the texture that then gets blitted to the
screen. How the heck does that work? Surely the color of the pixels in
the texture are already set long before 'on_draw()' gets invoked?

If GL_COLOR_MATERIAL is enabled, OpenGL multiplies all texture colours by the interpolated vertex colour during texture-mapping.

Thus, as long as the pixels in your texture are something sensible (i.e. white), you can use glColor to re-colour the rendered texture on the fly.

--
Tristam MacDonald
http://swiftcoder.wordpress.com/

Tristam MacDonald

unread,
Nov 19, 2009, 3:29:21 PM11/19/09
to pyglet...@googlegroups.com
Scratch that, I was thinking of lighting.

The vertex colour *always* multiplies the texture pixel colour.

Jonathan Hartley

unread,
Nov 19, 2009, 4:58:37 PM11/19/09
to pyglet-users
Ahar! Thanks - so it does. Thanks very much for the pointer.

I shall interpret that as a clue as I look for why the text looks
black in my own application. Obviously I made sure that vertex color
is set to something non-black, but that hasn't fixed it.




On Nov 19, 8:29 pm, Tristam MacDonald <swiftco...@gmail.com> wrote:
> On Thu, Nov 19, 2009 at 3:27 PM, Tristam MacDonald <swiftco...@gmail.com>wrote:

Tristam MacDonald

unread,
Nov 19, 2009, 5:16:23 PM11/19/09
to pyglet...@googlegroups.com
On Thu, Nov 19, 2009 at 4:58 PM, Jonathan Hartley <tar...@tartley.com> wrote:
Ahar! Thanks - so it does. Thanks very much for the pointer.

I shall interpret that as a clue as I look for why the text looks
black in my own application. Obviously I made sure that vertex color
is set to something non-black, but that hasn't fixed it.

Are the pixels in your texture black (since 0*x == 0)? A common problem is that someone manages to encode an opaque, black texture in an RGBA format...

Jonathan Hartley

unread,
Nov 19, 2009, 5:54:12 PM11/19/09
to pyglet-users
The texture's transparent pixels (around the text) come out as the
screen background color, they are perfect.
The problem is with the pixels which make up the text - they are
black, I expected the text baked into the texture to be the same color
that I created the text Label as.

I just got home, I'll do more tests now... ta!


On Nov 19, 10:16 pm, Tristam MacDonald <swiftco...@gmail.com> wrote:

Jonathan Hartley

unread,
Nov 20, 2009, 5:21:30 AM11/20/09
to pyglet-users
I have made some progress figuring this out. Minimal code repro below.

The text unexpectedly appears black only when I convert my Texture
into an ImageData, by calling get_image_data() on it.

I did this conversion because I add the image to a texture atlas for
rendering speed, and when adding the original Texture, I got:

File "C:\Python26\lib\site-packages\pyglet\image\__init__.py", line
482, in
blit_to_texture
raise ImageException('Cannot blit %r to a texture.' %
self)
pyglet.image.ImageException: Cannot blit <TextureRegion 12x28> to a
texture.


So, I think my only absolutely critical question is: How should I be
adding the Textures returned from label2texture() to my texture atlas?


Howevever, I clearly still have minstunderstood lots.

If I remove all usage of a Texture atlas (as in the minimal repro
below) and leave the Texture as a Texture, then the text is not
rendered black. It is rendered exactly as the current vertex color.
This still surprises me. Tristam, you say that the vertex color
multiplies the texture color, which I interpret to mean:

color visible on screen = pixel color in the texture * current
vertext color

(where all these are three component rgb values, with each component
normalised to lie within range 0.0 to 1.0, and the multiply operator
works like this:

Rout = Rtexture * Rvert
Gout = Gtexture * Gvert
Bout = Btexture * Bvert

But that isn't precisely what I'm seeing. As visible in the repro
below, it looks like:

color visible on screen = current vertext color

i.e. the drawing the label yellow (255, 255, 0), and setting the
current pixel color to blue (0, 0, 255), I see blue text on screen.
How does Bout get a non-zero value, if Btexture = 0?

Thanks for any understanding anyone can bequeath me with.

- Jonathan aka tartley




import code
import pyglet
from pyglet.text import Label
from pyglet.gl import *


def label2texture(label):
vertex_list = label._vertex_lists[0].vertices[:]
xpos = map(int, vertex_list[::8])
ypos = map(int, vertex_list[1::8])
glyphs = label._get_glyphs()

xstart = xpos[0]
xend = xpos[-1] + glyphs[-1].width
width = xend - xstart

ystart = min(ypos)
yend = max(ystart+glyph.height for glyph in glyphs)
height = yend - ystart

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

for glyph, x, y in zip(glyphs, xpos, ypos):
data = glyph.get_image_data()
x = x - xstart
y = height - glyph.height - y + ystart
texture.blit_into(data, x, y, 0)

return texture


class Render(object):

def create_image(self):
label = pyglet.text.Label(
text='yellow text',
font_name = 'Times New Roman',
font_size = 48,
bold = True,
x = 20,
y = 5,
color = (255, 255, 0, 255), # YELLOW
)
image = label2texture(label)

# converting the Texture to an ImageData turns the text black
# so don't do that
# but then how can we add this texture to a texture atlas?
# image = image.get_image_data()

image.anchor_x = image.width / 2
image.anchor_y = image.height / 2
return image


def init(self):
self.win = pyglet.window.Window()
self.win.on_draw = self.draw

glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glClearColor(0.9, 0.5, 0.7, 0.0)

self.image = self.create_image()

pyglet.app.run()


def draw(self):
glClear(GL_COLOR_BUFFER_BIT)
glColor3f(0.0, 0.0, 1.0) # current vertex color = blue

# image displays text in the current vertex color?
self.image.blit(self.win.width / 2, self.win.height / 2)


if __name__ == '__main__':
r = Render()
r.init()

Jonathan Hartley

unread,
Nov 20, 2009, 5:23:57 AM11/20/09
to pyglet-users
I should be going back to re-read my opengl books shouldn't I? Alright
I'll do that.

Also: I don't usually spell 'vertex' like that. I need my morning
coffee.

Jonathan Hartley

unread,
Nov 20, 2009, 6:01:29 AM11/20/09
to pyglet-users
I'm slowly getting it. Sorry for all the traffic.

I just understood the significance of creating the texture above using
the GL_ALPHA flag. The texture I am creating only has an alpha channel
- no RGB. That explains the behaviour I'm seeing perfectly.

So my only outstanding question is, how do I get the texture regions
generated by label2texture into my application's texture atlas? I
thought that an atlas must copy the textures it is given into its own
internal texture, so I don't get why it cares about the type of the
image which is added.

I'm only using this atlas because, up until now, everything visible in
my application (background, sprites, hud images, etc,) has gone into
the atlas, to be rendered with a single batch.draw(). So I figured I'd
stick with that pattern if I could.

Jonathan Hartley

unread,
Nov 20, 2009, 6:56:10 PM11/20/09
to pyglet-users
And, for the benefit of future Googlers, the texel/vertex color
combining that Tristam describes above is described in loving detail
under the documentation for

glTexEnvi(GLenum target, GLenum pname, GLint param)

(and its type-clones).

I have no perceptible performance problems even if I don't put these
Textures into my application's atlas, at least not compared to my n^2
collision detection, so unless anyone has any bright ideas they are
just bursting to tell, I'm not going to worry about that any more.

In the twisted world I live in, a screenshot like the following serves
as some sort of compensation for putting up with my silly questions
all day and all night.

A mild stress test of my 'floating / fading numbers' now that I sort
of half understand what's going on:
http://brokenspell.googlecode.com/svn/trunk/docs/screenshots/screenshot05-performance-test-hudpoints.jpg

For what it's worth, I would like it if people would post most
screenshots of works in progress to pyglet-users.

Best,

Jonathan

Florian Bösch

unread,
Nov 22, 2009, 4:12:48 AM11/22/09
to pyglet-users
On Nov 20, 12:01 pm, Jonathan Hartley <tart...@tartley.com> wrote:
> So my only outstanding question is, how do I get the texture regions
> generated by label2texture into my application's texture atlas? I
> thought that an atlas must copy the textures it is given into its own
> internal texture, so I don't get why it cares about the type of the
> image which is added.

Got it all solved here http://hg.codeflow.org/sociograph/file/d8008313a174/sociograph/atlas.py

Cheers,
Florian

Jonathan Hartley

unread,
Nov 22, 2009, 8:25:10 PM11/22/09
to pyglet-users
That's really great - I get an extra 20fps with that bad boy, when
running without vsync. That extra time will come in real handy. Thanks
heaps!

Jonathan Hartley

unread,
Jan 9, 2010, 12:30:09 PM1/9/10
to pyglet-users
On Nov 23 2009, 1:25 am, Jonathan Hartley <tart...@tartley.com> wrote:
> That's really great - I get an extra 20fps with that bad boy, when
> running without vsync. That extra time will come in real handy. Thanks
> heaps!
>
> On Nov 22, 9:12 am, Florian Bösch <pya...@gmail.com> wrote:
>
> > On Nov 20, 12:01 pm, Jonathan Hartley <tart...@tartley.com> wrote:
>
> > > So my only outstanding question is, how do I get the texture regions
> > > generated by label2texture into my application's textureatlas? I
> > > thought that anatlasmust copy the textures it is given into its own

> > > internal texture, so I don't get why it cares about the type of the
> > > image which is added.
>
> > Got it all solved herehttp://hg.codeflow.org/sociograph/file/d8008313a174/sociograph/atlas.py
>
> > Cheers,
> > Florian
>
>


I just realised why you included the 'get_transform(flip_y=True)' at
the end - that isn't required on Windows so I deleted it. But now on
Linux all my bitmaps are upside down! :-)

Reply all
Reply to author
Forward
0 new messages