Example #1
0
def current_program():
    """
        Return the currently bound shader program or None if there is None.
        The returned shader do not own the underlying buffer.
    """
    cprog = GLint(0)
    glGetIntegerv(GL_CURRENT_PROGRAM, byref(cprog))
    if cprog.value == 0:
        return None
    else:
        return ShaderProgram(cprog)
Example #2
0
def get_info():
    from OpenGL.GL import (glGetString, glGetIntegerv, GL_VENDOR, GL_VERSION,
                           GL_SHADING_LANGUAGE_VERSION, GL_RENDERER,
                           GL_MAJOR_VERSION, GL_MINOR_VERSION)
    return {
        'major': glGetIntegerv(GL_MAJOR_VERSION),
        'minor': glGetIntegerv(GL_MINOR_VERSION),
        'vendor': glGetString(GL_VENDOR),
        'version': glGetString(GL_VERSION),
        'shader_language_version': glGetString(GL_SHADING_LANGUAGE_VERSION),
        'renderer': glGetString(GL_RENDERER),
    }
Example #3
0
def screen_shot(name="screen_shot.%03i.png"):
	"""window screenshot."""
	from OpenGL.GL import glGetIntegerv, glReadBuffer, glReadPixels
	from OpenGL.GL import GL_VIEWPORT, GL_READ_BUFFER, GL_FRONT, GL_RGB, GL_UNSIGNED_BYTE
	x, y, width, height = glGetIntegerv(GL_VIEWPORT)
	read_buffer = glGetIntegerv(GL_READ_BUFFER)
	glReadBuffer(GL_FRONT)
	data = glReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE)
	glReadBuffer(read_buffer)
	
	from demos.common import png
	global _shot
	png.write(open(name % _shot, "wb"), width, height, 3, data)
	_shot += 1
    def _Screen2Real(self, x, y, expZ=0.0):
        '''
        Return the x and y in real coordination if the input is the x and y in screen coordination
        http://nehe.gamedev.net/article/using_gluunproject/16013/
        Inputs:
            - x, y: coordinates get from mouse in screen coordination
            - expZ: expected Z of the real coordinates
        Outputs: coordinates in the real world
        '''
        if not self.init:
            return 0, 0, 0
        
        projection = glGetDoublev(GL_PROJECTION_MATRIX)
        modelview = glGetDoublev(GL_MODELVIEW_MATRIX)
        viewport = glGetIntegerv(GL_VIEWPORT)
        
        winX = float(x)
        winY = float(viewport[3]) - float(y)
#         winZ = glReadPixels(x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT)
        
        try:
            posXF, posYF, posZF = gluUnProject(winX, winY, 1, modelview, projection, viewport)
            posXN, posYN, posZN = gluUnProject(winX, winY, -1, modelview, projection, viewport)
            posZ = expZ
            posX = (posZ - posZN) / (posZF - posZN) * (posXF - posXN) + posXN
            posY = (posZ - posZN) / (posZF - posZN) * (posYF - posYN) + posYN
#             posX, posY, posZ = gluUnProject(winX, winY, winZ, modelview, projection, viewport)
        except:
            return 0, 0, 0
        return posX, posY, posZ
Example #5
0
 def compile_total_list(self):
     if self.total_list is not None:
         glNewList(self.total_list, GL_COMPILE)
         # reset a few things
         glDisable(GL_DEPTH_TEST)
         glDisable(GL_LIGHTING)
         glMatrixMode(GL_PROJECTION)
         glLoadIdentity()
         glMatrixMode(GL_MODELVIEW)
         glLoadIdentity()
         # change the modelview to camera coordinates
         viewport = glGetIntegerv(GL_VIEWPORT)
         width = viewport[2] - viewport[0]
         height = viewport[3] - viewport[1]
         if width > height:
             w = float(width) / float(height)
             h = 1.0
         else:
             w = 1.0
             h = float(height) / float(width)
         glScalef(2 / w, 2 / h, 1.0)
         glCallList(self.draw_list)
         glEnable(GL_DEPTH_TEST)
         glEnable(GL_LIGHTING)
         glEndList()
Example #6
0
        def pickup(event, right):
            """
                Function to get the Name Stack
                right es si el boton pulsado es el derecho
                
                El viewport[3]-event.y() creo que es porque la medida de las Y está invertida
                Los problemas que tenía con windows de tener que hacer varios click se corrigieron sustituyendo la región de selección de 1,1 a 5,5

            """

            viewport = glGetIntegerv(GL_VIEWPORT)
            glMatrixMode(GL_PROJECTION)
            glPushMatrix()
            glSelectBuffer(512)
            glRenderMode(GL_SELECT)
            glLoadIdentity()
            gluPickMatrix(event.x(), viewport[3] - event.y(), 4, 4, viewport)
            aspect = viewport[2] / viewport[3]
            gluPerspective(60, aspect, 1.0, 400)
            glMatrixMode(GL_MODELVIEW)
            self.paintGL()
            glMatrixMode(GL_PROJECTION)
            if right == False:
                parseLeftButtonNameStack(glRenderMode(GL_RENDER))
            else:
                parseRightButtonNameStack(glRenderMode(GL_RENDER))
            glPopMatrix()
            glMatrixMode(GL_MODELVIEW)
    def _gl_select_(self, x, y):
        '''

        '''
        _gw, gh = self.GetSize()

        self.draw(offscreen=True)
        b = glReadPixels(x, gh - y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE)

        _buff = glSelectBuffer(128)
        view = glGetIntegerv(GL_VIEWPORT)
        glRenderMode(GL_SELECT)
        glInitNames()
        glPushName(0)

        glMatrixMode(GL_PROJECTION)
        glPushMatrix()
        glLoadIdentity()
        gluPickMatrix(x, gh - y, 1.0, 1.0, view)
        self._set_view_volume()

        glMatrixMode(GL_MODELVIEW)
        self.draw(offscreen=True)

        glMatrixMode(GL_PROJECTION)
        glPopMatrix()

        hits = glRenderMode(GL_RENDER)
        glMatrixMode(GL_MODELVIEW)

        self.scene_graph.set_view_cube_face(struct.unpack('BBB', b))  # get the top object

        return min([(h.near, h.names[0]) for h in hits])[1] if hits else None
Example #8
0
 def compile_total_list(self):
     if self.total_list is not None:
         glNewList(self.total_list, GL_COMPILE)
         # reset a few things
         glDisable(GL_DEPTH_TEST)
         glDisable(GL_LIGHTING)
         glMatrixMode(GL_PROJECTION)
         glLoadIdentity()
         glMatrixMode(GL_MODELVIEW)
         glLoadIdentity()
         # change the modelview to camera coordinates
         viewport = glGetIntegerv(GL_VIEWPORT)
         width = viewport[2] - viewport[0]
         height = viewport[3] - viewport[1]
         if width > height:
             w = float(width) / float(height)
             h = 1.0
         else:
             w = 1.0
             h = float(height) / float(width)
         glScalef(2/w, 2/h, 1.0)
         glCallList(self.draw_list)
         glEnable(GL_DEPTH_TEST)
         glEnable(GL_LIGHTING)
         glEndList()
Example #9
0
    def draw(self):
        # this code is modified from GLPane.drawcompass

        glMatrixMode(GL_MODELVIEW)
        glPushMatrix()
        glLoadIdentity()

        glMatrixMode(
            GL_PROJECTION
        )  # WARNING: we're now in nonstandard matrixmode (for sake of gluPickMatrix and glOrtho -- needed??##k)
        glPushMatrix()
        glLoadIdentity()

        try:
            glpane = self.env.glpane
            ##            aspect = 1.0 ###WRONG -- should use glpane.aspect (which exists as of 070919)
            aspect = glpane.aspect  # revised by bruce 070919, UNTESTED
            corner = self.corner
            delegate = self.delegate

            ###e should get glpane to do this for us (ie call a method in it to do this if necessary)
            # (this code is copied from it)
            glselect = glpane.current_glselect
            if glselect:
                # print "%r (ipath %r) setting up gluPickMatrix" % (self, self.ipath)
                x, y, w, h = glselect
                gluPickMatrix(
                    x, y, w, h, glGetIntegerv(GL_VIEWPORT)  # k is this arg needed? it might be the default...
                )

            # the first three cases here are still ###WRONG
            if corner == UPPER_RIGHT:
                glOrtho(-50 * aspect, 5.5 * aspect, -50, 5.5, -5, 500)  # Upper Right
            elif corner == UPPER_LEFT:
                glOrtho(-5 * aspect, 50.5 * aspect, -50, 5.5, -5, 500)  # Upper Left
            elif corner == LOWER_LEFT:
                glOrtho(-5 * aspect, 50.5 * aspect, -5, 50.5, -5, 500)  # Lower Left
            else:
                ## glOrtho(-50*aspect, 5.5*aspect, -5, 50.5,  -5, 500) # Lower Right
                ## glOrtho(-50*aspect, 0, 0, 50,  -5, 500) # Lower Right [used now] -- x from -50*aspect to 0, y (bot to top) from 0 to 50
                glOrtho(-glpane.width * PIXELS, 0, 0, glpane.height * PIXELS, -5, 500)
                # approximately right for the checkbox, but I ought to count pixels to be sure (note, PIXELS is a pretty inexact number)

            glMatrixMode(GL_MODELVIEW)  ###k guess 061210 at possible bugfix (and obviously needed in general) --
            # do this last to leave the matrixmode standard
            # (status of bugs & fixes unclear -- hard to test since even Highlightable(projection=True) w/o any change to
            # projection matrix (test _9cx) doesn't work!)
            offset = (-delegate.bright, delegate.bbottom)  # only correct for LOWER_RIGHT
            glTranslatef(offset[0], offset[1], 0)
            self.drawkid(delegate)  ## delegate.draw()

        finally:
            glMatrixMode(GL_PROJECTION)
            glPopMatrix()
            glMatrixMode(GL_MODELVIEW)  # be sure to do this last, to leave the matrixmode standard
            glPopMatrix()

        return
Example #10
0
    def draw(self):
        # this code is modified from GLPane.drawcompass

        glMatrixMode(GL_MODELVIEW)
        glPushMatrix()
        glLoadIdentity()
        
        glMatrixMode(GL_PROJECTION) # WARNING: we're now in nonstandard matrixmode (for sake of gluPickMatrix and glOrtho -- needed??##k)
        glPushMatrix()
        glLoadIdentity()

        try:
            glpane = self.env.glpane
##            aspect = 1.0 ###WRONG -- should use glpane.aspect (which exists as of 070919)
            aspect = glpane.aspect # revised by bruce 070919, UNTESTED
            corner = self.corner
            delegate = self.delegate

            ###e should get glpane to do this for us (ie call a method in it to do this if necessary)
            # (this code is copied from it)
            glselect = glpane.current_glselect
            if glselect:
                # print "%r (ipath %r) setting up gluPickMatrix" % (self, self.ipath)
                x,y,w,h = glselect
                gluPickMatrix(
                        x,y,
                        w,h,
                        glGetIntegerv( GL_VIEWPORT ) #k is this arg needed? it might be the default...
                )

            # the first three cases here are still ###WRONG
            if corner == UPPER_RIGHT:
                glOrtho(-50*aspect, 5.5*aspect, -50, 5.5,  -5, 500) # Upper Right
            elif corner == UPPER_LEFT:
                glOrtho(-5*aspect, 50.5*aspect, -50, 5.5,  -5, 500) # Upper Left
            elif corner == LOWER_LEFT:
                glOrtho(-5*aspect, 50.5*aspect, -5, 50.5,  -5, 500) # Lower Left
            else:
                ## glOrtho(-50*aspect, 5.5*aspect, -5, 50.5,  -5, 500) # Lower Right
                ## glOrtho(-50*aspect, 0, 0, 50,  -5, 500) # Lower Right [used now] -- x from -50*aspect to 0, y (bot to top) from 0 to 50
                glOrtho(-glpane.width * PIXELS, 0, 0, glpane.height * PIXELS,  -5, 500)
                    # approximately right for the checkbox, but I ought to count pixels to be sure (note, PIXELS is a pretty inexact number)

            glMatrixMode(GL_MODELVIEW) ###k guess 061210 at possible bugfix (and obviously needed in general) --
                # do this last to leave the matrixmode standard
                # (status of bugs & fixes unclear -- hard to test since even Highlightable(projection=True) w/o any change to
                # projection matrix (test _9cx) doesn't work!)
            offset = (-delegate.bright, delegate.bbottom) # only correct for LOWER_RIGHT
            glTranslatef(offset[0], offset[1], 0)
            self.drawkid( delegate) ## delegate.draw()
            
        finally:
            glMatrixMode(GL_PROJECTION)
            glPopMatrix()
            glMatrixMode(GL_MODELVIEW) # be sure to do this last, to leave the matrixmode standard
            glPopMatrix()

        return
