fsleyes.gl
¶
This package contains the OpenGL data and rendering stuff for FSLeyes. On-screen and off-screen rendering is supported, and two OpenGL versions (1.4 and 2.1) are supported. The contents of this package can be broadly categorised into the following:
Canvases: A canvas is a thing that can be drawn on.
Objects: An object is a thing which can be drawn on a canvas.
Quick start¶
import fsleyes.gl as fslgl
import fsleyes.gl.wxglslicecanvas as slicecanvas
# This function will be called when
# the GL context is ready to be used.
def ready():
# The fsleyes.gl package needs to do
# some initialisation that can only
# be performed once a GL context has
# been created.
fslgl.bootstrap()
# Once a GL context has been created,
# you can do stuff! The SliceCanvas
# will take care of creating and
# managing GLObjects for each overlay
# in the overlay list.
canvas = slicecanvas.WXGLSliceCanvas(parent, overlayList, displayCtx)
# Create a GL context, and tell it to
# call our function when it is ready.
fslgl.getGLContext(ready=ready)
# ...
# When you're finished, call the shutdown
# function to clear the context (only
# necessary for on-screen rendering)
fslgl.shutdown()
Canvases¶
A canvas is the destination for an OpenGL scene render. The following
canvases are defined in the gl
package:
The |
|
The |
|
The |
|
Contains logic to render a colour bar as an OpenGL texture. |
These classes are not intended to be used directly. This is because the gl
package has been written to support two primary use-cases:
On-screen display of a scene using a
wx.glcanvas.GLCanvas
canvas.Off-screen rendering of a scene to a file.
Because of this, the canvas classes listed above are not dependent upon the OpenGL environment in which they are used (i.e. on-screen or off-screen). Instead, two base classes are provided for each of the use-cases:
Base class for |
|
Base class for canvas objects which support off-screen rendering. |
And the following sub-classes are defined, providing use-case specific implementations for each of the available canvases:
The |
|
The |
|
The |
|
The |
|
The |
|
The |
|
The |
|
The |
The classes listed above are the ones which are intended to be instantiated and used by application code.
gl
objects¶
With the exception of the ColourBarCanvas
, everything that is drawn
on a canvas derives from the GLObject
base class. A GLObject
manages the underlying data structures, GL resources (e.g. shaders and
textures), and rendering routines required to draw an object, in 2D or 3D, to a
canvas. The following GLObject
sub-classes correspond to each of the
possible types (the Display.overlayType
property) that an overlay can
be displayed as:
|
The |
|
The |
|
The |
|
The |
|
The |
|
The |
|
The |
|
The |
|
The |
|
The |
|
The |
These objects are created and destroyed automatically by the canvas classes instances, so application code does not need to worry about them too much.
Annotations¶
Canvases can be annotated in a few ways, by use of the Annotations
class. An Annotations
object allows lines, rectangles, and other simple
shapes to be rendered on top of the GLObject
renderings which represent
the overlays in the OverlayList
. The Annotations
object for a
canvas instance can be accessed through its getAnnotations
method.
OpenGL versions and bootstrapping¶
FSLeyes needs to be able to run in restricted environments, such as within a
VNC session, and over SSH. In such environments the available OpenGL version
could be quite old, so the gl
package has been written to support an
environment as old as OpenGL 1.4.
The available OpenGL API version can only be determined once an OpenGL context
has been created, and a display is available for rendering. The package-level
getGLContext()
function allows a context to be created.
The data structures and rendering logic for some GLObject
classes differs
depending on the OpenGL version that is available. Therefore, the code for
these GLObject
classes may be duplicated, with one version for OpenGL 1.4,
and another version for OpenGL 2.1. The GLObject
code which targets a
specific OpenGL version lives within either the gl14
or gl21
sub-packages.
Because of this, the package-level bootstrap()
function must be called
before any GLObject
instances are created, but after a GL context has
been created.
- fsleyes.gl.GL_VERSION = None¶
Set in
bootstrap()
. String containing the available “major.minor” OpenGL version.
- fsleyes.gl.GL_COMPATIBILITY = None¶
Set in
bootstrap()
. String containing the target “major.minor” OpenGL compatibility version (“1.4” or “2.1”).
- fsleyes.gl.GL_RENDERER = None¶
Set in
bootstrap()
. Contains a description of the OpenGL renderer in use.
- fsleyes.gl._selectPyOpenGLPlatform()[source]¶
Pyopengl sometimes doesn’t select a suitable platform, so in some circumstances we need to force things (but not if
PYOPENGL_PLATFORM
is already set in the environment).
- fsleyes.gl.glIsSoftwareRenderer()[source]¶
Returns
True
if the OpenGL renderer appears to be software based,False
otherwise, orNone
bootstrap()
has not been called yet.Note
This check is based on heuristics, ans is not guaranteed to be correct.
- fsleyes.gl.bootstrap(glVersion=None)[source]¶
Imports modules appropriate to the specified OpenGL version.
The available OpenGL API version can only be queried once an OpenGL context is created, and a canvas is available to draw on. This makes things a bit complicated, because it means that we are only able to choose how to draw things when we actually need to draw them.
This function should be called after an OpenGL context has been created, and a canvas is available for drawing, but before any attempt to draw anything. It will figure out which version-dependent package needs to be loaded, and will attach all of the modules contained in said package to the
gl
package. The version-independent modules may then simply access these version-dependent modules through this module.After the
boostrap()
function has been called, the following package-level attributes will be available on thegl
package:GL_COMPATIBILITY
A string containing the target OpenGL version, in the format
major.minor
, e.g.2.1
.GL_VERSION
A string containing the available OpenGL version.
GL_RENDERER
A string containing the name of the OpenGL renderer.
glvolume_funcs
The version-specific module containing functions for rendering
GLVolume
instances.glrgbvolume_funcs
The version-specific module containing functions for rendering
GLRGBVolume
instances.glrgbvector_funcs
The version-specific module containing functions for rendering
GLRGBVector
instances.gllinevector_funcs
The version-specific module containing functions for rendering
GLLineVector
instances.glmesh_funcs
The version-specific module containing functions for rendering
GLMesh
instances.glmask_funcs
The version-specific module containing functions for rendering
GLMask
instances.gllabel_funcs
The version-specific module containing functions for rendering
GLLabel
instances.gltensor_funcs
The version-specific module containing functions for rendering
GLTensor
instances.glsh_funcs
The version-specific module containing functions for rendering
GLSH
instances.glmip_funcs
The version-specific module containing functions for rendering
GLMIP
instances.- Parameters
glVersion – A tuple containing the desired (major, minor) OpenGL API version to use. If
None
, the best possible API version will be used.
- fsleyes.gl.getGLContext(**kwargs)[source]¶
Create and return a GL context object for on- or off-screen OpenGL rendering.
If a context object has already been created, it is returned. Otherwise, one is created and returned.
See the
GLContext
class for details on the arguments.Warning
Use the
ready
argument toGLContext.__init__()
, and don’t callbootstrap()
until it has been called!
- fsleyes.gl.shutdown()[source]¶
Must be called when the GL rendering context is no longer needed. Destroys the context object, and resources associated with it.
Does not need to be called for off-screen rendering.
- class fsleyes.gl.GLContext(offscreen=False, other=None, target=None, createApp=False, ready=None, raiseErrors=False)[source]¶
Bases:
object
The
GLContext
class manages the creation of, and access to, an OpenGL context. This class abstracts away the differences between creation of on-screen and off-screen rendering contexts. It contains two methods:setTarget()
, which may be used to set aWXGLCanvasTarget
or anOffScreenCanvasTarget
as the GL rendering target.destroy()
, which must be called when the context is no longer needed.
On-screen rendering is performed via the
wx.GLCanvas.GLContext
context, whereas off-screen rendering is performed viaOpenGL.raw.osmesa.mesa
(OSMesa is assumed to be available).If it is possible to do so, a
wx.glcanvas.GLContext
will be created, even if an off-screen context has been requested. This is because using the native graphics card is nearly always preferable to using OSMesa.Creating an on-screen GL context
A
wx.glcanvas.GLContext
may only be created once awx.glcanvas.GLCanvas
has been created, and is visible on screen. TheGLContext
class therefore creates a dummywx.Frame
andGLCanvas
, and displays it, before creating thewx
GL context.A reference to this dummy
wx.Frame
is retained, because destroying it can result inGLXBadCurrentWindow
errors when running on macOS+XQuartz. The frame is destroyed on calls to theGLContext.destroy
method.Because
wx
contexts may be used even when an off-screen rendering context has been requested, theGLContext
class has the ability to create and run a temporarywx.App
, on which the canvas and context creation process is executed. This horrible ability is necessary, because awx.GLContext
must be created on awx
application loop. We cannot otherwise guarantee that thewx.GLCanvas
will be visible before thewx.GLContext
is created.The above issue has the effect that the real underlying
wx.GLContext
may only be created after theGLContext.__init__
method has returned. Therefore, you must use theready
callback function if you are creating awx
GL context - this function will be called when theGLContext
is ready to be used.You can get away without using the
ready
callback in the following situations:When you are 100% sure that you will be using OSMesa.
When there is not (and never will be) a
wx.MainLoop
running, and you pass increateApp=True
.
- __init__(offscreen=False, other=None, target=None, createApp=False, ready=None, raiseErrors=False)[source]¶
Create a
GLContext
.- Parameters
offscreen – On-screen or off-screen context?
other – Another
GLContext
instance with which GL state should be shared.target – If
other
is notNone
, this must be a reference to aWXGLCanvasTarget
, the rendering target for the new context.createApp – If
True
, and if possible, thisGLContext
will create and run awx.App
so that it can create awx.glcanvas.GLContext
.ready – Function which will be called when the context has been created and is ready to use.
- Are raiseErrors
Defaults to
False
. IfTrue
, and if theready
function raises an error, that error is not caught.
- destroy()[source]¶
Called by the module-level
shutdown()
function. If this is an on-screen context, the dummy canvas and frame that were created at initialisation are destroyed.
- setTarget(target=None)[source]¶
Set the given
WXGLCanvasTarget
orOffScreenCanvasTarget
as the target for GL rendering with this context.If
target
is None, and this is an on-screen rendering context, the dummywx.glcanvas.GLCanvas
that was used to create thisGLContext
is set as the rendering target.
- __createWXGLParent()¶
Create a dummy
wx.Frame
to be used as the parent for the dummywx.glcanvas.GLCanvas
.
- __createWXGLCanvas()¶
Create a dummy
wx.glcanvas.GLCanvas
instance which is to be used to create a context. Assigns the canvas to an attributed called__canvas
.
- __createWXGLContext(other=None, target=None)¶
Creates a
wx.glcanvas.GLContext
object, assigning it to an attribute called__context
. Assumes that awx.glcanvas.GLCanvas
has already been created.- Parameters
other – Another wx.glcanvas.GLContext` instance with which the new context should share GL state.
target – If
other
is notNone
, this must be awx.glcanvas.GLCanvas
, the rendering target for the new context.
Warning
This method must be called via the
wx.MainLoop
.
- __createOSMesaContext()¶
Creates an OSMesa context, assigning it to an attribute called
__context
.
- __dict__ = mappingproxy({'__module__': 'fsleyes.gl', '__doc__': 'The ``GLContext`` class manages the creation of, and access to, an\n OpenGL context. This class abstracts away the differences between\n creation of on-screen and off-screen rendering contexts.\n It contains two methods:\n\n - :meth:`setTarget`, which may be used to set a\n :class:`.WXGLCanvasTarget` or an :class:`OffScreenCanvasTarget` as the\n GL rendering target.\n - :meth:`destroy`, which must be called when the context is no longer\n needed.\n\n\n On-screen rendering is performed via the ``wx.GLCanvas.GLContext``\n context, whereas off-screen rendering is performed via\n ``OpenGL.raw.osmesa.mesa`` (OSMesa is assumed to be available).\n\n\n If it is possible to do so, a ``wx.glcanvas.GLContext`` will be created,\n even if an off-screen context has been requested. This is because\n using the native graphics card is nearly always preferable to using\n OSMesa.\n\n\n *Creating an on-screen GL context*\n\n\n A ``wx.glcanvas.GLContext`` may only be created once a\n ``wx.glcanvas.GLCanvas`` has been created, and is visible on screen. The\n ``GLContext`` class therefore creates a dummy ``wx.Frame`` and\n ``GLCanvas``, and displays it, before creating the ``wx`` GL context.\n\n\n A reference to this dummy ``wx.Frame`` is retained, because destroying it\n can result in ``GLXBadCurrentWindow`` errors when running on\n macOS+XQuartz. The frame is destroyed on calls to the ``GLContext.destroy``\n method.\n\n\n Because ``wx`` contexts may be used even when an off-screen rendering\n context has been requested, the ``GLContext`` class has the ability to\n create and run a temporary ``wx.App``, on which the canvas and context\n creation process is executed. This horrible ability is necessary, because\n a ``wx.GLContext`` must be created on a ``wx`` application loop. We cannot\n otherwise guarantee that the ``wx.GLCanvas`` will be visible before the\n ``wx.GLContext`` is created.\n\n\n The above issue has the effect that the real underlying ``wx.GLContext``\n may only be created after the ``GLContext.__init__`` method has returned.\n Therefore, you must use the ``ready`` callback function if you are\n creating a ``wx`` GL context - this function will be called when the\n ``GLContext`` is ready to be used.\n\n\n You can get away without using the ``ready`` callback in the following\n situations:\n\n - When you are 100% sure that you will be using OSMesa.\n\n - When there is not (and never will be) a ``wx.MainLoop`` running, and\n you pass in ``createApp=True``.\n ', '__init__': <function GLContext.__init__>, 'destroy': <function GLContext.destroy>, 'setTarget': <function GLContext.setTarget>, '_GLContext__createWXGLParent': <function GLContext.__createWXGLParent>, '_GLContext__createWXGLCanvas': <function GLContext.__createWXGLCanvas>, '_GLContext__createWXGLContext': <function GLContext.__createWXGLContext>, '_GLContext__createOSMesaContext': <function GLContext.__createOSMesaContext>, '__dict__': <attribute '__dict__' of 'GLContext' objects>, '__weakref__': <attribute '__weakref__' of 'GLContext' objects>, '__annotations__': {}})¶
- __module__ = 'fsleyes.gl'¶
- __weakref__¶
list of weak references to the object (if defined)
- class fsleyes.gl.OffScreenCanvasTarget(width, height)[source]¶
Bases:
object
Base class for canvas objects which support off-screen rendering.
- __init__(width, height)[source]¶
Create an
OffScreenCanvasTarget
. ARenderTexture
is created, to be used as the rendering target.- Parameters
width – Width in pixels
height – Height in pixels
- canvasToWorld(xpos, ypos)[source]¶
Convert X/Y pixel coordinates into a location in the display coordinate system. Must be provided by subclasses.
- worldToCanvas(pos)[source]¶
Convert a location in the display coordinate system into X/Y pixel coordinates. Must be provided by subclasses.
- getBitmap()[source]¶
Return a (height*width*4) shaped numpy array containing the rendered scene as an RGBA bitmap. The bitmap will be full of zeros if the scene has not been drawn (via a call to
draw()
).
- __dict__ = mappingproxy({'__module__': 'fsleyes.gl', '__doc__': 'Base class for canvas objects which support off-screen rendering. ', '__init__': <function OffScreenCanvasTarget.__init__>, '_setGLContext': <function OffScreenCanvasTarget._setGLContext>, '_draw': <function OffScreenCanvasTarget._draw>, 'getAnnotations': <function OffScreenCanvasTarget.getAnnotations>, 'canvasToWorld': <function OffScreenCanvasTarget.canvasToWorld>, 'worldToCanvas': <function OffScreenCanvasTarget.worldToCanvas>, 'GetSize': <function OffScreenCanvasTarget.GetSize>, 'GetScaledSize': <function OffScreenCanvasTarget.GetScaledSize>, 'Refresh': <function OffScreenCanvasTarget.Refresh>, 'FreezeDraw': <function OffScreenCanvasTarget.FreezeDraw>, 'ThawDraw': <function OffScreenCanvasTarget.ThawDraw>, 'FreezeSwapBuffers': <function OffScreenCanvasTarget.FreezeSwapBuffers>, 'ThawSwapBuffers': <function OffScreenCanvasTarget.ThawSwapBuffers>, 'EnableHighDPI': <function OffScreenCanvasTarget.EnableHighDPI>, 'draw': <function OffScreenCanvasTarget.draw>, 'getBitmap': <function OffScreenCanvasTarget.getBitmap>, 'saveToFile': <function OffScreenCanvasTarget.saveToFile>, '__dict__': <attribute '__dict__' of 'OffScreenCanvasTarget' objects>, '__weakref__': <attribute '__weakref__' of 'OffScreenCanvasTarget' objects>, '__annotations__': {}})¶
- __module__ = 'fsleyes.gl'¶
- __weakref__¶
list of weak references to the object (if defined)
- class fsleyes.gl.WXGLCanvasTarget[source]¶
Bases:
object
Base class for
wx.glcanvas.GLCanvas
objects.It is assumed that subclasses of this base class are also subclasses of
wx.glcanvas.GLCanvas
. Sub-classes must override the following methods:This method should perform any OpenGL data initialisation required for rendering.
This method should implement the OpenGL drawing logic - it must be implemented by subclasses.
And must also ensure that the
destroy()
method is called when the class is being destroyed.- static canToggleHighDPI()[source]¶
Return
True
if high-DPI scaling can be toggled,False
otherwise.Under GTK, high DPI support is not possible with wxPython < 4.0.7, as
wx.Window.GetContentScaleFactor
always returns 1. Under GTK and from wxPython 4.0.7 onwards, GL canvases are scaled automatically.Under macOS and wxpython < 4.1.0, high DPI must be explicitly requested for GL canvases via a Cocoa API call. This can be done via the
EnableHighDPI()
method.Under macOS and with wxpython >= 4.1.0, GL canvases are scaled automatically.
- static displayAttributes()[source]¶
Used within
__init__
methods ofWXGLCanvasTarget
sub-classes.Return a dict to be passed as keyword arguments to the
wx.glcanvas.GLCanvas.__init__
method, defining desired OpenGL display attributes (e.g. depth/stencil buffer sizes).The
GLCanvas
interface changed between wxWidgets 3.0.x and 3.1.x (roughly corresponding to wxPython 4.0.x and 4.1.x) - this method checks the wxPython version and returns a suitable set of arguments.In certain remote environments (e.g. x2go), this method may return an empty dictionary, as in some environments it does not seem to be possible to request display attributes.
- destroy()[source]¶
Must be called when this WXGLCanvasTarget is no longer in use. Clears the GL rendering context target.
- __onEraseBackground(ev)¶
Called on
wx.EVT_ERASE_BACKGROUND
events. Does nothing.
- _initGL()[source]¶
This method should perform any OpenGL data initialisation required for rendering. Must be implemented by subclasses.
- canvasToWorld(xpos, ypos)[source]¶
Convert X/Y pixel coordinates into a location in the display coordinate system. Must be provided by subclasses.
- worldToCanvas(pos)[source]¶
Convert a location in the display coordinate system into X/Y pixel coordinates. Must be provided by subclasses.
- _draw(*a)[source]¶
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
Refresh()
method instead.
- __realDraw(*a)¶
Called when the canvas needs to be refreshed.
This method calls
_initGL()
if it has not already been called. Otherwise, it calls the subclass_draw()
method.
- _setGLContext()[source]¶
Configures the GL context for drawing to this canvas.
This method should be called before any OpenGL operations related to this canvas take place (e.g. texture/data creation, drawing, etc).
- GetContentScaleFactor()[source]¶
Overrides
wx.Window.GetContentScaleFactor
.Calls the base class implementation, except where wxpython 3.0.2.0 is being used, as the method does not exist in that version. In this case, 1.0 is returned.
- FreezeDraw()[source]¶
Freezes updates to the canvas. See
ThawDraw()
.
- ThawDraw()[source]¶
Unfreezes canvas updates. See
FreezeDraw()
.
- __dict__ = mappingproxy({'__module__': 'fsleyes.gl', '__doc__': 'Base class for :class:`wx.glcanvas.GLCanvas` objects.\n\n It is assumed that subclasses of this base class are also subclasses of\n :class:`wx.glcanvas.GLCanvas`. Sub-classes must override the following\n methods:\n\n .. autosummary::\n :nosignatures:\n\n _initGL\n _draw\n\n And must also ensure that the :meth:`destroy` method is called when\n the class is being destroyed.\n ', 'canToggleHighDPI': <staticmethod(<function WXGLCanvasTarget.canToggleHighDPI>)>, 'displayAttributes': <staticmethod(<function WXGLCanvasTarget.displayAttributes>)>, '__init__': <function WXGLCanvasTarget.__init__>, 'destroy': <function WXGLCanvasTarget.destroy>, 'destroyed': <property object>, '_WXGLCanvasTarget__onEraseBackground': <function WXGLCanvasTarget.__onEraseBackground>, '_WXGLCanvasTarget__onPaint': <function WXGLCanvasTarget.__onPaint>, '_initGL': <function WXGLCanvasTarget._initGL>, 'getAnnotations': <function WXGLCanvasTarget.getAnnotations>, 'canvasToWorld': <function WXGLCanvasTarget.canvasToWorld>, 'worldToCanvas': <function WXGLCanvasTarget.worldToCanvas>, '_draw': <function WXGLCanvasTarget._draw>, '_WXGLCanvasTarget__realDraw': <function WXGLCanvasTarget.__realDraw>, '_setGLContext': <function WXGLCanvasTarget._setGLContext>, 'GetSize': <function WXGLCanvasTarget.GetSize>, 'GetContentScaleFactor': <function WXGLCanvasTarget.GetContentScaleFactor>, 'GetScale': <function WXGLCanvasTarget.GetScale>, 'GetScaledSize': <function WXGLCanvasTarget.GetScaledSize>, 'Refresh': <function WXGLCanvasTarget.Refresh>, 'FreezeDraw': <function WXGLCanvasTarget.FreezeDraw>, 'ThawDraw': <function WXGLCanvasTarget.ThawDraw>, 'FreezeSwapBuffers': <function WXGLCanvasTarget.FreezeSwapBuffers>, 'ThawSwapBuffers': <function WXGLCanvasTarget.ThawSwapBuffers>, 'SwapBuffers': <function WXGLCanvasTarget.SwapBuffers>, 'EnableHighDPI': <function WXGLCanvasTarget.EnableHighDPI>, 'getBitmap': <function WXGLCanvasTarget.getBitmap>, '__dict__': <attribute '__dict__' of 'WXGLCanvasTarget' objects>, '__weakref__': <attribute '__weakref__' of 'WXGLCanvasTarget' objects>, '__annotations__': {}})¶
- __module__ = 'fsleyes.gl'¶
- __weakref__¶
list of weak references to the object (if defined)
- FreezeSwapBuffers()[source]¶
Freezes canvas fron/back buffer swaps, but not canvas drawing. See
ThawSwapBuffers()
.
- ThawSwapBuffers()[source]¶
Unfreezes canvas fron/back buffer swaps. See
FreezeSwapBuffers()
.