Esempio n. 1
0
class WindowGL(QWindow):
    def __init__(self):
        super().__init__()

        fmt = QSurfaceFormat()
        fmt.setVersion(2, 0)
        fmt.setProfile(QSurfaceFormat.CompatibilityProfile)
        fmt.setStereo(False)
        fmt.setSwapBehavior(QSurfaceFormat.DoubleBuffer)

        self.setSurfaceType(QWindow.OpenGLSurface)
        self.context = QOpenGLContext()
        self.context.setFormat(fmt)

        if not self.context.create():
            raise Exception("Unable to create context")

        self.create()
        self.setTitle("OpenGL")

    def exposeEvent(self, e):
        e.accept()
        if self.isExposed() and self.isVisible():
            self.update()

    def makeCurrent(self):
        self.context.makeCurrent(self)

    def swapBuffers(self):
        self.context.swapBuffers(self)

    def resize(self, w, h):
        super().resize(w, h)
        self.makeCurrent()
        GL.glViewport(0, 0, w, h)

    def update(self):
        tri_size = 0.7
        self.makeCurrent()
        GL.glClearColor(0, 0, 0, 0)
        GL.glClearDepth(1)
        GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
        GL.glBegin(GL.GL_TRIANGLES)
        GL.glVertex2f(0, tri_size)
        GL.glColor3f(1, 0, 0)
        GL.glVertex2f(-tri_size, -tri_size)
        GL.glColor3f(0, 1, 0)
        GL.glVertex2f(tri_size, -tri_size)
        GL.glColor3f(0, 0, 1)
        GL.glEnd()
        GL.glFlush()
        self.swapBuffers()
Esempio n. 2
0
def offscreen_context(format):
    """Provide a temporary QOpenGLContext with the given QSurfaceFormat on an
    QOffscreenSurface."""
    surface = QOffscreenSurface()
    surface.create()
    context = QOpenGLContext()
    context.setFormat(format)
    context.create()
    context.makeCurrent(surface)
    try:
        yield context
    finally:
        context.doneCurrent()
Esempio n. 3
0
class GLWindow(QWindow):
    def __init__(self):
      super(GLWindow, self).__init__()
      self.title= "GLWindow"
      self.setGeometry(0, 0, 640, 480)
      self.setupUI()
      
    def setupUI(self):  
      self.setSurfaceType(QWindow.OpenGLSurface)
      self.renderctxt = QOpenGLContext(self)
      self.renderctxt.setFormat(self.requestedFormat())
      self.renderctxt.create()
      self.renderctxt.makeCurrent(self)
      self.glfunc = self.renderctxt.versionFunctions()
      self.glfunc.initializeOpenGLFunctions()
Esempio n. 4
0
def opengl_info() -> Optional[OpenGLInfo]:  # pragma: no cover
    """Get the OpenGL vendor used.

    This returns a string such as 'nouveau' or
    'Intel Open Source Technology Center'; or None if the vendor can't be
    determined.
    """
    assert QApplication.instance()

    override = os.environ.get('QUTE_FAKE_OPENGL')
    if override is not None:
        log.init.debug("Using override {}".format(override))
        vendor, version = override.split(', ', maxsplit=1)
        return OpenGLInfo.parse(vendor=vendor, version=version)

    old_context = cast(Optional[QOpenGLContext],
                       QOpenGLContext.currentContext())
    old_surface = None if old_context is None else old_context.surface()

    surface = QOffscreenSurface()
    surface.create()

    ctx = QOpenGLContext()
    ok = ctx.create()
    if not ok:
        log.init.debug("Creating context failed!")
        return None

    ok = ctx.makeCurrent(surface)
    if not ok:
        log.init.debug("Making context current failed!")
        return None

    try:
        if ctx.isOpenGLES():
            # Can't use versionFunctions there
            return OpenGLInfo(gles=True)

        vp = QOpenGLVersionProfile()
        vp.setVersion(2, 0)

        try:
            vf = ctx.versionFunctions(vp)
        except ImportError as e:
            log.init.debug("Importing version functions failed: {}".format(e))
            return None

        if vf is None:
            log.init.debug("Getting version functions failed!")
            return None

        vendor = vf.glGetString(vf.GL_VENDOR)
        version = vf.glGetString(vf.GL_VERSION)

        return OpenGLInfo.parse(vendor=vendor, version=version)
    finally:
        ctx.doneCurrent()
        if old_context and old_surface:
            old_context.makeCurrent(old_surface)
Esempio n. 5
0
def opengl_vendor():  # pragma: no cover
    """Get the OpenGL vendor used.

    This returns a string such as 'nouveau' or
    'Intel Open Source Technology Center'; or None if the vendor can't be
    determined.
    """
    assert QApplication.instance()

    override = os.environ.get('QUTE_FAKE_OPENGL_VENDOR')
    if override is not None:
        log.init.debug("Using override {}".format(override))
        return override

    old_context = QOpenGLContext.currentContext()
    old_surface = None if old_context is None else old_context.surface()

    surface = QOffscreenSurface()
    surface.create()

    ctx = QOpenGLContext()
    ok = ctx.create()
    if not ok:
        log.init.debug("Creating context failed!")
        return None

    ok = ctx.makeCurrent(surface)
    if not ok:
        log.init.debug("Making context current failed!")
        return None

    try:
        if ctx.isOpenGLES():
            # Can't use versionFunctions there
            return None

        vp = QOpenGLVersionProfile()
        vp.setVersion(2, 0)

        try:
            vf = ctx.versionFunctions(vp)
        except ImportError as e:
            log.init.debug("Importing version functions failed: {}".format(e))
            return None

        if vf is None:
            log.init.debug("Getting version functions failed!")
            return None

        return vf.glGetString(vf.GL_VENDOR)
    finally:
        ctx.doneCurrent()
        if old_context and old_surface:
            old_context.makeCurrent(old_surface)
Esempio n. 6
0
def opengl_vendor():  # pragma: no cover
    """Get the OpenGL vendor used.

    This returns a string such as 'nouveau' or
    'Intel Open Source Technology Center'; or None if the vendor can't be
    determined.
    """
    assert QApplication.instance()

    old_context = QOpenGLContext.currentContext()
    old_surface = None if old_context is None else old_context.surface()

    surface = QOffscreenSurface()
    surface.create()

    ctx = QOpenGLContext()
    ok = ctx.create()
    if not ok:
        log.init.debug("opengl_vendor: Creating context failed!")
        return None

    ok = ctx.makeCurrent(surface)
    if not ok:
        log.init.debug("opengl_vendor: Making context current failed!")
        return None

    try:
        if ctx.isOpenGLES():
            # Can't use versionFunctions there
            return None

        vp = QOpenGLVersionProfile()
        vp.setVersion(2, 0)

        try:
            vf = ctx.versionFunctions(vp)
        except ImportError as e:
            log.init.debug("opengl_vendor: Importing version functions "
                           "failed: {}".format(e))
            return None

        if vf is None:
            log.init.debug("opengl_vendor: Getting version functions failed!")
            return None

        return vf.glGetString(vf.GL_VENDOR)
    finally:
        ctx.doneCurrent()
        if old_context and old_surface:
            old_context.makeCurrent(old_surface)