Example #11
0
def glRenderMode( newMode ):
    """Change to the given rendering mode

    If the current mode is GL_FEEDBACK or GL_SELECT, return
    the current buffer appropriate to the mode
    """
    # must get the current mode to determine operation...
    from OpenGL.GL import glGetIntegerv
    from OpenGL.GL import selection, feedback
    currentMode = glGetIntegerv( simple.GL_RENDER_MODE )
    try:
        currentMode = currentMode[0]
    except (TypeError,ValueError,IndexError) as err:
        pass
    if currentMode in (simple.GL_RENDER,0):
        # no array needs to be returned...
        return simple.glRenderMode( newMode )
    result = simple.glRenderMode( newMode )
    # result is now an integer telling us how many elements were copied...

    if result < 0:
        if currentMode == simple.GL_SELECT:
            raise error.GLError(
                simple.GL_STACK_OVERFLOW,
                "glSelectBuffer too small to hold selection results",
            )
        elif currentMode == simple.GL_FEEDBACK:
            raise error.GLError(
                simple.GL_STACK_OVERFLOW,
                "glFeedbackBuffer too small to hold selection results",
            )
        else:
            raise error.GLError(
                simple.GL_STACK_OVERFLOW,
                "Unknown glRenderMode buffer (%s) too small to hold selection results"%(
                    currentMode,
                ),
            )
    # Okay, now that the easy cases are out of the way...
    #  Do we have a pre-stored pointer about which the user already knows?
    context = platform.GetCurrentContext()
    if context == 0:
        raise error.Error(
            """Returning from glRenderMode without a valid context!"""
        )
    arrayConstant, wrapperFunction = {
        simple.GL_FEEDBACK: (simple.GL_FEEDBACK_BUFFER_POINTER,feedback.parseFeedback),
        simple.GL_SELECT: (simple.GL_SELECTION_BUFFER_POINTER, selection.GLSelectRecord.fromArray),
    }[ currentMode ]
    current = contextdata.getValue( arrayConstant )
    # XXX check to see if it's the *same* array we set currently!
    if current is None:
        current = glGetPointerv( arrayConstant )
    # XXX now, can turn the array into the appropriate wrapper type...
    if wrapperFunction:
        current = wrapperFunction( current, result )
    return current
Example #12
0
def glRenderMode(newMode):
    """Change to the given rendering mode

    If the current mode is GL_FEEDBACK or GL_SELECT, return
    the current buffer appropriate to the mode
    """
    # must get the current mode to determine operation...
    from OpenGL.GL import glGetIntegerv
    from OpenGL.GL import selection, feedback
    currentMode = glGetIntegerv(simple.GL_RENDER_MODE)
    try:
        currentMode = currentMode[0]
    except (TypeError, ValueError, IndexError) as err:
        pass
    if currentMode in (simple.GL_RENDER, 0):
        # no array needs to be returned...
        return simple.glRenderMode(newMode)
    result = simple.glRenderMode(newMode)
    # result is now an integer telling us how many elements were copied...

    if result < 0:
        if currentMode == simple.GL_SELECT:
            raise error.GLError(
                simple.GL_STACK_OVERFLOW,
                "glSelectBuffer too small to hold selection results",
            )
        elif currentMode == simple.GL_FEEDBACK:
            raise error.GLError(
                simple.GL_STACK_OVERFLOW,
                "glFeedbackBuffer too small to hold selection results",
            )
        else:
            raise error.GLError(
                simple.GL_STACK_OVERFLOW,
                "Unknown glRenderMode buffer (%s) too small to hold selection results"
                % (currentMode, ),
            )
    # Okay, now that the easy cases are out of the way...
    #  Do we have a pre-stored pointer about which the user already knows?
    context = platform.GetCurrentContext()
    if context == 0:
        raise error.Error(
            """Returning from glRenderMode without a valid context!""")
    arrayConstant, wrapperFunction = {
        simple.GL_FEEDBACK:
        (simple.GL_FEEDBACK_BUFFER_POINTER, feedback.parseFeedback),
        simple.GL_SELECT: (simple.GL_SELECTION_BUFFER_POINTER,
                           selection.GLSelectRecord.fromArray),
    }[currentMode]
    current = contextdata.getValue(arrayConstant)
    # XXX check to see if it's the *same* array we set currently!
    if current is None:
        current = glGetPointerv(arrayConstant)
    # XXX now, can turn the array into the appropriate wrapper type...
    if wrapperFunction:
        current = wrapperFunction(current, result)
    return current
Example #13
0
 def draw(self, camera_matrix: numpy.ndarray):
     """Draw all of the levels."""
     for level, transform, is_mirrored in zip(
         self._objects, self._transformation_matrices, self._is_mirrored
     ):
         cull_state = glGetIntegerv(GL_CULL_FACE_MODE)
         if is_mirrored:
             glCullFace(GL_FRONT)
         else:
             glCullFace(GL_BACK)
         level.draw(numpy.matmul(camera_matrix, transform))
         glCullFace(cull_state)
Example #14
0
def glRenderMode( newMode ):
    """Change to the given rendering mode

    If the current mode is GL_FEEDBACK or GL_SELECT, return
    the current buffer appropriate to the mode
    """
    # must get the current mode to determine operation...
    from OpenGL.GL import glGetIntegerv
    from OpenGL.GL import selection, feedback
    currentMode = glGetIntegerv( simple.GL_RENDER_MODE )
    try:
        currentMode = currentMode[0]
    except (TypeError,ValueError,IndexError), err:
        pass
Example #15
0
def hasGLExtension( specifier ):
    """Given a string specifier, check for extension being available"""
    global AVAILABLE_GL_EXTENSIONS
    specifier = as_8_bit(specifier).replace(as_8_bit('.'),as_8_bit('_'))
    if specifier.startswith( VERSION_PREFIX ):
        specifier = [
            int(x)
            for x in specifier[ len(VERSION_PREFIX):].split(as_8_bit('_'))
        ]
        version = getGLVersion()
        if not version:
            return version
        return specifier <= version
    else:
        from OpenGL.GL import glGetString, GL_EXTENSIONS
        from OpenGL import error
        if not AVAILABLE_GL_EXTENSIONS:
            try:
                AVAILABLE_GL_EXTENSIONS[:] = glGetString( GL_EXTENSIONS ).split()
            except (AttributeError, error.GLError) as err:
                # OpenGL 3.0 deprecates glGetString( GL_EXTENSIONS )
                from OpenGL.GL.VERSION.GL_3_0 import GL_NUM_EXTENSIONS, glGetStringi
                from OpenGL.GL import glGetIntegerv
                count = glGetIntegerv( GL_NUM_EXTENSIONS )
                for i in range( count ):
                    extension = glGetStringi( GL_EXTENSIONS, i )
                    AVAILABLE_GL_EXTENSIONS.append(
                        extension
                    )
            # Add included-by-reference extensions...
            version = getGLVersion()
            if not version:
                # should not be possible?
                return version 
            check = tuple( version[:2] )
            for (v,v_exts) in VERSION_EXTENSIONS:
                if v <= check:
                    for v_ext in v_exts:
                        if v_ext not in AVAILABLE_GL_EXTENSIONS:
                            AVAILABLE_GL_EXTENSIONS.append( v_ext )
                else:
                    break
        result = specifier in AVAILABLE_GL_EXTENSIONS
        log.info(
            'GL Extension %s %s',
            specifier,
            ['unavailable','available'][bool(result)]
        )
        return result
Example #16
0
 def render_scene(self, object_list, view_matrix, projection_matrix,  orthographic_matrix, graphics_context):
     projection_matrix = np.array(projection_matrix, np.double)
     viewport = glGetIntegerv(GL_VIEWPORT)
     orthographic_matrix = np.array(orthographic_matrix, np.double)
     view_matrix = np.array(view_matrix, np.double)
     
     for o in object_list:
         if "animation_controller" in o._components:
             c = o._components["animation_controller"]
             if hasattr(c, "get_labeled_points"):
                 labels, points = c.get_labeled_points()
                 for i, l in enumerate(labels):
                     pos = points[i]
                     wx, wy, _ = gluProject(pos[0], pos[1], pos[2], view_matrix, projection_matrix, viewport)
                     wy = graphics_context.height - wy
                     self.draw(orthographic_matrix, (wx, wy), l[:self.max_label_length])
    def _getPickingRay(self, x, y):
        '''
        Process the ray for the current
        mouse position
        '''
        viewport = glGetIntegerv(GL_VIEWPORT)
        model_mat = np.array(glGetDoublev(GL_MODELVIEW_MATRIX))
        proj_mat = np.array(glGetDoublev(GL_PROJECTION_MATRIX))

        # win_coord   = (x*2, viewport[3] - y*2)
        win_coord = (x, viewport[3] - y)
        near_point = np.array(
            GLU.gluUnProject(win_coord[0], win_coord[1], 0.0, model_mat,
                             proj_mat, viewport))
        far_point = np.array(
            GLU.gluUnProject(win_coord[0], win_coord[1], 1.0, model_mat,
                             proj_mat, viewport))

        return far_point - near_point
Example #18
0
    def _setup_projection(
        self,
        glselect=False
    ):  #bruce 050608 split this out; 050615 revised docstring
        """
        Set up standard projection matrix contents using aspect, vdist, and 
        some attributes of self.
        
        @warning: leaves matrixmode as GL_PROJECTION.
                  Optional arg glselect should be False (default) or a 4-tuple
                  (to prepare for GL_SELECT picking).
        """
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()

        scale = self.scale  #bruce 050608 used this to clarify following code
        near, far = self.near, self.far

        #bruce 080219 moved these from one of two callers into here,
        # to fix bug when insert from partlib is first operation in NE1
        self.aspect = (self.width + 0.0) / (self.height + 0.0)
        self.vdist = 6.0 * scale

        if glselect:
            x, y, w, h = glselect
            gluPickMatrix(
                x,
                y,
                w,
                h,
                glGetIntegerv(
                    GL_VIEWPORT
                )  #k is this arg needed? it might be the default...
            )

        if self.ortho:
            glOrtho(-scale * self.aspect, scale * self.aspect, -scale, scale,
                    self.vdist * near, self.vdist * far)
        else:
            glFrustum(-scale * near * self.aspect, scale * near * self.aspect,
                      -scale * near, scale * near, self.vdist * near,
                      self.vdist * far)
        return
    def draw(self,
             camera_matrix: numpy.ndarray,
             camera_position: PointCoordinatesAny = None):
        """
        Draw the selection box
        :param camera_matrix: 4x4 transformation matrix for the camera
        :param camera_position: The position of the camera. Used to flip draw direction if camera inside box.
        :return:
        """
        self._setup()
        if self._needs_rebuild:
            self._create_geometry()

        transformation_matrix = numpy.matmul(camera_matrix,
                                             self.transformation_matrix)

        depth_state = glGetBooleanv(GL_DEPTH_TEST)
        cull_state = glGetIntegerv(GL_CULL_FACE_MODE)

        # draw the lines around the boxes
        self.draw_start = 0
        self.draw_count = 36

        if depth_state:
            glDisable(GL_DEPTH_TEST)
        self._draw_mode = GL_LINE_STRIP
        super()._draw(transformation_matrix)
        if depth_state:
            glEnable(GL_DEPTH_TEST)

        if camera_position is not None:
            if camera_position in self:
                glCullFace(GL_FRONT)
            else:
                glCullFace(GL_BACK)
        self._draw_mode = GL_TRIANGLES
        self.draw_start = 36
        # 6 faces, 9 quads/face, 2 triangles/quad, 3 verts/triangle
        self.draw_count = 324
        super()._draw(transformation_matrix)

        glCullFace(cull_state)
Example #20
0
    def draw(self,
             camera_matrix: numpy.ndarray,
             camera_position: PointCoordinatesAny = None):
        """
        Draw the selection box
        :param camera_matrix: 4x4 transformation matrix for the camera
        :param camera_position: The position of the camera. Used to flip draw direction if camera inside box.
        :return:
        """
        self._setup()
        if self._needs_rebuild:
            self._create_geometry()
        self._draw_mode = GL_TRIANGLES

        transformation_matrix = numpy.matmul(camera_matrix,
                                             self.transformation_matrix)

        glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_POLYGON_BIT
                     | GL_ENABLE_BIT)  # store opengl state

        if camera_position is not None and camera_position in self:
            mode = glGetIntegerv(GL_CULL_FACE_MODE)
            if mode == GL_BACK:
                glCullFace(GL_FRONT)
            elif mode == GL_FRONT:
                glCullFace(GL_BACK)

        self.draw_start = 0
        self.draw_count = 36
        super()._draw(transformation_matrix)

        # draw the lines around the boxes
        glDisable(GL_DEPTH_TEST)
        self._draw_mode = GL_LINE_STRIP
        super()._draw(transformation_matrix)

        glPopAttrib()  # reset to starting state
