diff options
Diffstat (limited to 'silx/gui/plot3d/scene/viewport.py')
-rw-r--r-- | silx/gui/plot3d/scene/viewport.py | 59 |
1 files changed, 47 insertions, 12 deletions
diff --git a/silx/gui/plot3d/scene/viewport.py b/silx/gui/plot3d/scene/viewport.py index 72e1ea3..0cacbf0 100644 --- a/silx/gui/plot3d/scene/viewport.py +++ b/silx/gui/plot3d/scene/viewport.py @@ -1,7 +1,7 @@ # coding: utf-8 # /*########################################################################## # -# Copyright (c) 2015-2017 European Synchrotron Radiation Facility +# Copyright (c) 2015-2018 European Synchrotron Radiation Facility # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -198,12 +198,17 @@ class Viewport(event.Notifier): @property def background(self): - """Background color of the viewport (4-tuple of float in [0, 1]""" + """Viewport's background color (4-tuple of float in [0, 1] or None) + + The background color is used to clear to viewport. + If None, the viewport is not cleared + """ return self._background @background.setter def background(self, color): - color = rgba(color) + if color is not None: + color = rgba(color) if self._background != color: self._background = color self._changed() @@ -295,12 +300,16 @@ class Viewport(event.Notifier): gl.glHint(gl.GL_LINE_SMOOTH_HINT, gl.GL_NICEST) gl.glEnable(gl.GL_LINE_SMOOTH) - gl.glClearColor(*self.background) + if self.background is None: + gl.glClear(gl.GL_STENCIL_BUFFER_BIT | + gl.GL_DEPTH_BUFFER_BIT) + else: + gl.glClearColor(*self.background) - # Prepare OpenGL - gl.glClear(gl.GL_COLOR_BUFFER_BIT | - gl.GL_STENCIL_BUFFER_BIT | - gl.GL_DEPTH_BUFFER_BIT) + # Prepare OpenGL + gl.glClear(gl.GL_COLOR_BUFFER_BIT | + gl.GL_STENCIL_BUFFER_BIT | + gl.GL_DEPTH_BUFFER_BIT) ctx = RenderContext(self, glContext) self.scene.render(ctx) @@ -454,11 +463,13 @@ class Viewport(event.Notifier): winy = oy + height * 0.5 * (1. - ndcY) return winx, winy - def _pickNdcZGL(self, x, y): + def _pickNdcZGL(self, x, y, offset=0): """Retrieve depth from depth buffer and return corresponding NDC Z. :param int x: In pixels in window coordinates, origin left. :param int y: In pixels in window coordinates, origin top. + :param int offset: Number of pixels to look at around the given pixel + :return: Normalize device Z coordinate of depth in [-1, 1] or None if outside viewport. :rtype: float or None @@ -476,10 +487,34 @@ class Viewport(event.Notifier): # Get depth from depth buffer in [0., 1.] # Bind used framebuffer to get depth gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.framebuffer) - depth = gl.glReadPixels( - x, y, 1, 1, gl.GL_DEPTH_COMPONENT, gl.GL_FLOAT)[0] + + if offset == 0: # Fast path + # glReadPixels is not GL|ES friendly + depth = gl.glReadPixels( + x, y, 1, 1, gl.GL_DEPTH_COMPONENT, gl.GL_FLOAT)[0] + else: + offset = abs(int(offset)) + size = 2*offset + 1 + depthPatch = gl.glReadPixels( + x - offset, y - offset, + size, size, + gl.GL_DEPTH_COMPONENT, gl.GL_FLOAT) + depthPatch = depthPatch.ravel() # Work in 1D + + # TODO cache sortedIndices to avoid computing it each time + # Compute distance of each pixels to the center of the patch + offsetToCenter = numpy.arange(- offset, offset + 1, dtype=numpy.float32) ** 2 + sqDistToCenter = numpy.add.outer(offsetToCenter, offsetToCenter) + + # Use distance to center to sort values from the patch + sortedIndices = numpy.argsort(sqDistToCenter.ravel()) + sortedValues = depthPatch[sortedIndices] + + # Take first depth that is not 1 in the sorted values + hits = sortedValues[sortedValues != 1.] + depth = 1. if len(hits) == 0 else hits[0] + gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, 0) - # This is not GL|ES friendly # Z in NDC in [-1., 1.] return float(depth) * 2. - 1. |