Esempio n. 7
0
def opengl_vendor():  # pragma: no cover
    """Get the OpenGL vendor used.

    This returns a string such as 'nouveau' or
    'Intel Open Source Technology Center'; or None if the vendor can't be
    determined.
    """
    # We're doing those imports here because this is only available with Qt 5.4
    # or newer.
    from PyQt5.QtGui import (QOpenGLContext, QOpenGLVersionProfile,
                             QOffscreenSurface)
    assert QApplication.instance()

    old_context = QOpenGLContext.currentContext()
    old_surface = None if old_context is None else old_context.surface()

    surface = QOffscreenSurface()
    surface.create()

    ctx = QOpenGLContext()
    ok = ctx.create()
    if not ok:
        log.init.debug("opengl_vendor: Creating context failed!")
        return None

    ok = ctx.makeCurrent(surface)
    if not ok:
        log.init.debug("opengl_vendor: Making context current failed!")
        return None

    try:
        if ctx.isOpenGLES():
            # Can't use versionFunctions there
            return None

        vp = QOpenGLVersionProfile()
        vp.setVersion(2, 0)

        vf = ctx.versionFunctions(vp)
        if vf is None:
            log.init.debug("opengl_vendor: Getting version functions failed!")
            return None

        return vf.glGetString(vf.GL_VENDOR)
    finally:
        ctx.doneCurrent()
        if old_context and old_surface:
            old_context.makeCurrent(old_surface)
Esempio n. 8
0
def opengl_vendor():  # pragma: no cover
    """Get the OpenGL vendor used.

    This returns a string such as 'nouveau' or
    'Intel Open Source Technology Center'; or None if the vendor can't be
    determined.
    """
    # We're doing those imports here because this is only available with Qt 5.4
    # or newer.
    from PyQt5.QtGui import (QOpenGLContext, QOpenGLVersionProfile,
                             QOffscreenSurface)
    assert QApplication.instance()

    old_context = QOpenGLContext.currentContext()
    old_surface = None if old_context is None else old_context.surface()

    surface = QOffscreenSurface()
    surface.create()

    ctx = QOpenGLContext()
    ok = ctx.create()
    if not ok:
        log.init.debug("opengl_vendor: Creating context failed!")
        return None

    ok = ctx.makeCurrent(surface)
    if not ok:
        log.init.debug("opengl_vendor: Making context current failed!")
        return None

    try:
        if ctx.isOpenGLES():
            # Can't use versionFunctions there
            return None

        vp = QOpenGLVersionProfile()
        vp.setVersion(2, 0)

        vf = ctx.versionFunctions(vp)
        if vf is None:
            log.init.debug("opengl_vendor: Getting version functions failed!")
            return None

        return vf.glGetString(vf.GL_VENDOR)
    finally:
        ctx.doneCurrent()
        if old_context and old_surface:
            old_context.makeCurrent(old_surface)
Esempio n. 9
0
def opengl_vendor():  # pragma: no cover
    """Get the OpenGL vendor used.

    This returns a string such as 'nouveau' or
    'Intel Open Source Technology Center'; or None if the vendor can't be
    determined.
    """
    # We're doing those imports here because this is only available with Qt 5.4
    # or newer.
    from PyQt5.QtGui import (QOpenGLContext, QOpenGLVersionProfile,
                             QOffscreenSurface)
    assert QApplication.instance()
    assert QOpenGLContext.currentContext() is None

    surface = QOffscreenSurface()
    surface.create()

    ctx = QOpenGLContext()
    ok = ctx.create()
    assert ok

    ok = ctx.makeCurrent(surface)
    assert ok

    if ctx.isOpenGLES():
        # Can't use versionFunctions there
        return None

    vp = QOpenGLVersionProfile()
    vp.setVersion(2, 0)

    vf = ctx.versionFunctions(vp)
    vendor = vf.glGetString(vf.GL_VENDOR)
    ctx.doneCurrent()

    return vendor
Esempio n. 10
0
class OpenGLWindow(QWindow):
    def __init__(self, parent=None):
        super(OpenGLWindow, self).__init__(parent)

        self.m_update_pending = False
        self.m_animating = False
        self.m_context = None
        self.m_gl = None

        self.setSurfaceType(QWindow.OpenGLSurface)

    def initialize(self):
        pass

    def setAnimating(self, animating):
        self.m_animating = animating

        if animating:
            self.renderLater()

    def renderLater(self):
        if not self.m_update_pending:
            self.m_update_pending = True
            QGuiApplication.postEvent(self, QEvent(QEvent.UpdateRequest))

    def renderNow(self):
        if not self.isExposed():
            return

        self.m_update_pending = False

        needsInitialize = False

        if self.m_context is None:
            self.m_context = QOpenGLContext(self)
            self.m_context.setFormat(self.requestedFormat())
            self.m_context.create()

            needsInitialize = True

        self.m_context.makeCurrent(self)

        if needsInitialize:
            self.m_gl = self.m_context.versionFunctions()
            self.m_gl.initializeOpenGLFunctions()

            self.initialize()

        self.render(self.m_gl)

        self.m_context.swapBuffers(self)

        if self.m_animating:
            self.renderLater()

    def event(self, event):
        if event.type() == QEvent.UpdateRequest:
            self.renderNow()
            return True

        return super(OpenGLWindow, self).event(event)

    def exposeEvent(self, event):
        self.renderNow()

    def resizeEvent(self, event):
        self.renderNow()