Example #21
0
    def _setup_projection(self, glselect=False):  # bruce 050608 split this out; 050615 revised docstring
        """
        Set up standard projection matrix contents using aspect, vdist, and 
        some attributes of self.
        
        @warning: leaves matrixmode as GL_PROJECTION.
                  Optional arg glselect should be False (default) or a 4-tuple
                  (to prepare for GL_SELECT picking).
        """
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()

        scale = self.scale  # bruce 050608 used this to clarify following code
        near, far = self.near, self.far

        # bruce 080219 moved these from one of two callers into here,
        # to fix bug when insert from partlib is first operation in NE1
        self.aspect = (self.width + 0.0) / (self.height + 0.0)
        self.vdist = 6.0 * scale

        if glselect:
            x, y, w, h = glselect
            gluPickMatrix(x, y, w, h, glGetIntegerv(GL_VIEWPORT))  # k is this arg needed? it might be the default...

        if self.ortho:
            glOrtho(-scale * self.aspect, scale * self.aspect, -scale, scale, self.vdist * near, self.vdist * far)
        else:
            glFrustum(
                -scale * near * self.aspect,
                scale * near * self.aspect,
                -scale * near,
                scale * near,
                self.vdist * near,
                self.vdist * far,
            )
        return
Example #22
0
    def _setup_projection(self, glselect = False):
        ### WARNING: This is not actually private! TODO: rename it.
        """
        Set up standard projection matrix contents using various attributes of
        self (aspect, vdist, scale, zoomFactor).  Also reads the current OpenGL
        viewport bounds in window coordinates.
        
        (Warning: leaves matrixmode as GL_PROJECTION.)
        
        @param glselect: False (default) normally, or a 4-tuple
               (format not documented here) to prepare for GL_SELECT picking by
               calling gluPickMatrix().

        If you are really going to draw in the pick window (for GL_RENDER and
        glReadPixels picking, rather than GL_SELECT picking), don't forget to
        set the glViewport *after* calling _setup_projection.  Here's why:

           gluPickMatrix needs to know the current *whole-window* viewport, in
           order to set up a projection matrix to map a small portion of it to
           the clipping boundaries for GL_SELECT.

           From the gluPickMatrix doc page:
             viewport:
               Specifies the current viewport (as from a glGetIntegerv call).
             Description:
               gluPickMatrix creates a projection matrix that can be used to
               restrict drawing to a small region of the viewport.

           In the graphics pipeline, the clipper actually works in homogeneous
           coordinates, clipping polygons to the {X,Y}==+-W boundaries.  This
           saves the work of doing the homogeneous division: {X,Y}/W==+-1.0,
           (and avoiding problems when W is zero for points on the eye plane in
           Z,) but it comes down to the same thing as clipping to X,Y==+-1 in
           orthographic.

           So the projection matrix decides what 3D model-space planes map to
           +-1 in X,Y.  (I think it maps [near,far] to [0,1] in Z, because
           they're not clipped symmetrically.)

           Then glViewport sets the hardware transform that determines where the
           +-1 square of clipped output goes in screen pixels within the window.

           Normally you don't actually draw pixels while picking in GL_SELECT
           mode because the pipeline outputs hits after the clipping stage, so
           gluPickMatrix only reads the viewport and sets the projection matrix.
        """
        #bruce 080912 moved this from GLPane into GLPane_minimal
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()

        scale = self.scale * self.zoomFactor
        near, far = self.near, self.far

        aspect = self.aspect
        vdist = self.vdist

        if glselect:
            x, y, w, h = glselect
            gluPickMatrix(
                x, y,
                w, h,
                glGetIntegerv( GL_VIEWPORT ) #k is this arg needed? it might be the default...
            )

        if self.ortho:
            glOrtho( - scale * aspect, scale * aspect,
                     - scale,          scale,
                     vdist * near, vdist * far )
        else:
            glFrustum( - scale * near * aspect, scale * near * aspect,
                       - scale * near,          scale * near,
                       vdist * near, vdist * far)
        return
Example #23
0
    def do_glselect_if_wanted(self):  # bruce 070919 split this out
        """
        Do the glRenderMode(GL_SELECT) drawing, and/or the glname-color
        drawing for shader primitives, used to guess which object
        might be under the mouse, for one drawing frame,
        if desired for this frame. Report results by storing candidate
        mouseover objects in self.glselect_dict. 
        
        The depth buffer is initially clear, and must be clear
        when we're done as well.

        @note: does not do related individual object depth/stencil 
               buffer drawing -- caller must do that on some or all
               of the objects we store into self.glselect_dict.
        """
        if self.glselect_wanted:  # note: this will be reset below.
            ###@@@ WARNING: The original code for this, here in GLPane, has been duplicated and slightly modified
            # in at least three other places (search for glRenderMode to find them). This is bad; common code
            # should be used. Furthermore, I suspect it's sometimes needlessly called more than once per frame;
            # that should be fixed too. [bruce 060721 comment]
            wX, wY, self.targetdepth = self.glselect_wanted  # wX, wY is the point to do the hit-test at
            # targetdepth is the depth buffer value to look for at that point, during ordinary drawing phase
            # (could also be used to set up clipping planes to further restrict hit-test, but this isn't yet done)
            # (Warning: targetdepth could in theory be out of date, if more events come between bareMotion
            #  and the one caused by its gl_update, whose paintGL is what's running now, and if those events
            #  move what's drawn. Maybe that could happen with mousewheel events or (someday) with keypresses
            #  having a graphical effect. Ideally we'd count intentional redraws, and disable this picking in that case.)
            self.wX, self.wY = wX, wY
            self.glselect_wanted = 0
            pwSize = 1  # Pick window size.  Russ 081128: Was 3.
            # Bruce: Replace 3, 3 with 1, 1? 5, 5? not sure whether this will
            # matter...  in principle should have no effect except speed.
            # Russ: For glname rendering, 1x1 is better because it doesn't
            # have window boundary issues.  We get the coords of a single
            # pixel in the window for the mouse position.

            # bruce 050615 for use by nodes which want to set up their own projection matrix.
            self.current_glselect = (wX, wY, pwSize, pwSize)
            self._setup_projection(glselect=self.current_glselect)  # option makes it use gluPickMatrix

            # Russ 081209: Added.
            debugPicking = debug_pref("GLPane: debug mouseover picking?", Choice_boolean_False, prefs_key=True)

            if self.enabled_shaders():
                # TODO: optimization: find an appropriate place to call
                # _compute_frustum_planes. [bruce 090105 comment]

                # Russ 081122: There seems to be no way to access the GL name
                # stack in shaders. Instead, for mouseover, draw shader
                # primitives with glnames as colors in glRenderMode(GL_RENDER),
                # then read back the pixel color (glname) and depth value.

                # Temporarily replace the full-size viewport with a little one
                # at the mouse location, matching the pick matrix location.
                # Otherwise, we will draw a closeup of that area into the whole
                # window, rather than a few pixels. (This wasn't needed when we
                # only used GL_SELECT rendering mode here, because that doesn't
                # modify the frame buffer -- it just returns hits by graphics
                # primitives when they are inside the clipping boundaries.)
                #
                # (Don't set the viewport *before* _setup_projection(), since
                #  that method needs to read the current whole-window viewport
                #  to set up glselect. See explanation in its docstring.)

                savedViewport = glGetIntegerv(GL_VIEWPORT)
                glViewport(wX, wY, pwSize, pwSize)  # Same as current_glselect.

                # First, clear the pixel RGBA to zeros and a depth of 1.0 (far),
                # so we won't confuse a color with a glname if there are
                # no shader primitives drawn over this pixel.
                saveDepthFunc = glGetInteger(GL_DEPTH_FUNC)
                glDepthFunc(GL_ALWAYS)
                glWindowPos3i(wX, wY, 1)  # Note the Z coord.
                gl_format, gl_type = GL_RGBA, GL_UNSIGNED_BYTE
                glDrawPixels(pwSize, pwSize, gl_format, gl_type, (0, 0, 0, 0))
                glDepthFunc(saveDepthFunc)  # needed, though we'll change it again

                # We must be in glRenderMode(GL_RENDER) (as usual) when this is called.
                # Note: _setup_projection leaves the matrix mode as GL_PROJECTION.
                glMatrixMode(GL_MODELVIEW)
                shaders = self.enabled_shaders()
                try:
                    # Set flags so that we will use glnames-as-color mode
                    # in shaders, and draw only shader primitives.
                    # (Ideally we would also draw all non-shader primitives
                    #  as some other color, unequal to all glname colors
                    #  (or derived from a fake glname for that purpose),
                    #  in order to obscure shader primitives where appropriate.
                    #  This is intended to be done but is not yet implemented.
                    #  [bruce 090105 addendum])
                    for shader in shaders:
                        shader.setPicking(True)
                    self.set_drawing_phase("glselect_glname_color")

                    for stereo_image in self.stereo_images_to_draw:
                        self._enable_stereo(stereo_image)
                        try:
                            self._do_graphicsMode_Draw(for_mouseover_highlighting=True)
                            # note: we can't disable depth writing here,
                            # since we need it to make sure the correct
                            # shader object comes out on top, or is
                            # obscured by a DL object. Instead, we'll
                            # clear the depth buffer again (at this pixel)
                            # below. [bruce 090105]
                        finally:
                            self._disable_stereo()
                except:
                    print_compact_traceback(
                        "exception in or around _do_graphicsMode_Draw() during glname_color;"
                        "drawing ignored; restoring modelview matrix: "
                    )
                    # REVIEW: what does "drawing ignored" mean, in that message? [bruce 090105 question]
                    glMatrixMode(GL_MODELVIEW)
                    self._setup_modelview()  ### REVIEW: correctness of this is unreviewed!
                    # now it's important to continue, at least enough to restore other gl state
                    pass
                for shader in shaders:
                    shader.setPicking(False)
                self.set_drawing_phase("?")

                # Restore the viewport.
                glViewport(savedViewport[0], savedViewport[1], savedViewport[2], savedViewport[3])

                # Read pixel value from the back buffer and re-assemble glname.
                glFinish()  # Make sure the drawing has completed.
                # REVIEW: is this glFinish needed? [bruce 090105 comment]
                rgba = glReadPixels(wX, wY, 1, 1, gl_format, gl_type)[0][0]
                pixZ = glReadPixelsf(wX, wY, 1, 1, GL_DEPTH_COMPONENT)[0][0]

                # Clear our depth pixel to 1.0 (far), so we won't mess up the
                # subsequent call of preDraw_glselect_dict.
                # (The following is not the most direct way, but it ought to work.
                #  Note that we also clear the color pixel, since (being a glname)
                #  it has no purpose remaining in the color buffer -- either it's
                #  changed later, or, if not, that's a bug, but we'd rather have
                #  it black than a random color.) [bruce 090105 bugfix]
                glDepthFunc(GL_ALWAYS)
                glWindowPos3i(wX, wY, 1)  # Note the Z coord.
                glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE)
                gl_format, gl_type = GL_RGBA, GL_UNSIGNED_BYTE
                glDrawPixels(pwSize, pwSize, gl_format, gl_type, (0, 0, 0, 0))
                glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)
                glDepthFunc(saveDepthFunc)

                # Comes back sign-wrapped, in spite of specifying UNSIGNED_BYTE.
                def us(b):
                    if b < 0:
                        return 256 + b
                    return b

                bytes = tuple([us(b) for b in rgba])
                ##glname = (bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3])
                ## Temp fix: Ignore the last byte, which always comes back 255 on Windows.
                glname = bytes[0] << 16 | bytes[1] << 8 | bytes[2]
                if debugPicking:
                    print (
                        "shader mouseover xy %d %d, " % (wX, wY)
                        + "rgba bytes (0x%x, 0x%x, 0x%x, 0x%x), " % bytes
                        + "Z %f, glname 0x%x" % (pixZ, glname)
                    )
                    pass

                ### XXX This ought to be better-merged with the DL selection below.
                if glname:
                    obj = self.object_for_glselect_name(glname)
                    if debugPicking:
                        print "shader mouseover glname=%r, obj=%r." % (glname, obj)
                    if obj is None:
                        # REVIEW: does this happen for mouse over a non-shader primitive?
                        # [bruce 090105 question]

                        #### Note: this bug is common. Guess: we are still drawing
                        # ordinary colors for some primitives and/or for the
                        # background, and they are showing up here and confusing
                        # us. To help debug this, print the color too. But testing
                        # shows it's not so simple -- e.g. for rung bonds it happens
                        # where shader sphere and cylinder overlap, but not on either
                        # one alone; for strand bonds it also happens on the bonds alone
                        # (tested in Build DNA, in or not in Insert DNA).
                        # [bruce 090218]
                        #
                        # Update: Since it's so common, I need to turn it off by default.
                        # Q: is the situation safe?
                        # A: if a color looks like a real glname by accident,
                        # we'll get some random candidate object -- perhaps a killed one
                        # or from a different Part or even a closed assy --
                        # and try to draw it. That doesn't sound very safe. Unfortunately
                        # there is no perfect way to filter selobjs for safety, in the
                        # current still-informal Selobj_API. The best approximation is
                        # selobj_still_ok, and it should always say yes for the usual kinds,
                        # so I'll add it as a check in the 'else' clause below.
                        # [bruce 090311]
                        if debug_flags.atom_debug:
                            print "bug: object_for_glselect_name returns None for glname %r (color %r)" % (
                                glname,
                                bytes,
                            )
                    else:
                        if self.graphicsMode.selobj_still_ok(obj):
                            # bruce 090311 added condition, explained above
                            self.glselect_dict[id(obj)] = obj
                        else:
                            # This should be rare but possible. Leave it on briefly and see
                            # if it's ever common. If possible, gate it by atom_debug before
                            # the release. [bruce 090311]
                            print "fyi: glname-color selobj %r rejected since not selobj_still_ok" % obj
                        pass
                    pass
                pass

            if self._use_frustum_culling:
                self._compute_frustum_planes()
                # piotr 080331 - the frustum planes have to be setup after the
                # projection matrix is setup. I'm not sure if there may
                # be any side effects - see the comment below about
                # possible optimization.
            glSelectBuffer(self.SIZE_FOR_glSelectBuffer)
            # Note: this allocates a new select buffer,
            # and glRenderMode(GL_RENDER) returns it and forgets it,
            # so it's required before *each* call of glRenderMode(GL_SELECT) +
            # glRenderMode(GL_RENDER), not just once to set the size.
            # Ref: http://pyopengl.sourceforge.net/documentation/opengl_diffs.html
            # [bruce 080923 comment]
            glInitNames()

            # REVIEW: should we also set up a clipping plane just behind the
            # hit point, as (I think) is done in ThumbView, to reduce the
            # number of candidate objects? This might be a significant
            # optimization, though I don't think it eliminates the chance
            # of having multiple candidates. [bruce 080917 comment]

            glRenderMode(GL_SELECT)
            glMatrixMode(GL_MODELVIEW)
            try:
                self.set_drawing_phase("glselect")  # bruce 070124
                for stereo_image in self.stereo_images_to_draw:
                    self._enable_stereo(stereo_image)
                    try:
                        self._do_graphicsMode_Draw(for_mouseover_highlighting=True)
                    finally:
                        self._disable_stereo()
            except:
                print_compact_traceback(
                    "exception in or around _do_graphicsMode_Draw() during GL_SELECT; "
                    "ignored; restoring modelview matrix: "
                )
                glMatrixMode(GL_MODELVIEW)
                self._setup_modelview()  ### REVIEW: correctness of this is unreviewed!
                # now it's important to continue, at least enough to restore other gl state

            self._frustum_planes_available = False  # piotr 080331
            # just to be safe and not use the frustum planes computed for
            # the pick matrix
            self.set_drawing_phase("?")
            self.current_glselect = False
            # REVIEW: On systems with no stencil buffer, I think we'd also need
            # to draw selobj here in highlighted form (in case that form is
            # bigger than when it's not highlighted), or (easier & faster)
            # just always pretend it passes the hit test and add it to
            # glselect_dict -- and, make sure to give it "first dibs" for being
            # the next selobj. I'll implement some of this now (untested when
            # no stencil buffer) but not yet all. [bruce 050612]
            selobj = self.selobj
            if selobj is not None:
                self.glselect_dict[id(selobj)] = selobj
                # (review: is the following note correct?)
                # note: unneeded, if the func that looks at this dict always
                # tries selobj first (except for a kluge near
                # "if self.glselect_dict", commented on below)
            glFlush()
            hit_records = list(glRenderMode(GL_RENDER))
            if debugPicking:
                print "DLs %d hits" % len(hit_records)
            for (near, far, names) in hit_records:  # see example code, renderpass.py
                ## print "hit record: near, far, names:", near, far, names
                # e.g. hit record: near, far, names: 1439181696 1453030144 (1638426L,)
                # which proves that near/far are too far apart to give actual depth,
                # in spite of the 1- or 3-pixel drawing window (presumably they're vertices
                # taken from unclipped primitives, not clipped ones).
                del near, far
                if 1:
                    # partial workaround for bug 1527. This can be removed once that bug (in drawer.py)
                    # is properly fixed. This exists in two places -- GLPane.py and modes.py. [bruce 060217]
                    if names and names[-1] == 0:
                        print "%d(g) partial workaround for bug 1527: removing 0 from end of namestack:" % env.redraw_counter, names
                        names = names[:-1]
                if names:
                    # For now, we only use the last element of names,
                    # though (as of long before 080917) it is often longer:
                    # - some code pushes the same name twice (directly and
                    #   via ColorSorter) (see 060725 debug print below);
                    # - chunks push a name even when they draw atoms/bonds
                    #   which push their own names (see 080411 comment below).
                    #
                    # Someday: if we ever support "name/subname paths" we'll
                    # probably let first name interpret the remaining ones.
                    # In fact, if nodes change projection or viewport for
                    # their kids, and/or share their kids, they'd need to
                    # push their own names on the stack, so we'd know how
                    # to redraw the kids, or which ones are meant when they
                    # are shared.
                    if debug_flags.atom_debug and len(names) > 1:  # bruce 060725
                        if len(names) == 2 and names[0] == names[1]:
                            if not env.seen_before("dual-names bug"):  # this happens for Atoms (colorsorter bug??)
                                print "debug (once-per-session message): why are some glnames duplicated on the namestack?", names
                        else:
                            # Note: as of sometime before 080411, this became common --
                            # I guess that chunks (which recently acquired glselect names)
                            # are pushing their names even while drawing their atoms and bonds.
                            # I am not sure if this can cause any problems -- almost surely not
                            # directly, but maybe the nestedness of highlighted appearances could
                            # violate some assumptions made by the highlight code... anyway,
                            # to reduce verbosity I need to not print this when the deeper name
                            # is that of a chunk, and there are exactly two names. [bruce 080411]
                            if len(names) == 2 and isinstance(self.object_for_glselect_name(names[0]), self.assy.Chunk):
                                if not env.seen_before("nested names for Chunk"):
                                    print "debug (once-per-session message): nested glnames for a Chunk: ", names
                            else:
                                print "debug fyi: len(names) == %d (names = %r)" % (len(names), names)
                    obj = self.object_for_glselect_name(names[-1])  # k should always return an obj
                    if obj is None:
                        print "bug: object_for_glselect_name returns None for name %r at end of namestack %r" % (
                            names[-1],
                            names,
                        )
                    else:
                        self.glselect_dict[id(obj)] = obj
                        # note: outside of this method, one of these will be
                        # chosen to be saved as self.selobj and rerendered
                        # in "highlighted" form
                        ##if 0:
                        ##    # this debug print was useful for debugging bug 2945,
                        ##    # and when it happens it's usually a bug,
                        ##    # but not always:
                        ##    # - it's predicted to happen for ChunkDrawer._renderOverlayText
                        ##    # - and whenever we're using a whole-chunk display style
                        ##    # so we can't leave it in permanently. [bruce 081211]
                        ##    if isinstance( obj, self.assy.Chunk ):
                        ##        print "\n*** namestack topped with a chunk:", obj
                    pass
                continue  # next hit_record
            # e maybe we should now sort glselect_dict by "hit priority"
            # (for depth-tiebreaking), or at least put selobj first.
            # (or this could be done lower down, where it's used.)
            # [I think we do this now...]

        return  # from do_glselect_if_wanted
