Esempio n. 1
0
    def setContext(cls,
                   major_version: int,
                   minor_version: int,
                   core=False,
                   profile=None):
        """Set OpenGL context, given major, minor version + core using QOpenGLContext
        Unfortunately, what you get back does not have to be the requested version.
        """
        new_format = QSurfaceFormat()
        new_format.setMajorVersion(major_version)
        new_format.setMinorVersion(minor_version)
        if core:
            profile_ = QSurfaceFormat.CoreProfile
        else:
            profile_ = QSurfaceFormat.CompatibilityProfile
        if profile is not None:
            profile_ = profile
        new_format.setProfile(profile_)

        new_context = QOpenGLContext()
        new_context.setFormat(new_format)
        success = new_context.create()
        if success:
            return new_context
        else:
            Logger.log(
                "e", "Failed creating OpenGL context (%d, %d, core=%s)" %
                (major_version, minor_version, core))
            return None
Esempio n. 2
0
    def setContext(cls,
                   major_version: int,
                   minor_version: int,
                   core=False,
                   profile=None):
        new_format = QSurfaceFormat()
        new_format.setMajorVersion(major_version)
        new_format.setMinorVersion(minor_version)
        if core:
            profile_ = QSurfaceFormat.CoreProfile
        else:
            profile_ = QSurfaceFormat.CompatibilityProfile
        if profile is not None:
            profile_ = profile
        new_format.setProfile(profile_)

        new_context = QOpenGLContext()
        new_context.setFormat(new_format)
        success = new_context.create()
        if success:
            return new_context
        else:
            Logger.log(
                "e", "Failed creating OpenGL context (%d, %d, core=%s)" %
                (major_version, minor_version, core))
            return None
Esempio n. 3
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. 4
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. 5
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. 6
0
    def setContext(cls, major_version, minor_version, core = False, profile = None):
        new_format = QSurfaceFormat()
        new_format.setMajorVersion(major_version)
        new_format.setMinorVersion(minor_version)
        if core:
            profile_ = QSurfaceFormat.CoreProfile
        else:
            profile_ = QSurfaceFormat.CompatibilityProfile
        if profile is not None:
            profile_ = profile
        new_format.setProfile(profile_)

        new_context = QOpenGLContext()
        new_context.setFormat(new_format)
        success = new_context.create()
        if success:
            return new_context
        else:
            Logger.log("e", "Failed creating OpenGL context (%d, %d, core=%s)" % (major_version, minor_version, core))
            return None
Esempio n. 7
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. 8
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. 9
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. 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 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. 12
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. 13
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. 14
0
	format = QSurfaceFormat()
	format.setSwapBehavior(QSurfaceFormat.DoubleBuffer)
	format.setSamples(16)
	format.setStencilBufferSize(8)
	if core:
		format.setProfile(QSurfaceFormat.CoreProfile)
	
	window.setSurfaceType(QWindow.OpenGLSurface)
	window.setFormat(format)
	window.setTitle(name)
	
	pixel_ratio = window.devicePixelRatio()
	window.resize(*(u/pixel_ratio for u in window_size))
	
	gl_context = QOpenGLContext(window)
	gl_context.setFormat(window.requestedFormat())
	gl_context.create()
	
	
	# asynchronous redisplay
	
	def redisplay():
		gl_display(scene, feedback)
		gl_context.swapBuffers(window)
	
	waiting_redisplay = False
	def post_redisplay():
		global waiting_redisplay
		if not waiting_redisplay:
			waiting_redisplay = True
			app.postEvent(app, QEvent(QEvent.UpdateRequest))