3
\$\begingroup\$

I just started OpenGL (PyopenGl) & Pyglet 3 weeks ago, and decided to read the Red Book. So sorry if my question shows my lack of comprehension...

My question is: Is it possible to display/write text using text.Label().draw in a FBO ?

What I want to do is use text.Label().draw to generate a texture and use that texture when I need it. But so far I haven't been able to do it. (lack of comprehension/experience?) I know that text in OpenGl is usually done by Bitmap Fonts, Outline Fonts or Texture Mapped Text, but I was wondering if the method I am thinking of could be a sortcut.

So sorry again if this question is stupid/obvious, but I'm still learning and did spend a lot of time looking/searching for an answer.

Thanks guys.

\$\endgroup\$
  • \$\begingroup\$ From what I learned, rendering to FBOs in pyglet seems to be for experienced developers. You also depend on your users openGL drivers supporting frame buffer extensions. Not all drivers do that. Have you thought about doing the rendering with, like, PIL? \$\endgroup\$ – J. Katzwinkel Jul 20 '13 at 9:46
  • \$\begingroup\$ No I haven't... Thanks for the advice. I will have a look. \$\endgroup\$ – BaldDude Jul 20 '13 at 18:40
1
\$\begingroup\$

It is possible with Pyglet (even without PyOpenGL), I've successfully done it with the following code (slightly modified). However, my Pyglet version is a little behind.

With the code you can create a valid Pyglet texture which you can use as a render target. Set the render target to None when you want to draw to the screen again.

import pyglet, traceback, math, ctypes
from pyglet.gl import *

SCREEN_WIDTH = 1024
SCREEN_HEIGHT = 768
FBO = None

def SetScreen(self, left, top, right, bottom):
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity();
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    glOrtho(left,right,bottom,top,-1.0,1.0)
    glMatrixMode(GL_MODELVIEW)

def SetRenderTarget(texture=None):
    if not texture:
        # use screen when no texture was specified
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)
        glViewport(0,0,SCREEN_WIDTH,SCREEN_HEIGHT)
        SetScreen(0,0,SCREEN_WIDTH,SCREEN_HEIGHT)
    else:
        # create FBO object once
        if not FBO:
            FBO = GLuint()
            glGenFramebuffersEXT(1, ctypes.byref(self.FBO))

        # bind the frame buffer
        glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, FBO)

        # check that the texture has a depth render-buffer (not strictly neccessary)
        try: _t = texture.DepthRB
        except:
            texture.DepthRB = GLuint()
            glGenRenderbuffersEXT(1, ctypes.byref(texture.DepthRB))
            glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, texture.DepthRB)
            glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT16, texture.width, texture.height)

        # bind texture and depth buffer to FBO
        glBindTexture(texture.target, texture.id)
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, texture.target, texture.id, 0)
        glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, texture.DepthRB)

        # clear FBO and set some GL defaults
        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        glEnable(GL_DEPTH_TEST)
        glDepthFunc(GL_LEQUAL)
        glClearDepth(1.0)
        glClearColor(0.5, 0.0, 0.5, 0.0)  # set clear color yourself!
        glViewport(0,0, texture.width, texture.height)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        SetScreen(0, 0, texture.width, texture.height)

        # simple error checking
        status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT)
        assert status == GL_FRAMEBUFFER_COMPLETE_EXT

def CreateTexture(size=512, fmt=GL_RGBA, data=None):
    if type(size) == int:
        w = size
        h = size
    else:
        w = int(size[0])
        h = int(size[1])

    tid = GLuint()
    target = GL_TEXTURE_2D

    glGenTextures(1, byref(tid))
    glBindTexture(target, tid.value)
    glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR)

    if not data:
        blank = (GLubyte * (w * h * 4))()
        data = blank

    glTexImage2D(target, 0,
                 fmt,
                 w, h,
                 0,
                 GL_RGBA, GL_UNSIGNED_BYTE,
                 data)

    return pyglet.image.Texture(w, h, target, tid.value)
\$\endgroup\$
0
\$\begingroup\$

You can render piglet.text.label into a frame buffer object, but you will need to manage the FBO and rendering the label into it yourself. Pyglet does not provide primitives for manipulating and rendering to FBOs.

However, assuming that you are considering this for performance reasons, I would generally advise that you use batching instead. Pyglet includes robust batching support, and piglet.text.Label can be initialized with a Batch object, which will provide significantly improved performance when rendering the same text for multiple frames.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.