Example #24
0
     '<table border="1" cellspacing="0" cellpadding="2"><thead><tr><h2>%s</h2></tr></thead>'
     % desc)
 for i in info[module_name]:
     try:
         if len(i) == 2:
             key, value = i
         else:
             key, id, t = i
             if t[0] == 'b':
                 value = glGetBooleanv(id)
                 if operator.isSequence(value):
                     value = map(_boolean, value)
                 else:
                     value = _boolean(value)
             elif t[0] == 'i':
                 value = glGetIntegerv(id)
             elif t[0] == 'd':
                 value = glGetDoublev(id)
             elif t[0] == 'e':
                 if len(t) > 1:
                     if t[1] == 'u':
                         x = gluGetString(id)
                     else:
                         x = glGetString(id)
                 else:
                     x = id
                 x = string.split(x)
                 x.sort()
                 y = []
                 for ext in x:
                     try:
Example #25
0
    def do_glselect_if_wanted(self):  #bruce 070919 split this out
        """
        Do the glRenderMode(GL_SELECT) drawing, and/or the glname-color
        drawing for shader primitives, used to guess which object
        might be under the mouse, for one drawing frame,
        if desired for this frame. Report results by storing candidate
        mouseover objects in self.glselect_dict. 
        
        The depth buffer is initially clear, and must be clear
        when we're done as well.

        @note: does not do related individual object depth/stencil 
               buffer drawing -- caller must do that on some or all
               of the objects we store into self.glselect_dict.
        """
        if self.glselect_wanted:  # note: this will be reset below.
            ###@@@ WARNING: The original code for this, here in GLPane, has been duplicated and slightly modified
            # in at least three other places (search for glRenderMode to find them). This is bad; common code
            # should be used. Furthermore, I suspect it's sometimes needlessly called more than once per frame;
            # that should be fixed too. [bruce 060721 comment]
            wX, wY, self.targetdepth = self.glselect_wanted  # wX, wY is the point to do the hit-test at
            # targetdepth is the depth buffer value to look for at that point, during ordinary drawing phase
            # (could also be used to set up clipping planes to further restrict hit-test, but this isn't yet done)
            # (Warning: targetdepth could in theory be out of date, if more events come between bareMotion
            #  and the one caused by its gl_update, whose paintGL is what's running now, and if those events
            #  move what's drawn. Maybe that could happen with mousewheel events or (someday) with keypresses
            #  having a graphical effect. Ideally we'd count intentional redraws, and disable this picking in that case.)
            self.wX, self.wY = wX, wY
            self.glselect_wanted = 0
            pwSize = 1  # Pick window size.  Russ 081128: Was 3.
            # Bruce: Replace 3, 3 with 1, 1? 5, 5? not sure whether this will
            # matter...  in principle should have no effect except speed.
            # Russ: For glname rendering, 1x1 is better because it doesn't
            # have window boundary issues.  We get the coords of a single
            # pixel in the window for the mouse position.

            #bruce 050615 for use by nodes which want to set up their own projection matrix.
            self.current_glselect = (wX, wY, pwSize, pwSize)
            self._setup_projection(glselect=self.current_glselect
                                   )  # option makes it use gluPickMatrix

            # Russ 081209: Added.
            debugPicking = debug_pref("GLPane: debug mouseover picking?",
                                      Choice_boolean_False,
                                      prefs_key=True)

            if self.enabled_shaders():
                # TODO: optimization: find an appropriate place to call
                # _compute_frustum_planes. [bruce 090105 comment]

                # Russ 081122: There seems to be no way to access the GL name
                # stack in shaders. Instead, for mouseover, draw shader
                # primitives with glnames as colors in glRenderMode(GL_RENDER),
                # then read back the pixel color (glname) and depth value.

                # Temporarily replace the full-size viewport with a little one
                # at the mouse location, matching the pick matrix location.
                # Otherwise, we will draw a closeup of that area into the whole
                # window, rather than a few pixels. (This wasn't needed when we
                # only used GL_SELECT rendering mode here, because that doesn't
                # modify the frame buffer -- it just returns hits by graphics
                # primitives when they are inside the clipping boundaries.)
                #
                # (Don't set the viewport *before* _setup_projection(), since
                #  that method needs to read the current whole-window viewport
                #  to set up glselect. See explanation in its docstring.)

                savedViewport = glGetIntegerv(GL_VIEWPORT)
                glViewport(wX, wY, pwSize, pwSize)  # Same as current_glselect.

                # First, clear the pixel RGBA to zeros and a depth of 1.0 (far),
                # so we won't confuse a color with a glname if there are
                # no shader primitives drawn over this pixel.
                saveDepthFunc = glGetInteger(GL_DEPTH_FUNC)
                glDepthFunc(GL_ALWAYS)
                glWindowPos3i(wX, wY, 1)  # Note the Z coord.
                gl_format, gl_type = GL_RGBA, GL_UNSIGNED_BYTE
                glDrawPixels(pwSize, pwSize, gl_format, gl_type, (0, 0, 0, 0))
                glDepthFunc(
                    saveDepthFunc)  # needed, though we'll change it again

                # We must be in glRenderMode(GL_RENDER) (as usual) when this is called.
                # Note: _setup_projection leaves the matrix mode as GL_PROJECTION.
                glMatrixMode(GL_MODELVIEW)
                shaders = self.enabled_shaders()
                try:
                    # Set flags so that we will use glnames-as-color mode
                    # in shaders, and draw only shader primitives.
                    # (Ideally we would also draw all non-shader primitives
                    #  as some other color, unequal to all glname colors
                    #  (or derived from a fake glname for that purpose),
                    #  in order to obscure shader primitives where appropriate.
                    #  This is intended to be done but is not yet implemented.
                    #  [bruce 090105 addendum])
                    for shader in shaders:
                        shader.setPicking(True)
                    self.set_drawing_phase("glselect_glname_color")

                    for stereo_image in self.stereo_images_to_draw:
                        self._enable_stereo(stereo_image)
                        try:
                            self._do_graphicsMode_Draw(
                                for_mouseover_highlighting=True)
                            # note: we can't disable depth writing here,
                            # since we need it to make sure the correct
                            # shader object comes out on top, or is
                            # obscured by a DL object. Instead, we'll
                            # clear the depth buffer again (at this pixel)
                            # below. [bruce 090105]
                        finally:
                            self._disable_stereo()
                except:
                    print_compact_traceback(
                        "exception in or around _do_graphicsMode_Draw() during glname_color;"
                        "drawing ignored; restoring modelview matrix: ")
                    # REVIEW: what does "drawing ignored" mean, in that message? [bruce 090105 question]
                    glMatrixMode(GL_MODELVIEW)
                    self._setup_modelview(
                    )  ### REVIEW: correctness of this is unreviewed!
                    # now it's important to continue, at least enough to restore other gl state
                    pass
                for shader in shaders:
                    shader.setPicking(False)
                self.set_drawing_phase('?')

                # Restore the viewport.
                glViewport(savedViewport[0], savedViewport[1],
                           savedViewport[2], savedViewport[3])

                # Read pixel value from the back buffer and re-assemble glname.
                glFinish()  # Make sure the drawing has completed.
                # REVIEW: is this glFinish needed? [bruce 090105 comment]
                rgba = glReadPixels(wX, wY, 1, 1, gl_format, gl_type)[0][0]
                pixZ = glReadPixelsf(wX, wY, 1, 1, GL_DEPTH_COMPONENT)[0][0]

                # Clear our depth pixel to 1.0 (far), so we won't mess up the
                # subsequent call of preDraw_glselect_dict.
                # (The following is not the most direct way, but it ought to work.
                #  Note that we also clear the color pixel, since (being a glname)
                #  it has no purpose remaining in the color buffer -- either it's
                #  changed later, or, if not, that's a bug, but we'd rather have
                #  it black than a random color.) [bruce 090105 bugfix]
                glDepthFunc(GL_ALWAYS)
                glWindowPos3i(wX, wY, 1)  # Note the Z coord.
                glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE)
                gl_format, gl_type = GL_RGBA, GL_UNSIGNED_BYTE
                glDrawPixels(pwSize, pwSize, gl_format, gl_type, (0, 0, 0, 0))
                glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)
                glDepthFunc(saveDepthFunc)

                # Comes back sign-wrapped, in spite of specifying UNSIGNED_BYTE.
                def us(b):
                    if b < 0:
                        return 256 + b
                    return b

                bytes = tuple([us(b) for b in rgba])
                ##glname = (bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3])
                ## Temp fix: Ignore the last byte, which always comes back 255 on Windows.
                glname = (bytes[0] << 16 | bytes[1] << 8 | bytes[2])
                if debugPicking:
                    print("shader mouseover xy %d %d, " % (wX, wY) +
                          "rgba bytes (0x%x, 0x%x, 0x%x, 0x%x), " % bytes +
                          "Z %f, glname 0x%x" % (pixZ, glname))
                    pass

                ### XXX This ought to be better-merged with the DL selection below.
                if glname:
                    obj = self.object_for_glselect_name(glname)
                    if debugPicking:
                        print "shader mouseover glname=%r, obj=%r." % (glname,
                                                                       obj)
                    if obj is None:
                        # REVIEW: does this happen for mouse over a non-shader primitive?
                        # [bruce 090105 question]

                        #### Note: this bug is common. Guess: we are still drawing
                        # ordinary colors for some primitives and/or for the
                        # background, and they are showing up here and confusing
                        # us. To help debug this, print the color too. But testing
                        # shows it's not so simple -- e.g. for rung bonds it happens
                        # where shader sphere and cylinder overlap, but not on either
                        # one alone; for strand bonds it also happens on the bonds alone
                        # (tested in Build DNA, in or not in Insert DNA).
                        # [bruce 090218]
                        #
                        # Update: Since it's so common, I need to turn it off by default.
                        # Q: is the situation safe?
                        # A: if a color looks like a real glname by accident,
                        # we'll get some random candidate object -- perhaps a killed one
                        # or from a different Part or even a closed assy --
                        # and try to draw it. That doesn't sound very safe. Unfortunately
                        # there is no perfect way to filter selobjs for safety, in the
                        # current still-informal Selobj_API. The best approximation is
                        # selobj_still_ok, and it should always say yes for the usual kinds,
                        # so I'll add it as a check in the 'else' clause below.
                        # [bruce 090311]
                        if debug_flags.atom_debug:
                            print "bug: object_for_glselect_name returns None for glname %r (color %r)" % (
                                glname, bytes)
                    else:
                        if self.graphicsMode.selobj_still_ok(obj):
                            #bruce 090311 added condition, explained above
                            self.glselect_dict[id(obj)] = obj
                        else:
                            # This should be rare but possible. Leave it on briefly and see
                            # if it's ever common. If possible, gate it by atom_debug before
                            # the release. [bruce 090311]
                            print "fyi: glname-color selobj %r rejected since not selobj_still_ok" % obj
                        pass
                    pass
                pass

            if self._use_frustum_culling:
                self._compute_frustum_planes()
                # piotr 080331 - the frustum planes have to be setup after the
                # projection matrix is setup. I'm not sure if there may
                # be any side effects - see the comment below about
                # possible optimization.
            glSelectBuffer(self.SIZE_FOR_glSelectBuffer)
            # Note: this allocates a new select buffer,
            # and glRenderMode(GL_RENDER) returns it and forgets it,
            # so it's required before *each* call of glRenderMode(GL_SELECT) +
            # glRenderMode(GL_RENDER), not just once to set the size.
            # Ref: http://pyopengl.sourceforge.net/documentation/opengl_diffs.html
            # [bruce 080923 comment]
            glInitNames()

            # REVIEW: should we also set up a clipping plane just behind the
            # hit point, as (I think) is done in ThumbView, to reduce the
            # number of candidate objects? This might be a significant
            # optimization, though I don't think it eliminates the chance
            # of having multiple candidates. [bruce 080917 comment]

            glRenderMode(GL_SELECT)
            glMatrixMode(GL_MODELVIEW)
            try:
                self.set_drawing_phase('glselect')  #bruce 070124
                for stereo_image in self.stereo_images_to_draw:
                    self._enable_stereo(stereo_image)
                    try:
                        self._do_graphicsMode_Draw(
                            for_mouseover_highlighting=True)
                    finally:
                        self._disable_stereo()
            except:
                print_compact_traceback(
                    "exception in or around _do_graphicsMode_Draw() during GL_SELECT; "
                    "ignored; restoring modelview matrix: ")
                glMatrixMode(GL_MODELVIEW)
                self._setup_modelview(
                )  ### REVIEW: correctness of this is unreviewed!
                # now it's important to continue, at least enough to restore other gl state

            self._frustum_planes_available = False  # piotr 080331
            # just to be safe and not use the frustum planes computed for
            # the pick matrix
            self.set_drawing_phase('?')
            self.current_glselect = False
            # REVIEW: On systems with no stencil buffer, I think we'd also need
            # to draw selobj here in highlighted form (in case that form is
            # bigger than when it's not highlighted), or (easier & faster)
            # just always pretend it passes the hit test and add it to
            # glselect_dict -- and, make sure to give it "first dibs" for being
            # the next selobj. I'll implement some of this now (untested when
            # no stencil buffer) but not yet all. [bruce 050612]
            selobj = self.selobj
            if selobj is not None:
                self.glselect_dict[id(selobj)] = selobj
                # (review: is the following note correct?)
                # note: unneeded, if the func that looks at this dict always
                # tries selobj first (except for a kluge near
                # "if self.glselect_dict", commented on below)
            glFlush()
            hit_records = list(glRenderMode(GL_RENDER))
            if debugPicking:
                print "DLs %d hits" % len(hit_records)
            for (near, far,
                 names) in hit_records:  # see example code, renderpass.py
                ## print "hit record: near, far, names:", near, far, names
                # e.g. hit record: near, far, names: 1439181696 1453030144 (1638426L,)
                # which proves that near/far are too far apart to give actual depth,
                # in spite of the 1- or 3-pixel drawing window (presumably they're vertices
                # taken from unclipped primitives, not clipped ones).
                del near, far
                if 1:
                    # partial workaround for bug 1527. This can be removed once that bug (in drawer.py)
                    # is properly fixed. This exists in two places -- GLPane.py and modes.py. [bruce 060217]
                    if names and names[-1] == 0:
                        print "%d(g) partial workaround for bug 1527: removing 0 from end of namestack:" % env.redraw_counter, names
                        names = names[:-1]
                if names:
                    # For now, we only use the last element of names,
                    # though (as of long before 080917) it is often longer:
                    # - some code pushes the same name twice (directly and
                    #   via ColorSorter) (see 060725 debug print below);
                    # - chunks push a name even when they draw atoms/bonds
                    #   which push their own names (see 080411 comment below).
                    #
                    # Someday: if we ever support "name/subname paths" we'll
                    # probably let first name interpret the remaining ones.
                    # In fact, if nodes change projection or viewport for
                    # their kids, and/or share their kids, they'd need to
                    # push their own names on the stack, so we'd know how
                    # to redraw the kids, or which ones are meant when they
                    # are shared.
                    if debug_flags.atom_debug and len(
                            names) > 1:  # bruce 060725
                        if len(names) == 2 and names[0] == names[1]:
                            if not env.seen_before(
                                    "dual-names bug"
                            ):  # this happens for Atoms (colorsorter bug??)
                                print "debug (once-per-session message): why are some glnames duplicated on the namestack?", names
                        else:
                            # Note: as of sometime before 080411, this became common --
                            # I guess that chunks (which recently acquired glselect names)
                            # are pushing their names even while drawing their atoms and bonds.
                            # I am not sure if this can cause any problems -- almost surely not
                            # directly, but maybe the nestedness of highlighted appearances could
                            # violate some assumptions made by the highlight code... anyway,
                            # to reduce verbosity I need to not print this when the deeper name
                            # is that of a chunk, and there are exactly two names. [bruce 080411]
                            if len(names) == 2 and \
                               isinstance( self.object_for_glselect_name(names[0]), self.assy.Chunk ):
                                if not env.seen_before(
                                        "nested names for Chunk"):
                                    print "debug (once-per-session message): nested glnames for a Chunk: ", names
                            else:
                                print "debug fyi: len(names) == %d (names = %r)" % (
                                    len(names), names)
                    obj = self.object_for_glselect_name(
                        names[-1])  #k should always return an obj
                    if obj is None:
                        print "bug: object_for_glselect_name returns None for name %r at end of namestack %r" % (
                            names[-1], names)
                    else:
                        self.glselect_dict[id(obj)] = obj
                        # note: outside of this method, one of these will be
                        # chosen to be saved as self.selobj and rerendered
                        # in "highlighted" form
                        ##if 0:
                        ##    # this debug print was useful for debugging bug 2945,
                        ##    # and when it happens it's usually a bug,
                        ##    # but not always:
                        ##    # - it's predicted to happen for ChunkDrawer._renderOverlayText
                        ##    # - and whenever we're using a whole-chunk display style
                        ##    # so we can't leave it in permanently. [bruce 081211]
                        ##    if isinstance( obj, self.assy.Chunk ):
                        ##        print "\n*** namestack topped with a chunk:", obj
                    pass
                continue  # next hit_record
            #e maybe we should now sort glselect_dict by "hit priority"
            # (for depth-tiebreaking), or at least put selobj first.
            # (or this could be done lower down, where it's used.)
            # [I think we do this now...]

        return  # from do_glselect_if_wanted