Esempio n. 11
0
class ViewerWindow(QWindow):

    instructions = """
--Key controls
0-9     - toggle data layers
r       - reset view parameters
c       - clip view
t       - view from top
l       - light/dark background
=       - increase point size
-       - decrease point size

--Mouse controls
drag               
shift + move         - translate dataset
scroll               - scale dataset
shift + scroll       - change field of view
ctrl + scroll        - move far clipping plane
alt + scroll         - move near clipping plane
ctrl + alt + scroll  - move far and near clipping plane simultaniously
"""

    def __init__(self, parent=None, **kwargs):
        super(ViewerWindow, self).__init__(parent)
        self.setSurfaceType(QWindow.OpenGLSurface)

        format = QSurfaceFormat()
        format.setVersion(3, 3)
        format.setProfile(QSurfaceFormat.CoreProfile)
        format.setStereo(False)
        format.setSwapBehavior(QSurfaceFormat.DoubleBuffer)
        format.setDepthBufferSize(24)
        format.setSamples(16)

        self.context = QOpenGLContext(self)
        self.context.setFormat(format)
        if not self.context.create():
            raise Exception('self.context.create() failed')
        self.create()

        size = 720, 720
        self.resize(*size)

        self.context.makeCurrent(self)
        self.hud_program = CrossHairProgram()

        self.default_view = np.eye(4, dtype=np.float32)
        self.view = self.default_view
        self.model = np.eye(4, dtype=np.float32)
        self.projection = np.eye(4, dtype=np.float32)

        self.layer_manager = LayerManager()

        self.visibility_toggle_listeners = []
        self.multiview = True

        self.rotation = q.quaternion()
        self.scale = 0.6
        self.translation = np.zeros(3)

        self.radius = 0.5 * min(*size)
        self.fov = 5.
        self.camera_position = -12.
        self.near_clip = .1
        if 'near_clip' in kwargs:
            self.near_clip = kwargs['near_clip']
        self.far_clip = 100.
        if 'far_clip' in kwargs:
            self.far_clip = kwargs['far_clip']

        self.projection_mode = 'perspective'  # 'orthographic'

        self.size = size
        self.bg_white = False
        self.viewpoint_dict = {}

        print((self.instructions))

    def add_layer(self, layer):
        self.layer_manager.add_layer(layer)
        return layer

    # keeping this compatibility with older scripts
    def add_data_source(self,
                        name,
                        opts,
                        points,
                        normals=None,
                        radii=None,
                        intensity=None,
                        category=None,
                        zrange=None,
                        **kwargs):
        if len(self.layer_manager.layers) == 0:
            self.layer_manager.add_layer(Layer(name='Default'))
        self.layer_manager.layers['Default'].add_data_source(
            name,
            opts,
            points,
            normals=normals,
            radii=radii,
            intensity=intensity,
            category=category,
            zrange=zrange,
            **kwargs)

    def add_data_source_line(self, name, coords_start, coords_end, **args):
        if len(self.layer_manager.layers) == 0:
            self.layer_manager.add_layer(Layer(name='Default'))
        self.layer_manager.layers['Default'].add_data_source_line(
            name, coords_start, coords_end, **args)

    def add_data_source_triangle(self, name, coords, normals, **args):
        if len(self.layer_manager.layers) == 0:
            self.layer_manager.add_layer(Layer(name='Default'))
        self.layer_manager.layers['Default'].add_data_source_triangle(
            name, coords, normals, **args)

    def run(self):
        self.initialize()
        self.show()

    def set_layer_visibility(self, name, is_visible):
        for listener in self.visibility_toggle_listeners:
            listener(name, is_visible)

    def center_view(self, center=None):
        if center is None:
            center = self.layer_manager.first.get_center()
            data_range = self.layer_manager.first.data_range
            self.data_width = data_range[0]
            self.data_height = data_range[2]
        self.translation = np.zeros(3)
        self.model = np.eye(4, dtype=np.float32)
        translate(self.model, -center[0], -center[1], -center[2])
        for program in self.layer_manager.programs():
            program.setUniform('u_model', self.model)
        self.update_view_matrix()

    def initialize(self):
        self.context.makeCurrent(self)

        gl.glDepthMask(gl.GL_TRUE)
        gl.glEnable(gl.GL_DEPTH_TEST)
        gl.glDepthFunc(gl.GL_LESS)

        self.set_bg()

        view_width, view_height = [x / self.radius for x in self.size]

        self.center_view()
        for program in self.layer_manager.programs():
            program.setUniform('u_model', self.model)
            program.setUniform('u_view', self.view)
            program.setUniform('u_projection', self.projection)

        self.modelscale = .6 * 2 * min(2. * view_width / self.data_width,
                                       2. * view_height / self.data_height)
        self.scale = self.modelscale
        self.update_view_matrix()

        self.last_mouse_pos = 0, 0

        self.on_resize(*self.size)

    def render(self):
        if not self.isExposed():
            return
        self.context.makeCurrent(self)

        bits = 0
        bits |= gl.GL_COLOR_BUFFER_BIT
        bits |= gl.GL_DEPTH_BUFFER_BIT
        bits |= gl.GL_STENCIL_BUFFER_BIT
        gl.glClear(bits)
        gl.glEnable(gl.GL_PROGRAM_POINT_SIZE)

        for program in self.layer_manager.programs():
            if program.do_blending:
                if self.bg_white:
                    gl.glEnable(gl.GL_BLEND)
                    gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_SRC_ALPHA)
                else:
                    gl.glEnable(gl.GL_BLEND)
                    gl.glBlendFunc(gl.GL_ONE, gl.GL_SRC_ALPHA)
            else:
                gl.glDisable(gl.GL_BLEND)
        self.layer_manager.draw()

        if self.hud_program.is_visible:
            self.hud_program.draw()

        self.context.swapBuffers(self)

    def event(self, event):
        # print event.type()
        if event.type() == QEvent.UpdateRequest:
            self.render()
            return True

        return super(ViewerWindow, self).event(event)

    def exposeEvent(self, event):
        self.render()

    def resizeEvent(self, event):
        size = event.size()
        self.on_resize(size.width(), size.height())
        self.render()

    def update_view_matrix(self):
        self.view = np.eye(4, dtype=np.float32)
        translate(self.view, self.translation[0], self.translation[1],
                  self.translation[2])
        scale(self.view, self.scale, self.scale, self.scale)
        self.view = self.view.dot(
            np.array(q.matrix(self.rotation), dtype=np.float32))
        # translate(self.view, -self.translation[0], -self.translation[1], -self.translation[2] )
        translate(self.view, 0, 0, self.camera_position)
        for program in self.layer_manager.programs():
            program.setUniform('u_view', self.view)
            if program.draw_type == 'points':
                program.setUniform('u_model_scale', self.scale)

    def update_projection_matrix(self):
        view_width, view_height = [x / self.radius for x in self.size]

        if self.projection_mode == 'orthographic':
            self.projection = ortho(-view_width, view_width, -view_height,
                                    view_height, self.near_clip, self.far_clip)
        elif self.projection_mode == 'perspective':
            self.projection = perspective(self.fov,
                                          view_width / float(view_height),
                                          self.near_clip, self.far_clip)

        for program in self.layer_manager.programs():
            program.setUniform('u_projection', self.projection)

    def screen2view(self, x, y):
        width, height = self.size
        # print (x-width/2.)/self.radius, ((height-y)-height/2.)/self.radius
        return (x - width / 2.) / self.radius, (
            (height - y) - height / 2.) / self.radius

    def set_bg(self):
        gl.glEnable(gl.GL_BLEND)
        gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
        if self.bg_white:
            gl.glClearColor(0.95, 0.95, 0.95, 1)
            # gloo.set_state('translucent', clear_color=np.array([1,1,1,1]) )
        else:
            gl.glClearColor(0.05, 0.05, 0.05, 1)
            # gloo.set_state('translucent', clear_color=np.array([0.15,0.15,0.15,1]) )

    def keyPressEvent(self, event):
        key = event.key()
        repeat = event.isAutoRepeat()
        if key == Qt.Key_R:
            self.view = np.eye(4, dtype=np.float32)
            self.rotation = q.quaternion()
            self.scale = self.modelscale
            self.camera_position = -12.
            self.near_clip = 2.
            self.far_clip = 100.
            self.center_view()
            self.update_projection_matrix()
        elif key == Qt.Key_Minus:
            for layer in self.layer_manager:
                if layer.is_visible:
                    for program in layer:
                        if program.draw_type == 'points':
                            if (program.is_visible
                                    and self.multiview) or not self.multiview:
                                program.setUniform(
                                    'u_point_size',
                                    program.uniforms['u_point_size'] / 1.2)
        elif key == Qt.Key_Equal:
            for layer in self.layer_manager:
                if layer.is_visible:
                    for program in layer:
                        if program.draw_type == 'points':
                            if (program.is_visible
                                    and self.multiview) or not self.multiview:
                                program.setUniform(
                                    'u_point_size',
                                    program.uniforms['u_point_size'] * 1.2)
        elif key == Qt.Key_B:
            for program in self.layer_manager.programs():
                if program.is_visible and program.draw_type == 'points':
                    program.do_blending = not program.do_blending
        elif key == Qt.Key_C:
            self.near_clip = -self.camera_position - 0.1
            self.far_clip = -self.camera_position + 0.1
            self.update_projection_matrix()
        elif key == Qt.Key_T:
            self.rotation = q.quaternion()
            self.update_view_matrix()
        elif key == Qt.Key_P:
            if self.projection_mode == 'perspective':
                self.projection_mode = 'orthographic'
            else:
                self.projection_mode = 'perspective'
            self.update_projection_matrix()
        elif key == Qt.Key_L:
            self.bg_white = not self.bg_white
            self.set_bg()
        elif Qt.Key_0 <= key <= Qt.Key_9:
            i = int(chr(key)) - 1
            layers = [item for item in self.layer_manager.layers.items()]
            if i < len(layers):
                name, layer = layers[i]
                self.set_layer_visibility(name, layer.toggle())

        #         if self.multiview:
        #             self.set_layer_visibility(list(self.data_programs.keys())[i], not list(self.data_programs.values())[i].is_visible)
        #         else:
        #             for pi, prog in enumerate(self.data_programs.values()):
        #                 prog.is_visible = False
        #                 if pi == i:
        #                     prog.is_visible = True

        self.update()

    def on_resize(self, size_x, size_y):
        gl.glViewport(int(0), int(0), int(size_x), int(size_y))

        self.radius = 0.5 * min(size_x, size_y)
        self.size = size_x, size_y

        self.update_projection_matrix()

    def wheelEvent(self, event):
        # def on_mouse_wheel(self, window, offset_x, offset_y):
        ticks = float(event.angleDelta().y() + event.angleDelta().x()) / 50
        modifiers = event.modifiers()

        if modifiers == Qt.ControlModifier | Qt.AltModifier:
            # if modifiers == Qt.ShiftModifier:
            ticks /= 30
            self.near_clip -= ticks
            self.far_clip -= ticks
            self.update_projection_matrix()
        elif modifiers == Qt.AltModifier:
            # if modifiers == Qt.ShiftModifier:
            ticks /= 30
            new = max(0.1, self.near_clip - ticks)
            if new <= self.far_clip:
                self.near_clip = new
                self.update_projection_matrix()
        elif modifiers == Qt.ControlModifier:
            # if modifiers == Qt.ShiftModifier:
            ticks /= 30
            new = min(1000, self.far_clip - ticks)
            if new >= self.near_clip:
                self.far_clip = new
                self.update_projection_matrix()
        elif modifiers == Qt.ShiftModifier:
            if self.projection_mode == 'perspective':
                old_fov = self.fov
                # do `dolly zooming` so that world appears at same size after canging fov
                self.fov = max(5., self.fov + ticks)
                self.fov = min(120., self.fov)
                self.camera_position = self.camera_position * (math.tan(
                    math.radians(old_fov) / 2.)) / (math.tan(
                        math.radians(self.fov) / 2.))
                self.update_projection_matrix()
                self.update_view_matrix()
        elif modifiers == Qt.MetaModifier:
            self.camera_position += ticks / 10
            self.update_view_matrix()
        else:
            self.scale *= ticks / 10 + 1.
            # self.camera_position += ticks/10
            self.update_view_matrix()
        self.update()

    def mouseMoveEvent(self, event):
        modifiers = event.modifiers()
        buttons = event.buttons()
        pos_x, pos_y = event.x(), event.y()

        if Qt.ShiftModifier == modifiers:
            x0, y0 = self.last_mouse_pos
            x1, y1 = pos_x, pos_y
            dx, dy = (x1 - x0), (y1 - y0)
            #scale to zero plane in projection frustrum
            if self.projection_mode == 'perspective':
                scale = -self.camera_position * math.tan(
                    math.radians(self.fov / 2.))
                dx, dy = scale * dx, scale * dy
                #multiply with inverse view matrix and apply translation in world coordinates
                self.translation += np.array(
                    [dx / self.radius, -dy / self.radius, 0.,
                     0.]).dot(np.linalg.inv(self.view))[:3]
            elif self.projection_mode == 'orthographic':
                # this is not fully correct
                self.translation += self.modelscale * np.array(
                    [dx, -dy, 0., 0.]).dot(np.linalg.inv(self.view))[:3]

            self.hud_program.is_visible = True
        elif Qt.LeftButton == buttons:
            x0, y0 = self.screen2view(*self.last_mouse_pos)
            x1, y1 = self.screen2view(pos_x, pos_y)

            v0 = q.arcball(x0, y0)
            v1 = q.arcball(x1, y1)

            self.rotation = q.product(v1, v0, self.rotation)

            self.hud_program.is_visible = True
        else:
            self.hud_program.is_visible = False
        self.update_view_matrix()
        self.update()

        self.last_mouse_pos = pos_x, pos_y

    def update(self):
        self.render()
