From 634c8d5ff5a1a1ddb3330e75ff1cd54f091fc385 Mon Sep 17 00:00:00 2001 From: Paul McCarthy <pauld.mccarthy@gmail.com> Date: Fri, 24 Jul 2015 14:14:56 +0100 Subject: [PATCH] Bugfixes. - All GLObjects test to see if opts instances have a parent, before doing things with their sync properties. - Render.py bug - using fsl/utils/layout functions, passing showLabels=True, but then passing no labels. Renderpy usage fixed, and layout test added (reverts to showLabels=False if no labels are provided) - CanvasPanel screenshot was passing all overlays, instead of just enabled/saved ones - settingspy imports wx inside functions, in case we're running in headless mode - In my SliceCanvas.genGLObject refactoring, I removed a critical piece of functionality - genGLObject(updateRenderTextures=True) was not updating render textures. --- fsl/fslview/gl/gl14/edge2D.prog | 26 ++++++++------- fsl/fslview/gl/gl14/gllinevector_funcs.py | 16 +++++++--- fsl/fslview/gl/gllabel.py | 22 +++++++------ fsl/fslview/gl/glmask.py | 20 +++++++----- fsl/fslview/gl/glvector.py | 18 +++++++---- fsl/fslview/gl/glvolume.py | 25 ++++++++------- fsl/fslview/gl/slicecanvas.py | 7 +++- fsl/fslview/overlay.py | 2 +- fsl/fslview/settings.py | 6 ++-- fsl/fslview/views/canvaspanel.py | 10 +++--- fsl/tools/render.py | 39 ++++++++++++----------- fsl/utils/layout.py | 4 ++- 12 files changed, 113 insertions(+), 82 deletions(-) diff --git a/fsl/fslview/gl/gl14/edge2D.prog b/fsl/fslview/gl/gl14/edge2D.prog index a89a45885..170a5f87d 100644 --- a/fsl/fslview/gl/gl14/edge2D.prog +++ b/fsl/fslview/gl/gl14/edge2D.prog @@ -12,8 +12,10 @@ TEMP off; TEMP back; TEMP front; TEMP tempCoord; -TEMP isEdgeBack[2]; -TEMP isEdgeFront[2]; +TEMP isEdgeBack0; +TEMP isEdgeBack1; +TEMP isEdgeFront0; +TEMP isEdgeFront1; TEMP isEdge; # Test along the x axis @@ -35,8 +37,8 @@ SUB front, front, val; ABS back, back; ABS front, front; -SLT isEdgeBack[0], tol, back; -SLT isEdgeFront[0], tol, front; +SLT isEdgeBack0, tol, back; +SLT isEdgeFront0, tol, front; # Test along the y axis @@ -58,22 +60,22 @@ SUB front, front, val; ABS back, back; ABS front, front; -SLT isEdgeBack[1], tol, back; -SLT isEdgeFront[1], tol, front; +SLT isEdgeBack1, tol, back; +SLT isEdgeFront1, tol, front; # For each of the isEdgeBack/isEdgeFront # vectors, set all components to 1 if an # edge was found on any component. -DP4 isEdgeBack[ 0], isEdgeBack[ 0], isEdgeBack[ 0]; -DP4 isEdgeFront[0], isEdgeFront[0], isEdgeFront[0]; -DP4 isEdgeBack[ 1], isEdgeBack[ 1], isEdgeBack[ 1]; -DP4 isEdgeFront[1], isEdgeFront[1], isEdgeFront[1]; +DP4 isEdgeBack0, isEdgeBack0, isEdgeBack0; +DP4 isEdgeFront0, isEdgeFront0, isEdgeFront0; +DP4 isEdgeBack1, isEdgeBack1, isEdgeBack1; +DP4 isEdgeFront1, isEdgeFront1, isEdgeFront1; # Set isEdge.i if there was an edge # on any component of the i axis. -MAX isEdge.x, isEdgeBack[0], isEdgeFront[0]; -MAX isEdge.y, isEdgeBack[1], isEdgeFront[1]; +MAX isEdge.x, isEdgeBack0, isEdgeFront0; +MAX isEdge.y, isEdgeBack1, isEdgeFront1; # Clamp the isEdge values to 1 SGE isEdge, isEdge, 1; diff --git a/fsl/fslview/gl/gl14/gllinevector_funcs.py b/fsl/fslview/gl/gl14/gllinevector_funcs.py index 94c24b0dc..38c0cf9ff 100644 --- a/fsl/fslview/gl/gl14/gllinevector_funcs.py +++ b/fsl/fslview/gl/gl14/gllinevector_funcs.py @@ -30,7 +30,7 @@ def init(self): self.lineVertices = None self._vertexResourceName = '{}_{}_vertices'.format( - type(self).__name__, id(self.image)) + type(self).__name__, id(self.image)) compileShaders( self) updateShaderState(self) @@ -42,16 +42,22 @@ def init(self): updateVertices(self) self.onUpdate() - opts.addListener('resolution', self.name, vertexUpdate, weak=False) - opts.addListener('directed', self.name, vertexUpdate, weak=False) + name = '{}_vertices'.format(self.name) + + opts.addListener('transform', name, vertexUpdate, weak=False) + opts.addListener('resolution', name, vertexUpdate, weak=False) + opts.addListener('directed', name, vertexUpdate, weak=False) def destroy(self): arbvp.glDeleteProgramsARB(1, gltypes.GLuint(self.vertexProgram)) arbfp.glDeleteProgramsARB(1, gltypes.GLuint(self.fragmentProgram)) - self.displayOpts.removeListener('resolution', self.name) - self.displayOpts.removeListener('directed', self.name) + name = '{}_vertices'.format(self.name) + + self.displayOpts.removeListener('transform', name) + self.displayOpts.removeListener('resolution', name) + self.displayOpts.removeListener('directed', name) glresources.delete(self._vertexResourceName) diff --git a/fsl/fslview/gl/gllabel.py b/fsl/fslview/gl/gllabel.py index 1b8e6379e..a1fc9edeb 100644 --- a/fsl/fslview/gl/gllabel.py +++ b/fsl/fslview/gl/gllabel.py @@ -101,11 +101,12 @@ class GLLabel(globject.GLImageObject): opts .addListener('volume', name, imageUpdate, weak=False) opts .addListener('resolution', name, imageUpdate, weak=False) opts.lut.addListener('labels', name, lutUpdate, weak=False) - - opts.addSyncChangeListener( - 'volume', name, imageRefresh, weak=False) - opts.addSyncChangeListener( - 'resolution', name, imageRefresh, weak=False) + + if opts.getParent() is not None: + opts.addSyncChangeListener( + 'volume', name, imageRefresh, weak=False) + opts.addSyncChangeListener( + 'resolution', name, imageRefresh, weak=False) def removeListeners(self): @@ -122,9 +123,11 @@ class GLLabel(globject.GLImageObject): opts .removeListener( 'lut', name) opts .removeListener( 'volume', name) opts .removeListener( 'resolution', name) - opts .removeSyncChangeListener('volume', name) - opts .removeSyncChangeListener('resolution', name) - opts.lut.removeListener( 'labels', name) + opts.lut.removeListener( 'labels', name) + + if opts.getParent() is not None: + opts.removeSyncChangeListener('volume', name) + opts.removeSyncChangeListener('resolution', name) @@ -140,7 +143,8 @@ class GLLabel(globject.GLImageObject): opts = self.displayOpts texName = '{}_{}' .format(type(self).__name__, id(self.image)) - unsynced = (not opts.isSyncedToParent('volume') or + unsynced = (opts.getParent() is None or + not opts.isSyncedToParent('volume') or not opts.isSyncedToParent('resolution')) if unsynced: diff --git a/fsl/fslview/gl/glmask.py b/fsl/fslview/gl/glmask.py index ac53ce08d..bf120fe3c 100644 --- a/fsl/fslview/gl/glmask.py +++ b/fsl/fslview/gl/glmask.py @@ -87,11 +87,12 @@ class GLMask(glvolume.GLVolume): opts .addListener('invert', name, colourUpdate, weak=False) opts .addListener('volume', name, imageUpdate, weak=False) opts .addListener('resolution', name, imageUpdate, weak=False) - - opts.addSyncChangeListener( - 'volume', name, imageRefresh, weak=False) - opts.addSyncChangeListener( - 'resolution', name, imageRefresh, weak=False) + + if opts.getParent() is not None: + opts.addSyncChangeListener( + 'volume', name, imageRefresh, weak=False) + opts.addSyncChangeListener( + 'resolution', name, imageRefresh, weak=False) def removeDisplayListeners(self): @@ -113,14 +114,17 @@ class GLMask(glvolume.GLVolume): opts .removeListener( 'invert', name) opts .removeListener( 'volume', name) opts .removeListener( 'resolution', name) - opts .removeSyncChangeListener('volume', name) - opts .removeSyncChangeListener('resolution', name) + + if opts.getParent() is not None: + opts.removeSyncChangeListener('volume', name) + opts.removeSyncChangeListener('resolution', name) def testUnsynced(self): """Overrides :meth:`.GLVolume.testUnsynced`. """ - return (not self.displayOpts.isSyncedToParent('volume') or + return (self.displayOpts.getParent() is None or + not self.displayOpts.isSyncedToParent('volume') or not self.displayOpts.isSyncedToParent('resolution')) diff --git a/fsl/fslview/gl/glvector.py b/fsl/fslview/gl/glvector.py index d026d3457..efd05bdd4 100644 --- a/fsl/fslview/gl/glvector.py +++ b/fsl/fslview/gl/glvector.py @@ -167,9 +167,10 @@ class GLVector(globject.GLImageObject): opts .addListener('modulate', name, modUpdate, weak=False) opts .addListener('modThreshold', name, shaderUpdate, weak=False) opts .addListener('resolution', name, imageUpdate, weak=False) - - opts.addSyncChangeListener( - 'resolution', name, imageRefresh, weak=False) + + if opts.getParent() is not None: + opts.addSyncChangeListener( + 'resolution', name, imageRefresh, weak=False) def removeListeners(self): @@ -192,8 +193,9 @@ class GLVector(globject.GLImageObject): opts .removeListener( 'modThreshold', name) opts .removeListener( 'volume', name) opts .removeListener( 'resolution', name) - opts .removeSyncChangeListener('volume', name) - opts .removeSyncChangeListener('resolution', name) + + if opts.getParent() is not None: + opts.removeSyncChangeListener('resolution', name) def refreshImageTexture(self): @@ -212,7 +214,8 @@ class GLVector(globject.GLImageObject): else: realPrefilter = lambda d: prefilter(d.transpose((3, 0, 1, 2))) - unsynced = (not opts.isSyncedToParent('resolution') or + unsynced = (opts.getParent() is None or + not opts.isSyncedToParent('resolution') or not opts.isSyncedToParent('volume')) if unsynced: @@ -268,7 +271,8 @@ class GLVector(globject.GLImageObject): type(self).__name__, id(self.image), id(modImage)) if modOpts is not None: - unsynced = (not modOpts.isSyncedToParent('resolution') or + unsynced = (modOpts.getParent() is None or + not modOpts.isSyncedToParent('resolution') or not modOpts.isSyncedToParent('volume')) # TODO If unsynced, this GLVector needs to diff --git a/fsl/fslview/gl/glvolume.py b/fsl/fslview/gl/glvolume.py index bcb28c7c4..40e4a5a22 100644 --- a/fsl/fslview/gl/glvolume.py +++ b/fsl/fslview/gl/glvolume.py @@ -123,9 +123,8 @@ class GLVolume(globject.GLImageObject): :class:`GLVolume` instance needs to create its own image texture; returns ``False`` otherwise. """ - if self.displayOpts.getParent() is None: - return True - return (not self.displayOpts.isSyncedToParent('volume') or + return (self.displayOpts.getParent() is None or + not self.displayOpts.isSyncedToParent('volume') or not self.displayOpts.isSyncedToParent('resolution') or not self.displayOpts.isSyncedToParent('interpolation')) @@ -230,12 +229,13 @@ class GLVolume(globject.GLImageObject): opts .addListener('resolution', lName, imageUpdate, weak=False) opts .addListener('interpolation', lName, imageUpdate, weak=False) - opts.addSyncChangeListener( - 'volume', lName, imageRefresh, weak=False) - opts.addSyncChangeListener( - 'resolution', lName, imageRefresh, weak=False) - opts.addSyncChangeListener( - 'interpolation', lName, imageRefresh, weak=False) + if opts.getParent() is not None: + opts.addSyncChangeListener( + 'volume', lName, imageRefresh, weak=False) + opts.addSyncChangeListener( + 'resolution', lName, imageRefresh, weak=False) + opts.addSyncChangeListener( + 'interpolation', lName, imageRefresh, weak=False) def removeDisplayListeners(self): @@ -258,9 +258,10 @@ class GLVolume(globject.GLImageObject): opts .removeListener( 'volume', lName) opts .removeListener( 'resolution', lName) opts .removeListener( 'interpolation', lName) - opts .removeSyncChangeListener('volume', lName) - opts .removeSyncChangeListener('resolution', lName) - opts .removeSyncChangeListener('interpolation', lName) + if opts.getParent() is not None: + opts.removeSyncChangeListener('volume', lName) + opts.removeSyncChangeListener('resolution', lName) + opts.removeSyncChangeListener('interpolation', lName) def preDraw(self): diff --git a/fsl/fslview/gl/slicecanvas.py b/fsl/fslview/gl/slicecanvas.py index 6da930479..6e43d1205 100644 --- a/fsl/fslview/gl/slicecanvas.py +++ b/fsl/fslview/gl/slicecanvas.py @@ -553,7 +553,7 @@ class SliceCanvas(props.HasProperties): 'changed to {}'.format(display.name, display.overlayType)) - self.__genGLObject(display.getOverlay(), display) + self.__genGLObject(display.getOverlay()) self._refresh() @@ -602,6 +602,9 @@ class SliceCanvas(props.HasProperties): self._glObjects[overlay] = globj + if updateRenderTextures: + self._updateRenderTextures() + if not display.isBound('softwareMode', self): display.bindProps('softwareMode', self) @@ -990,6 +993,8 @@ class SliceCanvas(props.HasProperties): # Assume that all is well - the texture # just has not yet been created if rt is None: + log.debug('Render texture missing for overlay {}'.format( + overlay)) continue log.debug('Drawing {} slice for overlay {} ' diff --git a/fsl/fslview/overlay.py b/fsl/fslview/overlay.py index cc26e9073..a7f1fd7bb 100644 --- a/fsl/fslview/overlay.py +++ b/fsl/fslview/overlay.py @@ -22,7 +22,6 @@ import fsl.data.featresults as featresults import fsl.data.featimage as fslfeatimage import fsl.data.strings as strings import fsl.data.model as fslmodel -import fsl.utils.dialog as fsldlg import fsl.fslview.settings as fslsettings @@ -227,6 +226,7 @@ def loadOverlays(paths, loadFunc='default', errorFunc='default', saveDir=True): # to show the currently loading image if defaultLoad: import wx + import fsl.utils.dialog as fsldlg loadDlg = fsldlg.SimpleMessageDialog(wx.GetApp().GetTopWindow()) # The default load function updates diff --git a/fsl/fslview/settings.py b/fsl/fslview/settings.py index a3f71ed48..d2d1347df 100644 --- a/fsl/fslview/settings.py +++ b/fsl/fslview/settings.py @@ -11,7 +11,8 @@ log = logging.getLogger(__name__) def read(name, default=None): - import wx + try: import wx + except: return None config = wx.Config('fslview') @@ -23,7 +24,8 @@ def read(name, default=None): def write(name, value): - import wx + try: import wx + except: return None value = str(value) config = wx.Config('fslview') diff --git a/fsl/fslview/views/canvaspanel.py b/fsl/fslview/views/canvaspanel.py index b76e0ee83..0c7f9d3f2 100644 --- a/fsl/fslview/views/canvaspanel.py +++ b/fsl/fslview/views/canvaspanel.py @@ -392,17 +392,15 @@ def _screenshot(overlayList, displayCtx, canvas): argv += ['--size', '{}'.format(width), '{}'.format(height)] argv += ['--background', '0', '0', '0', '255'] - argv += _genCommandLineArgs(overlayList, displayCtx, canvas) + argv += _genCommandLineArgs(overlays, displayCtx, canvas) log.debug('Generating screenshot with call ' 'to render: {}'.format(' '.join(argv))) # Run render.py to generate the screenshot - msg = strings.messages['CanvasPanel.screenshot.pleaseWait'] - busyDlg = wx.BusyInfo(msg, canvas) - result = fsl.runTool('render', argv) - - busyDlg.Destroy() + msg = strings.messages['CanvasPanel.screenshot.pleaseWait'] + dlg = fsldlg.ProcessingDialog(canvas, msg, fsl.runTool, 'render', argv) + result = dlg.Run() if result != 0: title = strings.titles[ 'CanvasPanel.screenshot.error'] diff --git a/fsl/tools/render.py b/fsl/tools/render.py index 8c18481bb..21770c808 100644 --- a/fsl/tools/render.py +++ b/fsl/tools/render.py @@ -75,26 +75,29 @@ def buildLabelBitmaps(overlayList, # There's no reference image for the selected overlay, # so we cannot calculate orientation labels if overlay is None: - return None + xorient = constants.ORIENT_UNKNOWN + yorient = constants.ORIENT_UNKNOWN + zorient = constants.ORIENT_UNKNOWN + else: - display = displayCtx.getDisplay(overlay) - opts = display.getDisplayOpts() + display = displayCtx.getDisplay(overlay) + opts = display.getDisplayOpts() - # The overlay is being displayed as it is stored on - # disk - the image.getOrientation method calculates - # and returns labels for each voxelwise axis. - if opts.transform in ('pixdim', 'id'): - xorient = overlay.getVoxelOrientation(0) - yorient = overlay.getVoxelOrientation(1) - zorient = overlay.getVoxelOrientation(2) - - # The overlay is being displayed in 'real world' space - - # the definition of this space may be present in the - # overlay meta data - else: - xorient = overlay.getWorldOrientation(0) - yorient = overlay.getWorldOrientation(1) - zorient = overlay.getWorldOrientation(2) + # The overlay is being displayed as it is stored on + # disk - the image.getOrientation method calculates + # and returns labels for each voxelwise axis. + if opts.transform in ('pixdim', 'id'): + xorient = overlay.getVoxelOrientation(0) + yorient = overlay.getVoxelOrientation(1) + zorient = overlay.getVoxelOrientation(2) + + # The overlay is being displayed in 'real world' space - + # the definition of this space may be present in the + # overlay meta data + else: + xorient = overlay.getWorldOrientation(0) + yorient = overlay.getWorldOrientation(1) + zorient = overlay.getWorldOrientation(2) if constants.ORIENT_UNKNOWN in [xorient, yorient, zorient]: fgColour = 'red' diff --git a/fsl/utils/layout.py b/fsl/utils/layout.py index 6e40170a9..49ce13889 100644 --- a/fsl/utils/layout.py +++ b/fsl/utils/layout.py @@ -240,7 +240,9 @@ def buildOrthoLayout(canvasBmps, bitmaps, and colour bar bitmap. """ - if labelBmps is None: labelBmps = [None] * len(canvasBmps) + if labelBmps is None: + labelBmps = [None] * len(canvasBmps) + showLabels = False canvasBoxes = map(lambda cbmp, lbmps: buildCanvasBox(cbmp, lbmps, -- GitLab