Example #26
0
def do_check_GL_support(force_enable):
    props = {}
    try:
        #log redirection:
        def redirect_log(logger_name):
            logger = logging.getLogger(logger_name)
            assert logger is not None
            logger.saved_handlers = logger.handlers
            logger.saved_propagate = logger.propagate
            logger.handlers = [CaptureHandler()]
            logger.propagate = 0
            return logger
        fhlogger = redirect_log('OpenGL.formathandler')
        elogger = redirect_log('OpenGL.extensions')
        alogger = redirect_log('OpenGL.acceleratesupport')
        arlogger = redirect_log('OpenGL.arrays')
        clogger = redirect_log('OpenGL.converters')

        import OpenGL
        props["pyopengl"] = OpenGL.__version__
        from OpenGL.GL import GL_VERSION, GL_EXTENSIONS
        from OpenGL.GL import glGetString, glGetInteger, glGetIntegerv
        gl_version_str = glGetString(GL_VERSION)
        if gl_version_str is None:
            gl_check_error("OpenGL version is missing - cannot continue")
            return  {}
        gl_major = int(gl_version_str[0])
        gl_minor = int(gl_version_str[2])
        props["opengl"] = gl_major, gl_minor
        MIN_VERSION = (1,1)
        if (gl_major, gl_minor) < MIN_VERSION:
            gl_check_error("OpenGL output requires version %s or greater, not %s.%s" %
                              (".".join([str(x) for x in MIN_VERSION]), gl_major, gl_minor))
        else:
            log("found valid OpenGL version: %s.%s", gl_major, gl_minor)

        from OpenGL import version as OpenGL_version
        pyopengl_version = OpenGL_version.__version__
        try:
            import OpenGL_accelerate
            accel_version = OpenGL_accelerate.__version__
            props["accelerate"] = accel_version
            log("OpenGL_accelerate version %s", accel_version)
        except:
            log("OpenGL_accelerate not found")
            OpenGL_accelerate = None
            accel_version = None

        if accel_version is not None and pyopengl_version!=accel_version:
            global _version_warning_shown
            if not _version_warning_shown:
                log.warn("Warning: version mismatch between PyOpenGL and PyOpenGL-accelerate")
                log.warn(" this may cause crashes")
                _version_warning_shown = True
        vsplit = pyopengl_version.split('.')
        #we now require PyOpenGL 3.1 or later
        if vsplit[:2]<['3','1'] and not force_enable:
            gl_check_error("PyOpenGL version 3.1 or later is required (found version %s)" % pyopengl_version)
            return {}

        props["zerocopy"] = bool(OpenGL_accelerate) and is_pyopengl_memoryview_safe(pyopengl_version, accel_version)

        try:
            extensions = glGetString(GL_EXTENSIONS).decode().split(" ")
        except:
            log("error querying extensions", exc_info=True)
            extensions = []
            gl_check_error("OpenGL could not find the list of GL extensions - does the graphics driver support OpenGL?")
        log("OpenGL extensions found: %s", ", ".join(extensions))
        props["extensions"] = extensions

        from OpenGL.arrays.arraydatatype import ArrayDatatype
        try:
            log("found the following array handlers: %s", set(ArrayDatatype.getRegistry().values()))
        except:
            pass

        from OpenGL.GL import GL_RENDERER, GL_VENDOR, GL_SHADING_LANGUAGE_VERSION
        def fixstring(v):
            try:
                return str(v).strip()
            except:
                return str(v)
        for d,s,fatal in (("vendor",     GL_VENDOR,      True),
                          ("renderer",   GL_RENDERER,    True),
                          ("shading language version", GL_SHADING_LANGUAGE_VERSION, False)):
            try:
                v = glGetString(s)
                v = fixstring(v.decode())
                log("%s: %s", d, v)
            except:
                if fatal:
                    gl_check_error("OpenGL property '%s' is missing" % d)
                else:
                    log("OpenGL property '%s' is missing", d)
                v = ""
            props[d] = v
        vendor = props["vendor"]
        version_req = VERSION_REQ.get(vendor)
        if version_req:
            req_maj, req_min = version_req
            if gl_major<req_maj or (gl_major==req_maj and gl_minor<req_min):
                if force_enable:
                    log.warn("Warning: '%s' OpenGL driver requires version %i.%i", vendor, req_maj, req_min)
                    log.warn(" version %i.%i was found", gl_major, gl_minor)
                else:
                    gl_check_error("OpenGL version %i.%i is too old, %i.%i is required for %s" % (gl_major, gl_minor, req_maj, req_min, vendor))

        from OpenGL.GLU import gluGetString, GLU_VERSION, GLU_EXTENSIONS
        for d,s in {"GLU version": GLU_VERSION, "GLU extensions":GLU_EXTENSIONS}.items():
            v = gluGetString(s)
            v = v.decode()
            log("%s: %s", d, v)
            props[d] = v

        blacklisted = None
        whitelisted = None
        greylisted = None
        for k,vlist in BLACKLIST.items():
            v = props.get(k)
            if v in vlist:
                log("%s '%s' found in blacklist: %s", k, v, vlist)
                blacklisted = k, v
        for k,vlist in GREYLIST.items():
            v = props.get(k)
            if v in vlist:
                log("%s '%s' found in greylist: %s", k, v, vlist)
                greylisted = k, v
        for k,vlist in WHITELIST.items():
            v = props.get(k)
            if v in vlist:
                log("%s '%s' found in whitelist: %s", k, v, vlist)
                whitelisted = k, v
        if blacklisted:
            if whitelisted:
                log.info("%s '%s' enabled (found in both blacklist and whitelist)", *whitelisted)
            elif force_enable:
                log.warn("Warning: %s '%s' is blacklisted!", *blacklisted)
            else:
                gl_check_error("%s '%s' is blacklisted!" % (blacklisted))
        safe = bool(whitelisted) or not (bool(greylisted) or bool(blacklisted))
        if safe and sys.version_info[0]>2:
            log.warn("Warning: OpenGL python3 support is not enabled by default")
            safe = False
        props["safe"] = safe

        #check for specific functions we need:
        from OpenGL.GL import glActiveTexture, glTexSubImage2D, glTexCoord2i, \
            glViewport, glMatrixMode, glLoadIdentity, glOrtho, \
            glEnableClientState, glGenTextures, glDisable, \
            glBindTexture, glPixelStorei, glEnable, glBegin, glFlush, \
            glTexParameteri, glTexEnvi, glHint, glBlendFunc, glLineStipple, \
            glTexImage2D, \
            glMultiTexCoord2i, \
            glVertex2i, glEnd
        check_functions(glActiveTexture, glTexSubImage2D, glTexCoord2i, \
            glViewport, glMatrixMode, glLoadIdentity, glOrtho, \
            glEnableClientState, glGenTextures, glDisable, \
            glBindTexture, glPixelStorei, glEnable, glBegin, glFlush, \
            glTexParameteri, glTexEnvi, glHint, glBlendFunc, glLineStipple, \
            glTexImage2D, \
            glMultiTexCoord2i, \
            glVertex2i, glEnd)

        glEnablei = None
        try:
            from OpenGL.GL import glEnablei
        except:
            pass
        if not bool(glEnablei):
            log.warn("OpenGL glEnablei is not available, disabling transparency")
            global GL_ALPHA_SUPPORTED
            GL_ALPHA_SUPPORTED = False
        props["transparency"] = GL_ALPHA_SUPPORTED

        #check for framebuffer functions we need:
        from OpenGL.GL.ARB.framebuffer_object import GL_FRAMEBUFFER, \
            GL_COLOR_ATTACHMENT0, glGenFramebuffers, glBindFramebuffer, glFramebufferTexture2D
        check_functions(GL_FRAMEBUFFER, \
            GL_COLOR_ATTACHMENT0, glGenFramebuffers, glBindFramebuffer, glFramebufferTexture2D)

        for ext in required_extensions:
            if ext not in extensions:
                gl_check_error("OpenGL driver lacks support for extension: %s" % ext)
            else:
                log("Extension %s is present", ext)

        #this allows us to do CSC via OpenGL:
        #see http://www.opengl.org/registry/specs/ARB/fragment_program.txt
        from OpenGL.GL.ARB.fragment_program import glInitFragmentProgramARB
        if not glInitFragmentProgramARB():
            gl_check_error("OpenGL output requires glInitFragmentProgramARB")
        else:
            log("glInitFragmentProgramARB works")

        from OpenGL.GL.ARB.texture_rectangle import glInitTextureRectangleARB
        if not glInitTextureRectangleARB():
            gl_check_error("OpenGL output requires glInitTextureRectangleARB")
        else:
            log("glInitTextureRectangleARB works")

        from OpenGL.GL.ARB.vertex_program import glGenProgramsARB, glDeleteProgramsARB, \
            glBindProgramARB, glProgramStringARB
        check_functions(glGenProgramsARB, glDeleteProgramsARB, glBindProgramARB, glProgramStringARB)

        try:
            from OpenGL.GL import GL_MAX_TEXTURE_SIZE
            texture_size = glGetInteger(GL_MAX_TEXTURE_SIZE)
            #this one may be missing?
            rect_texture_size = texture_size
            try:
                from OpenGL.GL import GL_MAX_RECTANGLE_TEXTURE_SIZE
                rect_texture_size = glGetInteger(GL_MAX_RECTANGLE_TEXTURE_SIZE)
            except ImportError as e:
                log("OpenGL: %s", e)
                log("using GL_MAX_TEXTURE_SIZE=%s as default", texture_size)
        except Exception as e:
            emsg = str(e)
            if hasattr(e, "description"):
                emsg = e.description
            gl_check_error("unable to query max texture size: %s" % emsg)
            return props

        log("Texture size GL_MAX_RECTANGLE_TEXTURE_SIZE=%s, GL_MAX_TEXTURE_SIZE=%s", rect_texture_size, texture_size)
        texture_size_limit = min(rect_texture_size, texture_size)
        props["texture-size-limit"] = texture_size_limit

        try:
            from OpenGL.GL import GL_MAX_VIEWPORT_DIMS
            v = glGetIntegerv(GL_MAX_VIEWPORT_DIMS)
            max_viewport_dims = v[0], v[1]
            assert max_viewport_dims[0]>=texture_size_limit and max_viewport_dims[1]>=texture_size_limit
            log("GL_MAX_VIEWPORT_DIMS=%s", max_viewport_dims)
        except ImportError as e:
            log.error("Error querying max viewport dims: %s", e)
            max_viewport_dims = texture_size_limit, texture_size_limit
        props["max-viewport-dims"] = max_viewport_dims
        return props
    finally:
        for x in alogger.handlers[0].records:
            #strip default message prefix:
            msg = x.getMessage().replace("No OpenGL_accelerate module loaded: ", "")
            if msg=="No module named OpenGL_accelerate":
                msg = "missing accelerate module"
            if msg!="OpenGL_accelerate module loaded":
                msg = "PyOpenGL warning: %s" % msg
            log.info(msg)

        #format handler messages:
        STRIP_LOG_MESSAGE = "Unable to load registered array format handler "
        missing_handlers = []
        for x in fhlogger.handlers[0].records:
            msg = x.getMessage()
            p = msg.find(STRIP_LOG_MESSAGE)
            if p<0:
                #unknown message, log it:
                log.info(msg)
                continue
            format_handler = msg[p+len(STRIP_LOG_MESSAGE):]
            p = format_handler.find(":")
            if p>0:
                format_handler = format_handler[:p]
                missing_handlers.append(format_handler)
        if len(missing_handlers)>0:
            log.warn("PyOpenGL warning: missing array format handlers: %s", ", ".join(missing_handlers))

        for x in elogger.handlers[0].records:
            msg = x.getMessage()
            #ignore extension messages:
            p = msg.startswith("GL Extension ") and msg.endswith("available")
            if not p:
                log.info(msg)

        missing_accelerators = []
        STRIP_AR_HEAD = "Unable to load"
        STRIP_AR_TAIL = "from OpenGL_accelerate"
        for x in arlogger.handlers[0].records+clogger.handlers[0].records:
            msg = x.getMessage()
            if msg.startswith(STRIP_AR_HEAD) and msg.endswith(STRIP_AR_TAIL):
                m = msg[len(STRIP_AR_HEAD):-len(STRIP_AR_TAIL)].strip()
                m = m.replace("accelerators", "").replace("accelerator", "").strip()
                missing_accelerators.append(m)
                continue
            elif msg.startswith("Using accelerated"):
                log(msg)
            else:
                log.info(msg)
        if missing_accelerators:
            log.info("OpenGL accelerate missing: %s", ", ".join(missing_accelerators))

        def restore_logger(logger):
            logger.handlers = logger.saved_handlers
            logger.propagate = logger.saved_propagate
        restore_logger(fhlogger)
        restore_logger(elogger)
        restore_logger(alogger)
        restore_logger(arlogger)
        restore_logger(clogger)
Example #27
0
def check_PyOpenGL_support(force_enable):
    props = {}
    try:
        if CRASH:
            import ctypes
            ctypes.string_at(0)
            raise Exception("should have crashed!")
        elif TIMEOUT > 0:
            import time
            time.sleep(TIMEOUT)
        #log redirection:
        def redirect_log(logger_name):
            logger = logging.getLogger(logger_name)
            assert logger is not None
            logger.saved_handlers = logger.handlers
            logger.saved_propagate = logger.propagate
            logger.handlers = [CaptureHandler()]
            logger.propagate = 0
            return logger

        fhlogger = redirect_log('OpenGL.formathandler')
        elogger = redirect_log('OpenGL.extensions')
        alogger = redirect_log('OpenGL.acceleratesupport')
        arlogger = redirect_log('OpenGL.arrays')
        clogger = redirect_log('OpenGL.converters')

        import OpenGL
        props["pyopengl"] = OpenGL.__version__
        from OpenGL.GL import GL_VERSION, GL_EXTENSIONS
        from OpenGL.GL import glGetString, glGetInteger, glGetIntegerv
        gl_version_str = glGetString(GL_VERSION)
        if gl_version_str is None:
            raise_fatal_error("OpenGL version is missing - cannot continue")
            return {}
        gl_major = int(bytestostr(gl_version_str)[0])
        gl_minor = int(bytestostr(gl_version_str)[2])
        props["opengl"] = gl_major, gl_minor
        MIN_VERSION = (1, 1)
        if (gl_major, gl_minor) < MIN_VERSION:
            raise_fatal_error(
                "OpenGL output requires version %s or greater, not %s.%s" %
                (".".join([str(x) for x in MIN_VERSION]), gl_major, gl_minor))
        else:
            log("found valid OpenGL version: %s.%s", gl_major, gl_minor)

        from OpenGL import version as OpenGL_version
        pyopengl_version = OpenGL_version.__version__
        try:
            import OpenGL_accelerate  #@UnresolvedImport
            accel_version = OpenGL_accelerate.__version__
            props["accelerate"] = accel_version
            log("OpenGL_accelerate version %s", accel_version)
        except:
            log("OpenGL_accelerate not found")
            OpenGL_accelerate = None
            accel_version = None

        if accel_version is not None and pyopengl_version != accel_version:
            global _version_warning_shown
            if not _version_warning_shown:
                log.warn(
                    "Warning: version mismatch between PyOpenGL and PyOpenGL-accelerate"
                )
                log.warn(" %s vs %s", pyopengl_version, accel_version)
                log.warn(" this may cause crashes")
                _version_warning_shown = True
                gl_check_error(
                    "PyOpenGL vs accelerate version mismatch: %s vs %s" %
                    (pyopengl_version, accel_version))
        vsplit = pyopengl_version.split('.')
        #we now require PyOpenGL 3.1 or later
        if vsplit[:3] < ['3', '1'] and not force_enable:
            raise_fatal_error("PyOpenGL version %s is too old and buggy" %
                              pyopengl_version)
            return {}
        props["zerocopy"] = bool(
            OpenGL_accelerate) and is_pyopengl_memoryview_safe(
                pyopengl_version, accel_version)

        try:
            extensions = glGetString(GL_EXTENSIONS).decode().split(" ")
        except:
            log("error querying extensions", exc_info=True)
            extensions = []
            raise_fatal_error(
                "OpenGL could not find the list of GL extensions - does the graphics driver support OpenGL?"
            )
        log("OpenGL extensions found: %s", csv(extensions))
        props["extensions"] = extensions

        from OpenGL.arrays.arraydatatype import ArrayDatatype
        try:
            log("found the following array handlers: %s",
                set(ArrayDatatype.getRegistry().values()))
        except:
            pass

        from OpenGL.GL import GL_RENDERER, GL_VENDOR, GL_SHADING_LANGUAGE_VERSION

        def fixstring(v):
            try:
                return str(v).strip()
            except:
                return str(v)

        for d, s, fatal in (("vendor", GL_VENDOR, True), ("renderer",
                                                          GL_RENDERER, True),
                            ("shading-language-version",
                             GL_SHADING_LANGUAGE_VERSION, False)):
            try:
                v = glGetString(s)
                v = fixstring(v.decode())
                log("%s: %s", d, v)
            except:
                if fatal:
                    gl_check_error("OpenGL property '%s' is missing" % d)
                else:
                    log("OpenGL property '%s' is missing", d)
                v = ""
            props[d] = v
        vendor = props["vendor"]
        version_req = VERSION_REQ.get(vendor)
        if version_req:
            req_maj, req_min = version_req
            if gl_major < req_maj or (gl_major == req_maj
                                      and gl_minor < req_min):
                if force_enable:
                    log.warn(
                        "Warning: '%s' OpenGL driver requires version %i.%i",
                        vendor, req_maj, req_min)
                    log.warn(" version %i.%i was found", gl_major, gl_minor)
                else:
                    gl_check_error(
                        "OpenGL version %i.%i is too old, %i.%i is required for %s"
                        % (gl_major, gl_minor, req_maj, req_min, vendor))

        from OpenGL.GLU import gluGetString, GLU_VERSION, GLU_EXTENSIONS
        for d, s in {
                "GLU.version": GLU_VERSION,
                "GLU.extensions": GLU_EXTENSIONS
        }.items():
            v = gluGetString(s)
            v = v.decode()
            log("%s: %s", d, v)
            props[d] = v

        def match_list(thelist, listname):
            for k, vlist in thelist.items():
                v = props.get(k)
                matches = [x for x in vlist if v.find(x) >= 0]
                if matches:
                    log("%s '%s' found in %s: %s", k, v, listname, vlist)
                    return (k, v)
                log("%s '%s' not found in %s: %s", k, v, listname, vlist)
            return None

        blacklisted = match_list(BLACKLIST, "blacklist")
        greylisted = match_list(GREYLIST, "greylist")
        whitelisted = match_list(WHITELIST, "whitelist")
        if blacklisted:
            if whitelisted:
                log.info(
                    "%s '%s' enabled (found in both blacklist and whitelist)",
                    *whitelisted)
            elif force_enable:
                log.warn("Warning: %s '%s' is blacklisted!", *blacklisted)
                log.warn(" force enabled by option")
            else:
                raise_fatal_error("%s '%s' is blacklisted!" % (blacklisted))
        safe = bool(whitelisted) or not bool(blacklisted)
        if greylisted and not whitelisted:
            log.warn("Warning: %s '%s' is greylisted,", *greylisted)
            log.warn(" you may want to turn off OpenGL if you encounter bugs")
        props["safe"] = safe

        #check for specific functions we need:
        from OpenGL.GL import glActiveTexture, glTexSubImage2D, glTexCoord2i, \
            glViewport, glMatrixMode, glLoadIdentity, glOrtho, \
            glEnableClientState, glGenTextures, glDisable, \
            glBindTexture, glPixelStorei, glEnable, glBegin, glFlush, \
            glTexParameteri, glTexEnvi, glHint, glBlendFunc, glLineStipple, \
            glTexImage2D, \
            glMultiTexCoord2i, \
            glVertex2i, glEnd
        check_functions(glActiveTexture, glTexSubImage2D, glTexCoord2i, \
            glViewport, glMatrixMode, glLoadIdentity, glOrtho, \
            glEnableClientState, glGenTextures, glDisable, \
            glBindTexture, glPixelStorei, glEnable, glBegin, glFlush, \
            glTexParameteri, glTexEnvi, glHint, glBlendFunc, glLineStipple, \
            glTexImage2D, \
            glMultiTexCoord2i, \
            glVertex2i, glEnd)
        #check for framebuffer functions we need:
        from OpenGL.GL.ARB.framebuffer_object import GL_FRAMEBUFFER, \
            GL_COLOR_ATTACHMENT0, glGenFramebuffers, glBindFramebuffer, glFramebufferTexture2D
        check_functions(GL_FRAMEBUFFER, \
            GL_COLOR_ATTACHMENT0, glGenFramebuffers, glBindFramebuffer, glFramebufferTexture2D)

        glEnablei = None
        try:
            from OpenGL.GL import glEnablei
        except:
            pass
        if not bool(glEnablei):
            log.warn(
                "OpenGL glEnablei is not available, disabling transparency")
            global GL_ALPHA_SUPPORTED
            GL_ALPHA_SUPPORTED = False
        props["transparency"] = GL_ALPHA_SUPPORTED

        for ext in required_extensions:
            if ext not in extensions:
                raise_fatal_error(
                    "OpenGL driver lacks support for extension: %s" % ext)
            else:
                log("Extension %s is present", ext)

        #this allows us to do CSC via OpenGL:
        #see http://www.opengl.org/registry/specs/ARB/fragment_program.txt
        from OpenGL.GL.ARB.fragment_program import glInitFragmentProgramARB
        if not glInitFragmentProgramARB():
            raise_fatal_error(
                "OpenGL output requires glInitFragmentProgramARB")
        else:
            log("glInitFragmentProgramARB works")

        from OpenGL.GL.ARB.texture_rectangle import glInitTextureRectangleARB
        if not glInitTextureRectangleARB():
            raise_fatal_error(
                "OpenGL output requires glInitTextureRectangleARB")
        else:
            log("glInitTextureRectangleARB works")

        from OpenGL.GL.ARB.vertex_program import glGenProgramsARB, glDeleteProgramsARB, \
            glBindProgramARB, glProgramStringARB
        check_functions(glGenProgramsARB, glDeleteProgramsARB,
                        glBindProgramARB, glProgramStringARB)

        try:
            from OpenGL.GL import GL_MAX_TEXTURE_SIZE
            texture_size = glGetInteger(GL_MAX_TEXTURE_SIZE)
            #this one may be missing?
            rect_texture_size = texture_size
            try:
                from OpenGL.GL import GL_MAX_RECTANGLE_TEXTURE_SIZE
                rect_texture_size = glGetInteger(GL_MAX_RECTANGLE_TEXTURE_SIZE)
            except ImportError as e:
                log("OpenGL: %s", e)
                log("using GL_MAX_TEXTURE_SIZE=%s as default", texture_size)
        except Exception as e:
            emsg = str(e)
            if hasattr(e, "description"):
                emsg = e.description
            gl_check_error("unable to query max texture size: %s" % emsg)
            return props

        log(
            "Texture size GL_MAX_RECTANGLE_TEXTURE_SIZE=%s, GL_MAX_TEXTURE_SIZE=%s",
            rect_texture_size, texture_size)
        texture_size_limit = min(rect_texture_size, texture_size)
        props["texture-size-limit"] = int(texture_size_limit)

        try:
            from OpenGL.GL import GL_MAX_VIEWPORT_DIMS
            v = glGetIntegerv(GL_MAX_VIEWPORT_DIMS)
            max_viewport_dims = int(v[0]), int(v[1])
            assert max_viewport_dims[
                0] >= texture_size_limit and max_viewport_dims[
                    1] >= texture_size_limit
            log("GL_MAX_VIEWPORT_DIMS=%s", max_viewport_dims)
        except ImportError as e:
            log.error("Error querying max viewport dims: %s", e)
            max_viewport_dims = texture_size_limit, texture_size_limit
        props["max-viewport-dims"] = max_viewport_dims
        return props
    finally:
        for x in alogger.handlers[0].records:
            #strip default message prefix:
            msg = x.getMessage().replace(
                "No OpenGL_accelerate module loaded: ", "")
            if msg == "No module named OpenGL_accelerate":
                msg = "missing accelerate module"
            if msg == "OpenGL_accelerate module loaded":
                log.info(msg)
            else:
                log.warn("PyOpenGL warning: %s", msg)

        #format handler messages:
        STRIP_LOG_MESSAGE = "Unable to load registered array format handler "
        missing_handlers = []
        for x in fhlogger.handlers[0].records:
            msg = x.getMessage()
            p = msg.find(STRIP_LOG_MESSAGE)
            if p < 0:
                #unknown message, log it:
                log.info(msg)
                continue
            format_handler = msg[p + len(STRIP_LOG_MESSAGE):]
            p = format_handler.find(":")
            if p > 0:
                format_handler = format_handler[:p]
                missing_handlers.append(format_handler)
        if len(missing_handlers) > 0:
            log.warn("PyOpenGL warning: missing array format handlers: %s",
                     csv(missing_handlers))

        for x in elogger.handlers[0].records:
            msg = x.getMessage()
            #ignore extension messages:
            p = msg.startswith("GL Extension ") and msg.endswith("available")
            if not p:
                log.info(msg)

        missing_accelerators = []
        STRIP_AR_HEAD = "Unable to load"
        STRIP_AR_TAIL = "from OpenGL_accelerate"
        for x in arlogger.handlers[0].records + clogger.handlers[0].records:
            msg = x.getMessage()
            if msg.startswith(STRIP_AR_HEAD) and msg.endswith(STRIP_AR_TAIL):
                m = msg[len(STRIP_AR_HEAD):-len(STRIP_AR_TAIL)].strip()
                m = m.replace("accelerators", "").replace("accelerator",
                                                          "").strip()
                missing_accelerators.append(m)
                continue
            elif msg.startswith("Using accelerated"):
                log(msg)
            else:
                log.info(msg)
        if missing_accelerators:
            log.info("OpenGL accelerate missing: %s",
                     csv(missing_accelerators))

        def restore_logger(logger):
            logger.handlers = logger.saved_handlers
            logger.propagate = logger.saved_propagate

        restore_logger(fhlogger)
        restore_logger(elogger)
        restore_logger(alogger)
        restore_logger(arlogger)
        restore_logger(clogger)