Esempio n. 12
0
class OFQtGraphicsContextCallback(PyOF.GraphicsContextCallback):
    """
    A callback that interfaces OpenFrames with PyQt's OpenGL rendering context

    Attributes
    ----------
    _context : QOpenGLContext
        Context used to render the window contents
    _surface : QSurface
        Surface (window) on which contents will be drawn
    """
    def __init__(self, surface):
        super().__init__()
        self._surface = surface
        self._context = None

    def swapBuffers(self):
        """
        Swaps the front/back rendering buffer

        """
        if self._context is not None:
            self._context.swapBuffers(self._surface)
        
    def makeCurrent(self):
        """
        Makes _context current for the surface of this window

        Returns
        -------
        bool
            True if successful
            False if an error occurs

        """        
        success = False
        if self._context is None:
            self._context = QOpenGLContext()
            self._context.create()
            success = self._context.makeCurrent(self._surface)
            if success:
                self._context.doneCurrent()
            else:
                return success
        if self._context is not None:
            success = self._context.makeCurrent(self._surface)
            # err = glGetError()
            
        return success
    
    def updateContext(self):
        """
        Updates _context when it becomes invalid, e.g. when resizing the window

        Returns
        -------
        bool
            True if successful
            False if an error occurs

        """   
        return self.makeCurrent()
Esempio n. 13
0
    def detectBestOpenGLVersion(cls):
        Logger.log("d", "Trying OpenGL context 4.1...")
        ctx = cls.setContext(4, 1, core=True)
        if ctx is not None:
            fmt = ctx.format()
            profile = fmt.profile()

            # First test: we hope for this
            if ((fmt.majorVersion() == 4 and fmt.minorVersion() >= 1) or
                (fmt.majorVersion() >
                 4)) and profile == QSurfaceFormat.CoreProfile:
                Logger.log(
                    "d", "Yay, we got at least OpenGL 4.1 core: %s",
                    cls.versionAsText(fmt.majorVersion(), fmt.minorVersion(),
                                      profile))

                # https://riverbankcomputing.com/pipermail/pyqt/2017-January/038640.html
                # PyQt currently only implements 2.0, 2.1 and 4.1Core
                # If eg 4.5Core would be detected and used here, PyQt would not be able to handle it.
                major_version = 4
                minor_version = 1

                # CURA-6092: Check if we're not using software backed 4.1 context; A software 4.1 context
                # is much slower than a hardware backed 2.0 context
                gl_window = QWindow()
                gl_window.setSurfaceType(QWindow.OpenGLSurface)
                gl_window.showMinimized()

                gl_format = QSurfaceFormat()
                gl_format.setMajorVersion(major_version)
                gl_format.setMinorVersion(minor_version)
                gl_format.setProfile(profile)

                gl_context = QOpenGLContext()
                gl_context.setFormat(gl_format)
                gl_context.create()
                gl_context.makeCurrent(gl_window)

                gl_profile = QOpenGLVersionProfile()
                gl_profile.setVersion(major_version, minor_version)
                gl_profile.setProfile(profile)

                gl = gl_context.versionFunctions(
                    gl_profile
                )  # type: Any #It's actually a protected class in PyQt that depends on the requested profile and the implementation of your graphics card.

                gpu_type = "Unknown"  # type: str

                result = None
                if gl:
                    result = gl.initializeOpenGLFunctions()

                if not result:
                    Logger.log("e",
                               "Could not initialize OpenGL to get gpu type")
                else:
                    # WORKAROUND: Cura/#1117 Cura-packaging/12
                    # Some Intel GPU chipsets return a string, which is not undecodable via PyQt5.
                    # This workaround makes the code fall back to a "Unknown" renderer in these cases.
                    try:
                        gpu_type = gl.glGetString(gl.GL_RENDERER)  #type: str
                    except UnicodeDecodeError:
                        Logger.log(
                            "e",
                            "DecodeError while getting GL_RENDERER via glGetString!"
                        )

                Logger.log("d",
                           "OpenGL renderer type for this OpenGL version: %s",
                           gpu_type)
                if "software" in gpu_type.lower():
                    Logger.log(
                        "w",
                        "Unfortunately OpenGL 4.1 uses software rendering")
                else:
                    return major_version, minor_version, QSurfaceFormat.CoreProfile
        else:
            Logger.log("d", "Failed to create OpenGL context 4.1.")

        # Fallback: check min spec
        Logger.log("d", "Trying OpenGL context 2.0...")
        ctx = cls.setContext(2, 0, profile=QSurfaceFormat.NoProfile)
        if ctx is not None:
            fmt = ctx.format()
            profile = fmt.profile()

            if fmt.majorVersion() >= 2 and fmt.minorVersion() >= 0:
                Logger.log(
                    "d", "We got at least OpenGL context 2.0: %s",
                    cls.versionAsText(fmt.majorVersion(), fmt.minorVersion(),
                                      profile))
                return 2, 0, QSurfaceFormat.NoProfile
            else:
                Logger.log(
                    "d", "Current OpenGL context is too low: %s" %
                    cls.versionAsText(fmt.majorVersion(), fmt.minorVersion(),
                                      profile))
                return None, None, None
        else:
            Logger.log("d", "Failed to create OpenGL context 2.0.")
            return None, None, None
