Skip to content
Snippets Groups Projects
Commit cf7240e8 authored by Paul McCarthy's avatar Paul McCarthy
Browse files

ImageRenderTexture replaced with GLObjectRenderTexture, and associated changes.

parent 6f6f5083
No related branches found
No related tags found
No related merge requests found
......@@ -14,6 +14,9 @@ OpenGL representation.
"""
import numpy as np
def createGLObject(image, display):
"""Create :class:`GLObject` instance for the given
:class:`~fsl.data.image.Image` instance.
......@@ -69,7 +72,7 @@ class GLObject(object):
self.__updateListeners[name] = listener
def removeUpdateListener(self, name, listener):
def removeUpdateListener(self, name):
"""Removes a listener previously registered via
:meth:`addUpdateListener`.
"""
......@@ -225,10 +228,20 @@ class GLImageObject(GLObject):
def getDataResolution(self, xax, yax):
image = self.image
display = self.display
res = display.resolution
if display.transform in ('id', 'pixdim'):
pixdim = np.array(image.pixdim[:3])
steps = [res, res, res] / pixdim
res = image.shape[:3] / steps
return np.array(res.round(), dtype=np.uint32)
if self.display.transform in ('id', 'pixdim'):
return self.image.shape[:3]
else:
lo, hi = self.display.getDisplayBounds()
minres = int(round(((hi - lo) / self.display.resolution).min()))
lo, hi = display.getDisplayBounds()
minres = int(round(((hi - lo) / res).min()))
return [minres] * 3
......@@ -258,6 +258,10 @@ class GLVolume(globject.GLImageObject):
fslgl.glvolume_funcs.updateShaderState(self)
self.onUpdate()
def update(*a):
self.onUpdate()
display.addListener('resolution', lName, update)
display.addListener('interpolation', lName, shaderUpdate)
display.addListener('softwareMode', lName, shaderCompile)
display.addListener('alpha', lName, colourUpdate)
......@@ -277,6 +281,7 @@ class GLVolume(globject.GLImageObject):
lName = self.name
display.removeListener('resolution', lName)
display.removeListener('interpolation', lName)
display.removeListener('softwareMode', lName)
display.removeListener('alpha', lName)
......
......@@ -461,8 +461,11 @@ def subsample(data, resolution, pixdim=None, volume=None):
if pixdim is None:
pixdim = (1.0, 1.0, 1.0)
if volume is None:
volume = slice(None, None, None)
xstep = np.round(resolution / pixdim[0])
ystep = np.round(resolution / pixdim[1])
ystep = np.round(resolution / pixdim[1])
zstep = np.round(resolution / pixdim[2])
if xstep < 1: xstep = 1
......@@ -472,23 +475,14 @@ def subsample(data, resolution, pixdim=None, volume=None):
xstart = np.floor(xstep / 2)
ystart = np.floor(ystep / 2)
zstart = np.floor(zstep / 2)
if volume is not None:
if len(data.shape) > 3: sample = data[xstart::xstep,
ystart::ystep,
zstart::zstep,
volume]
else: sample = data[xstart::xstep,
ystart::ystep,
zstart::zstep]
else:
if len(data.shape) > 3: sample = data[xstart::xstep,
ystart::ystep,
zstart::zstep,
:]
else: sample = data[xstart::xstep,
ystart::ystep,
zstart::zstep]
if len(data.shape) > 3: sample = data[xstart::xstep,
ystart::ystep,
zstart::zstep,
volume]
else: sample = data[xstart::xstep,
ystart::ystep,
zstart::zstep]
return sample, (xstart, ystart, zstart), (xstep, ystep, zstep)
......
......@@ -382,12 +382,10 @@ class SliceCanvas(props.HasProperties):
# by a RenderTexture object.
if self.renderMode == 'offscreen':
display = self.displayCtx.getDisplayProperties(image)
name = '{}_{}_{}'.format(image.name, self.xax, self.yax)
rt = textures.ImageRenderTexture(
name = '{}_{}_{}'.format(image.name, self.xax, self.yax)
rt = textures.GLObjectRenderTexture(
name,
image,
display,
globj,
self.xax,
self.yax)
......@@ -968,7 +966,7 @@ class SliceCanvas(props.HasProperties):
# those off-screen textures are all rendered on
# to the screen canvas.
if self.renderMode == 'offscreen':
textures.ImageRenderTexture.unbindAsRenderTarget()
textures.GLObjectRenderTexture.unbindAsRenderTarget()
self._setViewport()
self._drawOffscreenTextures()
......
......@@ -21,5 +21,5 @@ from imagetexture import ImageTexture
from colourmaptexture import ColourMapTexture
from selectiontexture import SelectionTexture
from rendertexture import RenderTexture
from rendertexture import ImageRenderTexture
from rendertexture import GLObjectRenderTexture
from rendertexturestack import RenderTextureStack
......@@ -11,8 +11,6 @@ import OpenGL.GL as gl
import OpenGL.raw.GL._types as gltypes
import OpenGL.GL.EXT.framebuffer_object as glfbo
import numpy as np
import texture
import fsl.fslview.gl.routines as glroutines
......@@ -101,41 +99,24 @@ class RenderTexture(texture.Texture2D):
self.unbindAsRenderTarget()
self.unbindTexture()
class ImageRenderTexture(RenderTexture):
"""A :class:`RenderTexture` for off-screen volumetric rendering of an
:class:`.Image` instance.
"""
class GLObjectRenderTexture(RenderTexture):
def __init__(self, name, image, display, xax, yax, maxResolution=512):
def __init__(self, name, globj, xax, yax, maxResolution=1024):
"""
"""
self.__image = image
self.__display = display
self.__globj = globj
self.__xax = xax
self.__yax = yax
self.__maxResolution = maxResolution
RenderTexture.__init__(self, name)
self.__addListeners()
self.__updateSize()
def __addListeners(self):
def onInterp(*a):
if self.__display.interpolation == 'none': interp = gl.GL_NEAREST
else: interp = gl.GL_LINEAR
self.setInterpolation(interp)
name = '{}_{}'.format(self.getTextureName(), id(self))
globj.addUpdateListener(name, self.__updateSize)
self.__display.addListener('imageType', name, self.__updateSize)
self.__display.addListener('resolution', name, self.__updateSize)
self.__display.addListener('interpolation', name, onInterp)
self.__display.addListener('transform', name, self.__updateSize)
self.__updateSize()
def setAxes(self, xax, yax):
......@@ -147,12 +128,8 @@ class ImageRenderTexture(RenderTexture):
def destroy(self):
name = '{}_{}'.format(self.getTextureName(), id(self))
self.__globj.removeUpdateListener(name)
RenderTexture.destroy(self)
self.__display.removeListener('imageType', name)
self.__display.removeListener('resolution', name)
self.__display.removeListener('interpolation', name)
self.__display.removeListener('transform', name)
def setSize(self, width, height):
......@@ -162,50 +139,15 @@ class ImageRenderTexture(RenderTexture):
def __updateSize(self, *a):
image = self.__image
display = self.__display
maxRes = self.__maxResolution
resolution = display.resolution / np.array(image.pixdim)
resolution = np.round(resolution)
keepAspectRatio = True
if resolution[0] < 1: resolution[0] = 1
if resolution[1] < 1: resolution[1] = 1
if resolution[2] < 1: resolution[2] = 1
# For some image types, the display resolution
# does not affect performance, and needs to be
# higher than the image resolution
if display.imageType == 'linevector':
keepAspectRatio = False
width = 16 * image.shape[self.__xax] / resolution[self.__xax]
height = 16 * image.shape[self.__yax] / resolution[self.__yax]
# If the display transformation is 'id' or
# 'pixdim', then the display coordinate system
# axes line up with the voxel coordinate system
# axes, so we can just match the voxel resolution
elif display.transform in ('id', 'pixdim'):
width = image.shape[self.__xax] / resolution[self.__xax]
height = image.shape[self.__yax] / resolution[self.__yax]
# However, if we're displaying in world coordinates,
# we cannot assume any correspondence between the
# voxel coordinate system and the display coordinate
# system. So we'll use a fixed size render texture
# instead.
elif display.transform == 'affine':
width = maxRes / resolution.min()
height = maxRes / resolution.min()
# Limit the width/height to an arbitrary maximum
if not keepAspectRatio:
if width > maxRes: width = maxRes
if height > maxRes: height = maxRes
elif width > maxRes or height > maxRes:
globj = self.__globj
maxRes = self.__maxResolution
resolution = globj.getDataResolution(self.__xax, self.__yax)
width = resolution[self.__xax]
height = resolution[self.__yax]
if width > maxRes or height > maxRes:
oldWidth, oldHeight = width, height
ratio = min(width, height) / max(width, height)
......@@ -216,11 +158,15 @@ class ImageRenderTexture(RenderTexture):
height = maxRes
width = height * ratio
log.debug('Limiting texture resolution to {}x{} '
'(for image resolution {}x{})'.format(
*map(int, (width, height, oldWidth, oldHeight))))
width = int(round(width))
height = int(round(height))
width = int(round(width))
height = int(round(height))
RenderTexture.setSize(self, width, height)
log.debug('Limiting texture resolution to {}x{} '
'(for {} resolution {}x{})'.format(
width,
height,
type(globj).__name__,
oldWidth,
oldHeight))
RenderTexture.setSize(self, width, height)
......@@ -169,6 +169,12 @@ class Texture2D(Texture):
print data.shape, data.dtype
data = data.ravel('F')
log.debug('Configuring {} ({}) with size {}x{}'.format(
type(self).__name__,
self.getTextureHandle(),
self.__width,
self.__height))
# If the width and height have not changed,
# then we don't need to re-define the texture.
if self.__width == self.__oldWidth and \
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment