Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Embedded pyglet Widget
Forum Updated to NodeBB v4.3 + New Features

Embedded pyglet Widget

Scheduled Pinned Locked Moved Unsolved Qt for Python
qt for pythonpython
4 Posts 2 Posters 1.3k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • G Offline
    G Offline
    gadese
    wrote on 3 Jun 2022, 21:43 last edited by
    #1

    Hi,

    I currently have a Pyglet window running a simple 3D scene (simple shapes moving in the scene). I would like to build a GUI around this window using PyQt. Ideally, I would have an embedded Widget showing the scene, and a bunch of buttons/sliders that would let me add or move objects in the scene. I've been searching for most of this week, but haven't really found anything to help me, apart from a few obscure forums threads for 2007 or 2009. Note that I am not an OpenGL expert.

    I have been trying to adapt this repo from 2013 and I've managed to make some progress, but I'm currently a bit stuck. I've been trying to display simple pyglet text through a custom PyQt widget, but the display isn't right. I know something is working because I can correctly change the scene's background color, but drawing text or shapes aren't working properly as you can see in the image below

    efae091d-a56f-45de-9863-a2004a803fab-image.png .

    I'm not sure what to look at next, any insight would be very appreciated. My code is below (it's pretty simple)

    """
    This module contains the definiton of a pyglet widget for a 
    PySide application: QPygletWidget
    It also provides a basic usage example.
    """
    import sys
    import pyglet
    pyglet.options['shadow_window'] = False
    pyglet.options['debug_gl'] = False
    from pyglet import gl
    from PyQt5 import QtCore, QtOpenGL, QtWidgets
    
    
    class ObjectSpace(object):
        """ Object space mocker """
        def __init__(self):
            # Textures and buffers scheduled for deletion the next time this
            # object space is active.
            self._doomed_textures = []
            self._doomed_buffers = []
    
    
    class Context(object):
        """
        pyglet.gl.Context mocker. This is used to make pyglet believe that a valid
        context has already been setup. (Qt takes care of creating the open gl
        context)
        _Most of the methods are empty, there is just the minimum required to make
        it look like a duck..._
        """
            # define the same class attribute as pyglet.gl.Context
        CONTEXT_SHARE_NONE = None
        CONTEXT_SHARE_EXISTING = 1
        _gl_begin = False
        _info = None
        _workaround_checks = [
            ('_workaround_unpack_row_length',
             lambda info: info.get_renderer() == 'GDI Generic'),
            ('_workaround_vbo',
             lambda info: info.get_renderer().startswith('ATI Radeon X')),
            ('_workaround_vbo_finish',
             lambda info: ('ATI' in info.get_renderer() and
                           info.have_version(1, 5) and
                           sys.platform == 'darwin'))]
    
        def __init__(self, context_share=None):
            """
            Setup workaround attr and object spaces (again to mock what is done in
            pyglet context)
            """
            self.object_space = ObjectSpace()
            for attr, check in self._workaround_checks:
                setattr(self, attr, None)
    
        def __repr__(self):
            return '%s()' % self.__class__.__name__
    
        def set_current(self):
            pass
    
        def destroy(self):
            pass
    
        def delete_texture(self, texture_id):
            pass
    
        def delete_buffer(self, buffer_id):
            pass
    
    
    class QPygletWidget(QtOpenGL.QGLWidget):
        """
        A simple pyglet widget.
        User can subclass this widget and implement the following methods:
            - on_init: called when open gl has been initialised
            - on_update: called every dt.
            - on_draw: called when paintGL is executed
            - on_resize: called when resizeGL is executed
        """
        def __init__(self, parent=None,
                     clear_color=(0.0, 0.0, 0.0, 1.0),
                     frame_time=32,
                     dt=16):
            """
            :param clear_color: The widget clear color
            :type clear_color: tuple(r, g, b, a)
            :param frame_time: The desired frame time [ms]
            :type: frame_time: int
            :param dt: The desired update rate [ms]
            :type: dt: int
            """
            QtOpenGL.QGLWidget.__init__(self, parent)
    
            # init members
            self._clear_color = clear_color
            self._dt = dt
            self.update_timer = QtCore.QTimer()
            self.draw_timer = QtCore.QTimer()
    
            # configure draw and update timers
            self.update_timer.setInterval(dt)
            self.update_timer.timeout.connect(self._update)
            self.draw_timer.setInterval(frame_time)
            self.draw_timer.timeout.connect(self.updateGL)
    
            # start timers
            self.update_timer.start()
            self.draw_timer.start()
    
        def _update(self):
            """
            Calls on_update with the choosen dt
            """
            self.on_update(self._dt)
    
        def on_init(self):
            """
            Lets the user initialise himself
            """
            pass
    
        def on_draw(self):
            """
            Lets the user draw his scene
            """
            pass
    
        def on_update(self, dt):
            """
            Lets the user draw his scene
            """
            pass
    
        def on_resize(self, w, h):
            """
            Lets the user handle the widget resize event. By default, this method
            resizes the view to the widget size.
            """
            gl.glViewport(0, 0, w, h)
            gl.glMatrixMode(gl.GL_PROJECTION)
            gl.glLoadIdentity()
            gl.glOrtho(0, w, 0, h, -1, 1)
            gl.glMatrixMode(gl.GL_MODELVIEW)
    
        def initializeGL(self):
            """
            Initialises open gl:
                - create a mock context to fool pyglet
                - setup various opengl rule (only the clear color atm)
            """
            # display = pyglet.canvas.get_display()
            # screen = display.get_default_screen()
    
            # template = pyglet.gl.Config()
            # config = screen.get_best_config(template)
            # context = config.create_context(None)
            # gl.current_context = context
            
            gl.current_context = Context()
            gl.glClearColor(0.5, 0.7, 1, 1)
            self.on_init()
    
        def resizeGL(self, w, h):
            """
            Resizes the gl camera to match the widget size.
            """
            self.on_resize(w, h)
    
        def paintGL(self):
            """
            Clears the back buffer than calls the on_draw method
            """
            gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
            self.on_draw()
    
    
    class MyPygletWidget(QPygletWidget):
        def on_init(self):
            self.label = pyglet.text.Label('This is a pyglet label rendered in a Qt widget :)',
                              font_name='Times New Roman',
                              font_size=36,
                              x=180, y=200,
                              anchor_x='center', anchor_y='center')
    
            self.setMinimumSize(QtCore.QSize(640, 480))
    
        def on_draw(self):
            self.label.draw()
    
    class Window(QtWidgets.QMainWindow):
        def __init__(self):
            super().__init__()
            self.widget = MyPygletWidget()
            self.setCentralWidget(self.widget)
    
    def main():
        app = QtWidgets.QApplication(sys.argv)
        window = Window()
        window.show()
        sys.exit(app.exec())
    
    
    if __name__ == "__main__":
        main()
    
    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on 4 Jun 2022, 19:42 last edited by
      #2

      Hi and welcome to devnet,

      Did you already tried with using QOpenGLWidget ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      1
      • G Offline
        G Offline
        gadese
        wrote on 6 Jun 2022, 12:53 last edited by gadese 6 Jun 2022, 13:22
        #3

        Yes I've tried QOpenGLWidget, and I get the same issue. The problem seems to be the pyglet integration and getting pyglet to use the OpenGL context created by QOpenGLWidget or QGLWidget rather than its own.

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on 4 Aug 2022, 20:04 last edited by
          #4

          I tested your sample code with a conda environment, latest PyQt5, pyglet from pip and while the text is not properly placed, it's rendered correctly.

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          0

          • Login

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • Users
          • Groups
          • Search
          • Get Qt Extensions
          • Unsolved