Esempio n. 14
0
class OpenGLWindow(QWindow):
    def __init__(self, parent=None):
        super(OpenGLWindow, self).__init__(parent)

        self.m_update_pending = False
        self.m_animating = False
        self.m_context = None
        self.m_gl = None

        self.setSurfaceType(QWindow.OpenGLSurface)

    def initialize(self):
        pass

    def setAnimating(self, animating):
        self.m_animating = animating

        if animating:
            self.renderLater()

    def renderLater(self):
        if not self.m_update_pending:
            self.m_update_pending = True
            QGuiApplication.postEvent(self, QEvent(QEvent.UpdateRequest))

    def renderNow(self):
        if not self.isExposed():
            return

        self.m_update_pending = False

        needsInitialize = False

        if self.m_context is None:
            self.m_context = QOpenGLContext(self)
            self.m_context.setFormat(self.requestedFormat())
            self.m_context.create()

            needsInitialize = True

        self.m_context.makeCurrent(self)

        if needsInitialize:
            version_profile = QOpenGLVersionProfile()
            version_profile.setVersion(2, 0)
            self.m_gl = self.m_context.versionFunctions(version_profile)
            self.m_gl.initializeOpenGLFunctions()

            self.initialize()

        self.render(self.m_gl)

        self.m_context.swapBuffers(self)

        if self.m_animating:
            self.renderLater()

    def event(self, event):
        if event.type() == QEvent.UpdateRequest:
            self.renderNow()
            return True

        return super(OpenGLWindow, self).event(event)

    def exposeEvent(self, event):
        self.renderNow()

    def resizeEvent(self, event):
        self.renderNow()
Esempio n. 15
0
File: app.py Progetto: Ylannl/povipy
class ViewerWindow(QWindow):

    instructions = """
--Key controls
0-9     - toggle data layers
r       - reset view parameters
c       - clip view
t       - view from top
l       - light/dark background
=       - increase point size
-       - decrease point size

--Mouse controls
drag               
shift + move         - translate dataset
scroll               - scale dataset
shift + scroll       - change field of view
ctrl + scroll        - move far clipping plane
alt + scroll         - move near clipping plane
ctrl + alt + scroll  - move far and near clipping plane simultaniously
"""

    def __init__(self, parent=None, **kwargs):
        super(ViewerWindow, self).__init__(parent)
        self.setSurfaceType(QWindow.OpenGLSurface)

        format = QSurfaceFormat()
        format.setVersion(3, 3)
        format.setProfile(QSurfaceFormat.CoreProfile)
        format.setStereo(False)
        format.setSwapBehavior(QSurfaceFormat.DoubleBuffer)
        format.setDepthBufferSize(24)
        format.setSamples(16)
        
        self.context = QOpenGLContext(self)
        self.context.setFormat(format)
        if not self.context.create():
            raise Exception('self.context.create() failed')
        self.create()

        size = 720, 720
        self.resize(*size)

        self.context.makeCurrent(self)
        self.hud_program = CrossHairProgram()

        self.default_view = np.eye(4, dtype=np.float32)
        self.view = self.default_view
        self.model = np.eye(4, dtype=np.float32)
        self.projection = np.eye(4, dtype=np.float32)

        self.layer_manager = LayerManager()

        self.visibility_toggle_listeners = []
        self.multiview = True

        self.rotation = q.quaternion()
        self.scale = 0.6
        self.translation = np.zeros(3)

        self.radius = 0.5 * min(*size)
        self.fov = 5.
        self.camera_position = -12.
        self.near_clip = .1
        if 'near_clip' in kwargs:
            self.near_clip = kwargs['near_clip']
        self.far_clip = 100.
        if 'far_clip' in kwargs:
            self.far_clip = kwargs['far_clip']
        

        self.projection_mode = 'perspective' # 'orthographic'

        self.size = size
        self.bg_white = False
        self.viewpoint_dict = {}

        print((self.instructions))

    def add_layer(self, layer):
        self.layer_manager.add_layer(layer)
        return layer

    # keeping this compatibility with older scripts 
    def add_data_source(self, name, opts, points, normals=None, radii=None, intensity=None, category=None, zrange=None, **kwargs):
        if len(self.layer_manager.layers) == 0:
            self.layer_manager.add_layer(Layer(name='Default'))
        self.layer_manager.layers['Default'].add_data_source(name, opts, points, normals=normals, radii=radii, intensity=intensity, category=category, zrange=zrange, **kwargs)

    def add_data_source_line(self, name, coords_start, coords_end, **args):
        if len(self.layer_manager.layers) == 0:
            self.layer_manager.add_layer(Layer(name='Default'))
        self.layer_manager.layers['Default'].add_data_source_line(name, coords_start, coords_end, **args)

    def add_data_source_triangle(self, name, coords, normals, **args):
        if len(self.layer_manager.layers) == 0:
            self.layer_manager.add_layer(Layer(name='Default'))
        self.layer_manager.layers['Default'].add_data_source_triangle(name, coords, normals, **args)

    def run(self):
        self.initialize()
        self.show()

    def set_layer_visibility(self, name, is_visible):
        for listener in self.visibility_toggle_listeners:
            listener(name, is_visible)

    def center_view(self, center=None):
        if center is None:
            center = self.layer_manager.first.get_center()
            data_range = self.layer_manager.first.data_range
            self.data_width = data_range[0]
            self.data_height = data_range[2]
        self.translation = np.zeros(3)
        self.model = np.eye(4, dtype=np.float32)
        translate(self.model, -center[0], -center[1], -center[2])
        for program in self.layer_manager.programs():
            program.setUniform('u_model', self.model)
        self.update_view_matrix()

    def initialize(self):
        self.context.makeCurrent(self)

        gl.glDepthMask(gl.GL_TRUE)
        gl.glEnable(gl.GL_DEPTH_TEST)
        gl.glDepthFunc(gl.GL_LESS)

        self.set_bg()

        view_width, view_height = [x/self.radius for x in self.size]

        self.center_view()
        for program in self.layer_manager.programs():
            program.setUniform('u_model', self.model)
            program.setUniform('u_view', self.view)
            program.setUniform('u_projection', self.projection)

        self.modelscale = .6* 2*min(2.*view_width/self.data_width, 2.*view_height/self.data_height)
        self.scale = self.modelscale
        self.update_view_matrix()

        self.last_mouse_pos = 0,0

        self.on_resize(*self.size)

    def render(self):
        if not self.isExposed():
            return
        self.context.makeCurrent(self)

        bits = 0
        bits |= gl.GL_COLOR_BUFFER_BIT
        bits |= gl.GL_DEPTH_BUFFER_BIT
        bits |= gl.GL_STENCIL_BUFFER_BIT
        gl.glClear(bits)
        gl.glEnable(gl.GL_PROGRAM_POINT_SIZE)
        
        for program in self.layer_manager.programs():
            if program.do_blending:
                if self.bg_white:
                    gl.glEnable(gl.GL_BLEND)
                    gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_SRC_ALPHA)
                else:
                    gl.glEnable(gl.GL_BLEND)
                    gl.glBlendFunc(gl.GL_ONE, gl.GL_SRC_ALPHA)
            else:
                gl.glDisable(gl.GL_BLEND)
        self.layer_manager.draw()
        
        if self.hud_program.is_visible:
            self.hud_program.draw()

        self.context.swapBuffers(self)

    def event(self, event):
        # print event.type()
        if event.type() == QEvent.UpdateRequest:
            self.render()
            return True

        return super(ViewerWindow, self).event(event)

    def exposeEvent(self, event):
        self.render()

    def resizeEvent(self, event):
        size = event.size()
        self.on_resize(size.width(), size.height())
        self.render()

    def update_view_matrix(self):
        self.view = np.eye(4, dtype=np.float32)
        translate(self.view, self.translation[0], self.translation[1], self.translation[2] )
        scale(self.view, self.scale, self.scale, self.scale)
        self.view = self.view.dot( np.array(q.matrix(self.rotation), dtype=np.float32) )
        # translate(self.view, -self.translation[0], -self.translation[1], -self.translation[2] )
        translate(self.view, 0,0, self.camera_position)
        for program in self.layer_manager.programs():
            program.setUniform('u_view', self.view)
            if program.draw_type == 'points':
                program.setUniform('u_model_scale', self.scale)

    def update_projection_matrix(self):
        view_width, view_height = [x/self.radius for x in self.size]

        if self.projection_mode == 'orthographic':
            self.projection = ortho(-view_width, view_width, -view_height, view_height, self.near_clip, self.far_clip)
        elif self.projection_mode == 'perspective':
            self.projection = perspective(self.fov, view_width / float(view_height), self.near_clip, self.far_clip)

        for program in self.layer_manager.programs():
            program.setUniform('u_projection', self.projection)

    def screen2view(self, x,y):
        width, height = self.size
        # print (x-width/2.)/self.radius, ((height-y)-height/2.)/self.radius
        return (x-width/2.)/self.radius, ((height-y)-height/2.)/self.radius

    def set_bg(self):
        gl.glEnable(gl.GL_BLEND)
        gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA)
        if self.bg_white:
            gl.glClearColor(0.95,0.95,0.95,1)
            # gloo.set_state('translucent', clear_color=np.array([1,1,1,1]) )
        else:
            gl.glClearColor(0.05,0.05,0.05,1)
            # gloo.set_state('translucent', clear_color=np.array([0.15,0.15,0.15,1]) )

    def keyPressEvent(self, event):
        key = event.key()
        repeat = event.isAutoRepeat()
        if key == Qt.Key_R:
            self.view = np.eye(4, dtype=np.float32)
            self.rotation = q.quaternion()
            self.scale = self.modelscale
            self.camera_position = -12.
            self.near_clip = 2.
            self.far_clip = 100.
            self.center_view()
            self.update_projection_matrix()
        elif key == Qt.Key_Minus:
            for layer in self.layer_manager:
                if layer.is_visible:
                    for program in layer:
                        if program.draw_type == 'points':
                            if (program.is_visible and self.multiview) or not self.multiview:
                                program.setUniform('u_point_size', program.uniforms['u_point_size']/1.2)
        elif key == Qt.Key_Equal:
            for layer in self.layer_manager:
                if layer.is_visible:
                    for program in layer:
                        if program.draw_type == 'points':
                            if (program.is_visible and self.multiview) or not self.multiview:
                                program.setUniform('u_point_size', program.uniforms['u_point_size']*1.2)
        elif key == Qt.Key_B:
            for program in self.layer_manager.programs():
                if program.is_visible and program.draw_type == 'points':
                    program.do_blending = not program.do_blending
        elif key == Qt.Key_C:
            self.near_clip = -self.camera_position - 0.1
            self.far_clip = -self.camera_position + 0.1
            self.update_projection_matrix()
        elif key == Qt.Key_T:
            self.rotation = q.quaternion()
            self.update_view_matrix()
        elif key == Qt.Key_P:
            if self.projection_mode == 'perspective':
                self.projection_mode = 'orthographic'
            else:
                self.projection_mode = 'perspective'
            self.update_projection_matrix()
        elif key == Qt.Key_L:
            self.bg_white = not self.bg_white
            self.set_bg()
        elif Qt.Key_0 <= key <= Qt.Key_9:
            i = int(chr(key))-1
            layers = [item for item in self.layer_manager.layers.items()]
            if i < len(layers):
                name, layer = layers[i]
                self.set_layer_visibility(name,layer.toggle()) 

        #         if self.multiview:
        #             self.set_layer_visibility(list(self.data_programs.keys())[i], not list(self.data_programs.values())[i].is_visible)
        #         else:
        #             for pi, prog in enumerate(self.data_programs.values()):
        #                 prog.is_visible = False
        #                 if pi == i:
        #                     prog.is_visible = True

        self.update()

    def on_resize(self, size_x, size_y):
        gl.glViewport(int(0), int(0), int(size_x), int(size_y))

        self.radius = 0.5 * min(size_x, size_y)
        self.size = size_x, size_y

        self.update_projection_matrix()

    def wheelEvent(self, event):
    # def on_mouse_wheel(self, window, offset_x, offset_y):
        ticks = float(event.angleDelta().y()+event.angleDelta().x())/50
        modifiers = event.modifiers()

        if modifiers == Qt.ControlModifier | Qt.AltModifier:
            # if modifiers == Qt.ShiftModifier:
            ticks /= 30
            self.near_clip -= ticks
            self.far_clip -= ticks
            self.update_projection_matrix()
        elif modifiers == Qt.AltModifier:
            # if modifiers == Qt.ShiftModifier:
            ticks /= 30
            new = max(0.1,self.near_clip - ticks)
            if new <= self.far_clip:
                self.near_clip = new
                self.update_projection_matrix()
        elif modifiers == Qt.ControlModifier:
            # if modifiers == Qt.ShiftModifier:
            ticks /= 30
            new = min(1000,self.far_clip - ticks)
            if new >= self.near_clip:
                self.far_clip = new
                self.update_projection_matrix()
        elif modifiers == Qt.ShiftModifier:
            if self.projection_mode == 'perspective':
                old_fov = self.fov
                # do `dolly zooming` so that world appears at same size after canging fov
                self.fov = max(5.,self.fov + ticks)
                self.fov = min(120.,self.fov)
                self.camera_position = self.camera_position * (math.tan(math.radians(old_fov)/2.)) / (math.tan(math.radians(self.fov)/2.))
                self.update_projection_matrix()
                self.update_view_matrix()
        elif modifiers == Qt.MetaModifier:
            self.camera_position += ticks/10
            self.update_view_matrix()
        else:
            self.scale *= ticks/10 + 1.
            # self.camera_position += ticks/10
            self.update_view_matrix()
        self.update()

    def mouseMoveEvent(self, event):
        modifiers = event.modifiers()
        buttons = event.buttons()
        pos_x, pos_y = event.x(), event.y()

        if Qt.ShiftModifier == modifiers:
            x0,y0 = self.last_mouse_pos
            x1,y1 = pos_x, pos_y
            dx, dy = (x1-x0), (y1-y0)
            #scale to zero plane in projection frustrum
            if self.projection_mode == 'perspective':
                scale = -self.camera_position * math.tan(math.radians(self.fov/2.))
                dx, dy = scale*dx, scale*dy
                #multiply with inverse view matrix and apply translation in world coordinates
                self.translation += np.array([dx/self.radius, -dy/self.radius, 0., 0.]).dot( np.linalg.inv(self.view)) [:3]
            elif self.projection_mode == 'orthographic':
                # this is not fully correct
                self.translation += self.modelscale * np.array([dx, -dy, 0., 0.]).dot( np.linalg.inv(self.view)) [:3]
            
            self.hud_program.is_visible = True
        elif Qt.LeftButton == buttons:
            x0,y0 = self.screen2view(*self.last_mouse_pos)
            x1,y1 = self.screen2view(pos_x, pos_y)

            v0 = q.arcball(x0, y0)
            v1 = q.arcball(x1, y1)

            self.rotation = q.product(v1, v0, self.rotation)

            self.hud_program.is_visible = True
        else:
            self.hud_program.is_visible = False
        self.update_view_matrix()
        self.update()

        self.last_mouse_pos = pos_x, pos_y

    def update(self):
        self.render()