Example #28
0
    def _setup_projection(self, glselect=False):
        ### WARNING: This is not actually private! TODO: rename it.
        """
        Set up standard projection matrix contents using various attributes of
        self (aspect, vdist, scale, zoomFactor).  Also reads the current OpenGL
        viewport bounds in window coordinates.
        
        (Warning: leaves matrixmode as GL_PROJECTION.)
        
        @param glselect: False (default) normally, or a 4-tuple
               (format not documented here) to prepare for GL_SELECT picking by
               calling gluPickMatrix().

        If you are really going to draw in the pick window (for GL_RENDER and
        glReadPixels picking, rather than GL_SELECT picking), don't forget to
        set the glViewport *after* calling _setup_projection.  Here's why:

           gluPickMatrix needs to know the current *whole-window* viewport, in
           order to set up a projection matrix to map a small portion of it to
           the clipping boundaries for GL_SELECT.

           From the gluPickMatrix doc page:
             viewport:
               Specifies the current viewport (as from a glGetIntegerv call).
             Description:
               gluPickMatrix creates a projection matrix that can be used to
               restrict drawing to a small region of the viewport.

           In the graphics pipeline, the clipper actually works in homogeneous
           coordinates, clipping polygons to the {X,Y}==+-W boundaries.  This
           saves the work of doing the homogeneous division: {X,Y}/W==+-1.0,
           (and avoiding problems when W is zero for points on the eye plane in
           Z,) but it comes down to the same thing as clipping to X,Y==+-1 in
           orthographic.

           So the projection matrix decides what 3D model-space planes map to
           +-1 in X,Y.  (I think it maps [near,far] to [0,1] in Z, because
           they're not clipped symmetrically.)

           Then glViewport sets the hardware transform that determines where the
           +-1 square of clipped output goes in screen pixels within the window.

           Normally you don't actually draw pixels while picking in GL_SELECT
           mode because the pipeline outputs hits after the clipping stage, so
           gluPickMatrix only reads the viewport and sets the projection matrix.
        """
        #bruce 080912 moved this from GLPane into GLPane_minimal
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()

        scale = self.scale * self.zoomFactor
        near, far = self.near, self.far

        aspect = self.aspect
        vdist = self.vdist

        if glselect:
            x, y, w, h = glselect
            gluPickMatrix(
                x,
                y,
                w,
                h,
                glGetIntegerv(
                    GL_VIEWPORT
                )  #k is this arg needed? it might be the default...
            )

        if self.ortho:
            glOrtho(-scale * aspect, scale * aspect, -scale, scale,
                    vdist * near, vdist * far)
        else:
            glFrustum(-scale * near * aspect, scale * near * aspect,
                      -scale * near, scale * near, vdist * near, vdist * far)
        return
