diff --git a/fsl/fsleyes/gl/__init__.py b/fsl/fsleyes/gl/__init__.py index 52af7866c80c6afdd26dbd0acc829e1bec028b5d..dffe3c51cb9c945045850fcbb9641f23906871df 100644 --- a/fsl/fsleyes/gl/__init__.py +++ b/fsl/fsleyes/gl/__init__.py @@ -187,9 +187,14 @@ package also contains the following: ~fsl.fsleyes.gl.shaders """ -import logging + +import logging +import platform import os +import fsl.utils.async as async +import fsl.utils.platform as fslplatform + log = logging.getLogger(__name__) @@ -251,6 +256,9 @@ def bootstrap(glVersion=None): ``GL_VERSION`` A string containing the target OpenGL version, in the format ``major.minor``, e.g. ``2.1``. + + ``GL_RENDERER`` A string containing the name of the OpenGL renderer. + ``glvolume_funcs`` The version-specific module containing functions for rendering :class:`.GLVolume` instances. @@ -269,6 +277,11 @@ def bootstrap(glVersion=None): ``gltensor_funcs`` The version-specific module containing functions for rendering :class:`.GLTensor` instances. ====================== ==================================================== + + + This function also sets the :attr:`.Platform.glVersion` and + :attr:`.Platform.glRenderer` properties of the + :attr:`fsl.utils.platform.platform` instance. :arg glVersion: A tuple containing the desired (major, minor) OpenGL API @@ -308,7 +321,6 @@ def bootstrap(glVersion=None): # fall back to the gl14 implementation if glpkg == gl21: - # List any GL21 extensions here exts = ['GL_EXT_framebuffer_object', 'GL_ARB_instanced_arrays', @@ -380,6 +392,7 @@ def bootstrap(glVersion=None): except ValueError: pass thismod.GL_VERSION = verstr + thismod.GL_RENDERER = renderer thismod.glvolume_funcs = glpkg.glvolume_funcs thismod.glrgbvector_funcs = glpkg.glrgbvector_funcs thismod.gllinevector_funcs = glpkg.gllinevector_funcs @@ -387,6 +400,9 @@ def bootstrap(glVersion=None): thismod.gllabel_funcs = glpkg.gllabel_funcs thismod.gltensor_funcs = glpkg.gltensor_funcs thismod._bootstrapped = True + + fslplatform.glVersion = thismod.GL_VERSION + fslplatform.glRenderer = thismod.GL_RENDERER def getWXGLContext(parent=None): @@ -612,6 +628,25 @@ class WXGLCanvasTarget(object): self._glReady = False self.Bind(wx.EVT_PAINT, self._mainDraw) + + # Using the Apple software renderer under OSX, + # we need to call refresh on the idle loop, + # otherwise refresh of multiple canvases (i.e. + # the OrthoPanel). gets all screwed up. Don't + # know why. + if platform.system() == 'Darwin' and \ + 'software' in fslplatform.glRenderer.lower(): + + def refresh(*a): + async.idle(self.Refresh) + + # On other platforms/renderers, + # we can call Refresh directly + else: + def refresh(*a): + self.Refresh() + + self._refresh = refresh def _initGL(self): @@ -622,8 +657,12 @@ class WXGLCanvasTarget(object): def _draw(self, *a): - """This method should implement the OpenGL drawing logic. Must be + """This method should implement the OpenGL drawing logic - it must be implemented by subclasses. + + .. note:: When runing with an on-screen display, this method should + never be called directly - call the :meth:`_refresh` method + instead. """ raise NotImplementedError() @@ -670,9 +709,10 @@ class WXGLCanvasTarget(object): def _refresh(self, *a): - """Triggers a redraw via the :meth:`_draw` method.""" - self.Refresh() + """Triggers a redraw via the :meth:`_draw` method. + .. note:: This method is dynamically assigned in :meth:`__init__`. + """ def _postDraw(self): """Called after the scene has been rendered. Swaps the front/back diff --git a/fsl/fsleyes/gl/slicecanvas.py b/fsl/fsleyes/gl/slicecanvas.py index ef31b1c1eb7bac03aa3ac27c27a6853c79b42e1e..bbb27f1f5d1c79a13f0fe3920c800e34372aab93 100644 --- a/fsl/fsleyes/gl/slicecanvas.py +++ b/fsl/fsleyes/gl/slicecanvas.py @@ -208,13 +208,13 @@ class SliceCanvas(props.HasProperties): # when any of the properties of this # canvas change, we need to redraw self.addListener('zax', self.name, self._zAxisChanged) - self.addListener('pos', self.name, self._draw) - self.addListener('displayBounds', self.name, self._draw) - self.addListener('bgColour', self.name, self._draw) - self.addListener('cursorColour', self.name, self._draw) - self.addListener('showCursor', self.name, self._draw) - self.addListener('invertX', self.name, self._draw) - self.addListener('invertY', self.name, self._draw) + self.addListener('pos', self.name, self._refresh) + self.addListener('displayBounds', self.name, self._refresh) + self.addListener('bgColour', self.name, self._refresh) + self.addListener('cursorColour', self.name, self._refresh) + self.addListener('showCursor', self.name, self._refresh) + self.addListener('invertX', self.name, self._refresh) + self.addListener('invertY', self.name, self._refresh) self.addListener('zoom', self.name, self._zoomChanged) self.addListener('renderMode', self.name, self._renderModeChange) self.addListener('resolutionLimit', diff --git a/fsl/utils/platform.py b/fsl/utils/platform.py index 844856826a8efe53dc4af83c6056e619cc20f1c0..c3d6ca7a0b687932a464d07533b3612653bc2a4b 100644 --- a/fsl/utils/platform.py +++ b/fsl/utils/platform.py @@ -60,12 +60,20 @@ class Platform(notifier.Notifier): """The ``Platform`` class contains a handful of properties which contain information about the platform we are running on. + .. note:: The values of the :attr:`glVersion` and :attr:`glRenderer` + properties are not automatically set - they will only contain + a value if one is assigned to them. The + :func:`fsl.fsleyes.gl.bootstrap` function does this when it is + first called. + .. autosummary:: fsldir haveGui wxBuild wxFlavour + glVersion + glRenderer """ @@ -77,6 +85,8 @@ class Platform(notifier.Notifier): self.__haveGui = False self.__wxFlavour = None self.__wxPlatform = None + self.__glVersion = None + self.__glRenderer = None try: import wx @@ -151,6 +161,34 @@ class Platform(notifier.Notifier): self.__fsldir = value self.notify() + + @property + def glVersion(self): + """Returns the available OpenGL version, or ``None`` if it has not + been set. + """ + return self.__glVersion + + + @glVersion.setter + def glVersion(self, value): + """Set the available OpenGL version. """ + self.__glVersion = value + + + @property + def glRenderer(self): + """Returns the available OpenGL renderer, or ``None`` if it has not + been set. + """ + return self.__glRenderer + + + @glRenderer.setter + def glRenderer(self, value): + """Set the available OpenGL renderer. """ + self.__glRenderer = value + platform = Platform() """An instance of the :class:`Platform` class. Feel free to create your own