Esempio n. 16
0
class Window(QWindow):
    """
    A QWindow for rendering of WindowProxy

    Attributes
    ----------
    _context : QOpenGLContext
        Context used to render the window contents
    _window_proxy_id : int
        The WindowProxy responsible for drawing
    _saved_size : QSize
        If a resize event occurs before WindowProxy is started, then the size is saved here so that it can be set when
        WindowProxy is started
    _proxy_started_once : bool
        True after the first time that _of has been started

    """
    def __init__(self, nrow=1, ncol=1, id=0):
        """
        Create an instance of OFWindow

        Attributes
        ----------
        nrow : int, optional
            Number of rows in WindowProxy grid, default = 1
        ncol : int, optional
            Number of columns in WindowProxy grid, default = 1
        id : int, optional
            Identifier for the WindowProxy (each WindowProxy should have a unique identifier), default = 0

        """
        super().__init__()
        self._context = None
        self._proxy_started = False
        self._saved_size = None
        self.setSurfaceType(QWindow.OpenGLSurface)

        self._window_proxy_id = id

        ofwin_createproxy(0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT, nrow, ncol,
                          True, self._window_proxy_id, False)
        ofwin_setmakecurrentfunction(self.make_current)
        ofwin_setupdatecontextfunction(self.make_current)
        ofwin_setswapbuffersfunction(self.swap_buffers)

    def exposeEvent(self, event):
        """
        Overrides QWindow.exposeEvent()

        """
        if not self._proxy_started:
            self._proxy_started = True
            ofwin_activate(self._window_proxy_id)
            ofwin_start()
            if self._saved_size is not None:
                ofwin_resizewindow(0, 0, self._saved_size.width(),
                                   self._saved_size.height())
                self._saved_size = None

    def hideEvent(self, event):
        """
        Overrides QWindow.exposeEvent()

        """
        ofwin_activate(self._window_proxy_id)
        ofwin_signalstop()
        while ofwin_isrunning() == 1:
            QCoreApplication.processEvents(QEventLoop.AllEvents, 100)
        self._proxy_started = False

    def resizeEvent(self, event):
        """
        Overrides QWindow.resizeEvent()

        """
        ofwin_activate(self._window_proxy_id)
        if ofwin_isrunning() == 1:
            ofwin_resizewindow(0, 0,
                               event.size().width(),
                               event.size().height())
        else:
            self._saved_size = event.size()

    def mousePressEvent(self, event):
        """
        Overrides QWindow.mousePressEvent()

        """
        ofwin_activate(self._window_proxy_id)
        if ofwin_isrunning() == 1:
            button = Window._map_qt_button_to_of_button(event.button())
            if button != 0:
                ofwin_buttonpress(event.x(), event.y(), button)

    def mouseReleaseEvent(self, event):
        """
        Overrides QWindow.mouseReleaseEvent()

        """
        ofwin_activate(self._window_proxy_id)
        if ofwin_isrunning() == 1:
            button = Window._map_qt_button_to_of_button(event.button())
            if button != 0:
                ofwin_buttonrelease(event.x(), event.y(), button)

    def mouseMoveEvent(self, event):
        """
        Overrides QWindow.mouseMoveEvent()

        """
        ofwin_activate(self._window_proxy_id)
        if ofwin_isrunning() == 1:
            ofwin_mousemotion(event.x(), event.y())

    def keyPressEvent(self, event):
        """
        Overrides QWindow.keyPressEvent()

        """
        ofwin_activate(self._window_proxy_id)
        if ofwin_isrunning() == 1:
            key = Window._map_qt_key_event_to_osg_key(event)
            ofwin_keypress(key)

    # TODO call glGetError() to print any errors that may have occurred
    def make_current(self):
        """
        Makes _context current for the surface of this window

        Returns
        -------
        bool
            True if successful
            False if an error occurs

        """
        success = False
        if self._context is None:
            self._context = QOpenGLContext()
            self._context.create()
            success = self._context.makeCurrent(self)
            if success:
                # self.initializeOpenGLFunctions()
                self._context.doneCurrent()
            else:
                return success
        if self._context is not None:
            success = self._context.makeCurrent(self)
            # err = glGetError()
        return success

    def swap_buffers(self):
        """
        Swaps the buffer from _context to the surface of this window

        """
        if self._context is not None:
            self._context.swapBuffers(self)

    @staticmethod
    def _map_qt_button_to_of_button(qt_button):
        """
        Maps a Qt.MouseButton enumeration to an int for OpenFrames

        Parameters
        ----------
        qt_button : Qt.MouseButton
            The button to map

        Returns
        -------
        int
            The corresponding button for OpenFrames

        """
        if qt_button == Qt.LeftButton:
            return 1
        elif qt_button == Qt.RightButton:
            return 3
        elif qt_button == Qt.MiddleButton:
            return 2
        elif qt_button == Qt.BackButton:
            return 6
        elif qt_button == Qt.ForwardButton:
            return 7
        else:
            return 0

    @staticmethod
    def _map_qt_key_event_to_osg_key(event):
        """
        Maps a QKeyEvent to an int for OpenFrames

        Parameters
        ----------
        event : PyQt5.QtGui.QKeyEvent.QKeyEvent
            The key event to map

        Returns
        -------
        int
            The corresponding key code for OpenFrames

        """
        if Qt.Key_A <= event.key() <= Qt.Key_Z:
            if event.modifiers() & Qt.ShiftModifier:
                key = event.key()
            else:
                key = event.key() + 0x20
        else:
            key = event.key()
        return key
Esempio n. 17
0
class OpenGLWindow(QWindow):
    def __init__(self, parent=None):
        super(OpenGLWindow, self).__init__(parent)

        self.m_update_pending = False
        self.m_animating = False
        self.m_context = None
        self.m_device = None
        self.m_gl = None
        self.logger = None

        self.setSurfaceType(QWindow.OpenGLSurface)

    def initialize(self, gl):
        pass

    def setAnimating(self, animating):
        self.m_animating = animating

        if animating:
            self.renderLater()

    def renderLater(self):
        if not self.m_update_pending:
            self.m_update_pending = True
            QGuiApplication.postEvent(self, QEvent(QEvent.UpdateRequest))

    def paint(self, painter):
        pass

    def render(self, gl):
        pass

    def addGlFunctuins(self, GL, functions):
        for function, arguments in functions.items():
            GL[function].restype = None
            GL[function].argtypes = arguments
            setattr(self.m_gl, function, GL[function])

    @exitOnKeyboardInterrupt
    def renderNow(self):
        if not self.isExposed():
            return

        self.m_update_pending = False

        needsInitialize = False

        if self.m_context is None:
            self.m_context = QOpenGLContext(self)
            self.m_context.setFormat(self.requestedFormat())
            self.m_context.create()

            needsInitialize = True

        self.m_context.makeCurrent(self)

        if needsInitialize:
#           Sorry, no support for higher versions for now.
            profile = QOpenGLVersionProfile()
            profile.setVersion(2, 0)

            self.m_gl = self.m_context.versionFunctions(profile)
            self.m_gl.initializeOpenGLFunctions()

            #print(self.m_context.hasExtension('GL_EXT_framebuffer_object'))
            #print(self.m_context.hasExtension('GL_ARB_texture_float'))
            #print(*sorted(self.m_context.extensions()), sep='\n')