Example #29
0
    def set_data(self, data, **kwargs):
        '''Associates N-D point data with the window.
        ARGUMENTS:
            data (numpy.ndarray):
                An RxCxB array of data points to display.
        KEYWORD ARGUMENTS:
            classes (numpy.ndarray):
                An RxC array of integer class labels (zeros means unassigned).
            features (list):
                Indices of feautures to display in the octant (see
                NDWindow.set_octant_display_features for description).
        '''
        import OpenGL.GL as gl
        try:
            from OpenGL.GL import glGetIntegerv
        except:
            from OpenGL.GL.glget import glGetIntegerv

        classes = kwargs.get('classes', None)
        features = kwargs.get('features', list(range(6)))
        if self.data.shape[2] < 6:
            features = features[:3]
            self.quadrant_mode == 'single'

        # Scale the data set to span an octant

        data2d = np.array(data.reshape((-1, data.shape[-1])))
        mins = np.min(data2d, axis=0)
        maxes = np.max(data2d, axis=0)
        denom = (maxes - mins).astype(float)
        denom = np.where(denom > 0, denom, 1.0)
        self.data = (data2d - mins) / denom
        self.data.shape = data.shape

        self.palette = spy_colors.astype(float) / 255.
        self.palette[0] = np.array([1.0, 1.0, 1.0])
        self.colors = self.palette[self.classes.ravel()].reshape(
            self.data.shape[:2] + (3, ))
        self.colors = (self.colors * 255).astype('uint8')
        colors = np.ones((self.colors.shape[:-1]) + (4, ), 'uint8')
        colors[:, :, :-1] = self.colors
        self.colors = colors
        self._refresh_display_lists = True
        self.set_octant_display_features(features)

        # Determine the bit masks to use when using RGBA components for
        # identifying pixel IDs.
        components = [
            gl.GL_RED_BITS, gl.GL_GREEN_BITS, gl.GL_GREEN_BITS,
            gl.GL_ALPHA_BITS
        ]
        self._rgba_bits = [min(8, glGetIntegerv(i)) for i in components]
        self._low_bits = [min(8, 8 - self._rgba_bits[i]) for i in range(4)]
        self._rgba_masks = \
            [(2**self._rgba_bits[i] - 1) << (8 - self._rgba_bits[i])
             for i in range(4)]

        # Determine how many times the scene will need to be rendered in the
        # background to extract the pixel's row/col index.

        N = self.data.shape[0] * self.data.shape[1]
        if N > 2**sum(self._rgba_bits):
            raise Exception(
                'Insufficient color bits (%d) for N-D window display' %
                sum(self._rgba_bits))
        self.reset_view_geometry()
Example #30
0
			desc = string.split(module_name, '.', 1)[1]
		f.write('<table border="1" cellspacing="0" cellpadding="2"><thead><tr><h2>%s</h2></tr></thead>' % desc)
		for i in info[module_name]:
			try:
				if len(i) == 2:
					key, value = i
				else:
					key, id, t = i
					if t[0] == 'b':
						value = glGetBooleanv(id)
						if operator.isSequence(value):
							value = map(_boolean, value)
						else:
							value = _boolean(value)
					elif t[0] == 'i':
						value = glGetIntegerv(id)
					elif t[0] == 'd':
						value = glGetDoublev(id)
					elif t[0] == 'e':
						if len(t) > 1:
							if t[1] == 'u':
								x = gluGetString(id)
							else:
								x = glGetString(id)
						else:
							x = id
						x = string.split(x)
						x.sort()
						y = []
						for ext in x:
							try:
Example #31
0
    def set_data(self, data, **kwargs):
        '''Associates N-D point data with the window.
        ARGUMENTS:
            data (numpy.ndarray):
                An RxCxB array of data points to display.
        KEYWORD ARGUMENTS:
            classes (numpy.ndarray):
                An RxC array of integer class labels (zeros means unassigned).
            features (list):
                Indices of feautures to display in the octant (see
                NDWindow.set_octant_display_features for description).
        '''
        import OpenGL.GL as gl
        try:
            from OpenGL.GL import glGetIntegerv
        except:
            from OpenGL.GL.glget import glGetIntegerv

        classes = kwargs.get('classes', None)
        features = kwargs.get('features', list(range(6)))
        if self.data.shape[2] < 6:
            features = features[:3]
            self.quadrant_mode == 'single'

        # Scale the data set to span an octant

        data2d = np.array(data.reshape((-1, data.shape[-1])))
        mins = np.min(data2d, axis=0)
        maxes = np.max(data2d, axis=0)
        denom = (maxes - mins).astype(float)
        denom = np.where(denom > 0, denom, 1.0)
        self.data = (data2d - mins) / denom
        self.data.shape = data.shape

        self.palette = spy_colors.astype(float) / 255.
        self.palette[0] = np.array([1.0, 1.0, 1.0])
        self.colors = self.palette[self.classes.ravel()].reshape(
            self.data.shape[:2] + (3,))
        self.colors = (self.colors * 255).astype('uint8')
        colors = np.ones((self.colors.shape[:-1]) + (4,), 'uint8')
        colors[:, :, :-1] = self.colors
        self.colors = colors
        self._refresh_display_lists = True
        self.set_octant_display_features(features)

        # Determine the bit masks to use when using RGBA components for
        # identifying pixel IDs.
        components = [gl.GL_RED_BITS, gl.GL_GREEN_BITS,
                      gl.GL_GREEN_BITS, gl.GL_ALPHA_BITS]
        self._rgba_bits = [min(8, glGetIntegerv(i)) for i in components]
        self._low_bits = [min(8, 8 - self._rgba_bits[i]) for i in range(4)]
        self._rgba_masks = \
            [(2**self._rgba_bits[i] - 1) << (8 - self._rgba_bits[i])
             for i in range(4)]

        # Determine how many times the scene will need to be rendered in the
        # background to extract the pixel's row/col index.

        N = self.data.shape[0] * self.data.shape[1]
        if N > 2**sum(self._rgba_bits):
            raise Exception('Insufficient color bits (%d) for N-D window display'
                            % sum(self._rgba_bits))
        self.reset_view_geometry()
Example #32
0
    def draw_primitives(self,
                        scalefactor=1.0,
                        center=[0.0, 0.0, 0.0],
                        recenter=False,
                        want_camera=False):

        # measure the bounding box of all our primitives, so that we can
        # recenter them in our field of view
        if recenter:
            all_meshes = self.static_meshes + self.dynamic_meshes
            all_lines = self.static_lines + self.dynamic_lines

            if (len(all_meshes) + len(all_lines)) == 0:
                if want_camera:
                    return {
                        'modelview_matrix': glGetDoublev(GL_MODELVIEW_MATRIX),
                        'projection_matrix':
                        glGetDoublev(GL_PROJECTION_MATRIX),
                        'viewport': glGetIntegerv(GL_VIEWPORT)
                    }
                else:
                    return None

            for m in all_meshes:
                m.v = m.v.reshape((-1, 3))

            all_verts = np.concatenate([
                m.v[m.f.flatten() if len(m.f) > 0 else np.arange(len(m.v))]
                for m in all_meshes
            ] + [l.v[l.e.flatten()] for l in all_lines],
                                       axis=0)

            maximum = np.max(all_verts, axis=0)
            minimum = np.min(all_verts, axis=0)
            center = (maximum + minimum) / 2.
            scalefactor = (maximum - minimum) / 4.
            scalefactor = np.max(scalefactor)
        else:
            center = np.array(center)
            #            for mesh in self.dynamic_meshes :
            #                if mesh.f : mesh.reset_normals()
            all_meshes = self.static_meshes + self.dynamic_meshes
            all_lines = self.static_lines + self.dynamic_lines
        self.current_center = center
        self.current_scalefactor = scalefactor

        glMatrixMode(GL_MODELVIEW)
        glPushMatrix()
        # uncomment to add a default rotation (useful when automatically snapshoting kinect data
        # glRotate(220, 0.0, 1.0, 0.0)

        tf = np.identity(4, 'f') / scalefactor
        tf[:3, 3] = -center / scalefactor
        tf[3, 3] = 1
        cur_mtx = glGetFloatv(GL_MODELVIEW_MATRIX).T

        glLoadMatrixf(cur_mtx.dot(tf).T)

        if want_camera:
            result = {
                'modelview_matrix': glGetDoublev(GL_MODELVIEW_MATRIX),
                'projection_matrix': glGetDoublev(GL_PROJECTION_MATRIX),
                'viewport': glGetIntegerv(GL_VIEWPORT)
            }
        else:
            result = None

        for m in all_meshes:
            if not hasattr(m, 'vbo'):
                # Precompute vertex vbo
                fidxs = m.f.flatten() if len(m.f) > 0 else np.arange(len(m.v))
                allpts = m.v[fidxs].astype(np.float32).flatten()
                vbo = OpenGL.arrays.vbo.VBO(allpts)
                m.vbo = {'v': vbo}

                # Precompute normals vbo
                if hasattr(m, 'vn'):
                    ns = m.vn.astype(np.float32)
                    ns = ns[m.f.flatten(), :]
                    m.vbo['vn'] = OpenGL.arrays.vbo.VBO(ns.flatten())
                elif hasattr(m, 'f') and m.f.size > 0:
                    ns = TriNormals(m.v, m.f).reshape(-1, 3)
                    ns = np.tile(ns, (1, 3)).reshape(-1, 3).astype(np.float32)
                    m.vbo['vn'] = OpenGL.arrays.vbo.VBO(ns.flatten())

                # Precompute texture vbo
                if hasattr(m, 'ft') and (m.ft.size > 0):
                    ftidxs = m.ft.flatten()
                    data = m.vt[ftidxs].astype(np.float32)[:, 0:2]
                    data[:, 1] = 1.0 - 1.0 * data[:, 1]
                    m.vbo['vt'] = OpenGL.arrays.vbo.VBO(data)

                # Precompute color vbo
                if hasattr(m, 'vc'):
                    data = m.vc[fidxs].astype(np.float32)
                    m.vbo['vc'] = OpenGL.arrays.vbo.VBO(data)
                elif hasattr(m, 'fc'):
                    data = np.tile(m.fc, (1, 3)).reshape(-1,
                                                         3).astype(np.float32)
                    m.vbo['vc'] = OpenGL.arrays.vbo.VBO(data)

        for e in all_lines:
            self.draw_lines(e)

        for m in all_meshes:
            if hasattr(m, 'texture_image') and not hasattr(m, 'textureID'):
                self.set_texture(m)
            self.draw_mesh(m, self.lighting_on)

        glMatrixMode(GL_MODELVIEW)
        glPopMatrix()

        return result