#           Small hack. Guess noone mind?            
            import ctypes
            import ctypes.util
            GL = ctypes.CDLL(ctypes.util.find_library('GL'))

            self.addGlFunctuins(GL, {
                'glFramebufferTexture2D': (ctypes.c_uint, ctypes.c_uint, ctypes.c_uint, ctypes.c_uint, ctypes.c_int)
                })

            self.logger = QOpenGLDebugLogger()
            self.logger.initialize()
            self.logger.loggedMessages()
            self.logger.messageLogged.connect(self.handleLoggedMassage)
            self.logger.startLogging()

            self.initialize(self.m_gl)
        
        if not self.m_device:
            self.m_device = QOpenGLPaintDevice()

        self.m_gl.glClear(self.m_gl.GL_COLOR_BUFFER_BIT | self.m_gl.GL_DEPTH_BUFFER_BIT);

        self.m_device.setSize(self.size())

        painter = QPainter(self.m_device)


        painter.beginNativePainting()
        self.render(self.m_gl)
        painter.endNativePainting()

        self.paint(painter)

        self.m_context.swapBuffers(self)

        if self.m_animating:
            self.renderLater()

    def handleLoggedMassage(self, message):
#       This three really annoyng and brings no useful info =\        
        if not (message.message().find('Use glDrawRangeElements() to avoid this.') > -1 or 
                message.message().find('CPU mapping a busy miptree') > -1 or
                message.message().find('Flushing before mapping a referenced bo.') > -1
                ):
            print(message.message().strip())

    def event(self, event):
        if event.type() == QEvent.UpdateRequest:
            self.renderNow()
            return True

        return super(OpenGLWindow, self).event(event)

    def exposeEvent(self, event):
        self.renderNow()

    def resizeEvent(self, event):
        self.renderNow()
Esempio n. 18
0
class OffscreenModelRendererThread(QThread):
    TEX_SIZE = 128
    renderedTexture = pyqtSignal(str, QImage)

    def __init__(self, parent_screen):
        super().__init__()
        self.parent_screen = parent_screen
        self.started.connect(self.started_)
        self.workspace = None
        self.offscreen_surface = QOffscreenSurface()
        self.offscreen_surface.requestedFormat().setVersion(4, 3)
        self.offscreen_surface.requestedFormat().setProfile(
            QSurfaceFormat.CoreProfile)
        self.offscreen_surface.requestedFormat().setDepthBufferSize(24)
        self.offscreen_surface.setFormat(
            self.offscreen_surface.requestedFormat())
        self.offscreen_surface.create()

    @pyqtSlot()
    def started_(self):
        self.ctx = QOpenGLContext(self.offscreen_surface)
        self.ctx.setFormat(self.offscreen_surface.requestedFormat())
        self.ctx.create()
        self.fbo = -1
        self.tex = -1
        self.rbuf = -1
        self.setup_fbo()

        self.renderer = ModelRenderer(self.workspace, self.offscreen_surface)

    @pyqtSlot(Workspace)
    def setWorkspace(self, w):
        if hasattr(self, "renderer"):
            self.renderer.set_workspace(w)
        else:
            self.workspace = w

    def setup_fbo(self):
        self.ctx.makeCurrent(self.offscreen_surface)
        self.tex = GL.glGenTextures(1)
        self.fbo = GL.glGenFramebuffers(1)
        self.rbuf = GL.glGenRenderbuffers(1)

        GL.glBindTexture(GL.GL_TEXTURE_2D, self.tex)
        GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER,
                           GL.GL_NEAREST)
        GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER,
                           GL.GL_NEAREST)
        GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA,
                        OffscreenModelRendererThread.TEX_SIZE,
                        OffscreenModelRendererThread.TEX_SIZE, 0, GL.GL_RGBA,
                        GL.GL_UNSIGNED_BYTE, None)

        GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, self.rbuf)
        GL.glRenderbufferStorage(GL.GL_RENDERBUFFER, GL.GL_DEPTH_COMPONENT24,
                                 OffscreenModelRendererThread.TEX_SIZE,
                                 OffscreenModelRendererThread.TEX_SIZE)

        GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, self.fbo)
        GL.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT,
                                     GL.GL_RENDERBUFFER, self.rbuf)
        GL.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0,
                                  GL.GL_TEXTURE_2D, self.tex, 0)
        if GL.glCheckFramebufferStatus(
                GL.GL_FRAMEBUFFER) != GL.GL_FRAMEBUFFER_COMPLETE:
            raise RuntimeError("Framebuffer is not complete!")
        GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0)
        GL.glBindRenderbuffer(GL.GL_RENDERBUFFER, 0)

    @pyqtSlot(str, BlockModel)
    def queue_render_order(self, order_name, model):
        """
        Render a block model in item format. Subscribing (connecting) to the renderedTexture signal allows you to get the rendered texture back.

        Pass in an order name so you know which image you got back

        :param order_name: the order name. passed to renderedTexture
        :param model: the blockmodel
        :return:
        """
        self.ctx.makeCurrent(self.offscreen_surface)
        GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, self.fbo)
        GL.glViewport(0, 0, OffscreenModelRendererThread.TEX_SIZE,
                      OffscreenModelRendererThread.TEX_SIZE)
        GL.glClearColor(0, 0, 0, 0)
        GL.glClear(GL.GL_DEPTH_BUFFER_BIT | GL.GL_COLOR_BUFFER_BIT)
        self.renderer.setup_data_for_block_model(model)
        self.renderer.resize(OffscreenModelRendererThread.TEX_SIZE,
                             OffscreenModelRendererThread.TEX_SIZE)
        self.renderer.draw_loaded_model(
            glm.lookAt(glm.vec3(15, 5, 5), glm.vec3(5, 5, 5),
                       glm.vec3(0, 1, 0)), "gui",
            glm.ortho(-10, 10, 10, -10, 0.1, 50))
        tex_str = GL.glReadPixels(0,
                                  0,
                                  OffscreenModelRendererThread.TEX_SIZE,
                                  OffscreenModelRendererThread.TEX_SIZE,
                                  GL.GL_RGBA,
                                  GL.GL_UNSIGNED_BYTE,
                                  outputType=bytes)
        GL.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0)
        qimage = QImage(tex_str, OffscreenModelRendererThread.TEX_SIZE,
                        OffscreenModelRendererThread.TEX_SIZE,
                        OffscreenModelRendererThread.TEX_SIZE * 4,
                        QImage.Format_RGBA8888)
        qimage = qimage.mirrored(vertical=True)
        self.renderedTexture.emit(order_name, qimage)
Esempio n. 19
0
# along with qutebrowser.  If not, see <https://www.gnu.org/licenses/>.
"""Show information about the OpenGL setup."""

from PyQt5.QtGui import (QOpenGLContext, QOpenGLVersionProfile,
                         QOffscreenSurface, QGuiApplication)

app = QGuiApplication([])

surface = QOffscreenSurface()
surface.create()

ctx = QOpenGLContext()
ok = ctx.create()
assert ok

ok = ctx.makeCurrent(surface)
assert ok

print(f"GLES: {ctx.isOpenGLES()}")

vp = QOpenGLVersionProfile()
vp.setVersion(2, 0)

vf = ctx.versionFunctions(vp)
print(f"Vendor: {vf.glGetString(vf.GL_VENDOR)}")
print(f"Renderer: {vf.glGetString(vf.GL_RENDERER)}")
print(f"Version: {vf.glGetString(vf.GL_VERSION)}")
print(
    f"Shading language version: {vf.glGetString(vf.GL_SHADING_LANGUAGE_VERSION)}"
)