Esempio n. 1
0
    def updateVertices(self, *a):
        """Called by :meth:`__init__`, and when certain display properties
        change. (Re-)generates the mesh vertices, indices and normals (if
        being displayed in 3D). They are stored as attributes called
        ``vertices``, ``indices``, and ``normals`` respectively.
        """

        overlay  = self.overlay
        vertices = overlay.vertices
        indices  = overlay.indices
        normals  = self.overlay.vnormals
        xform    = self.opts.getTransform('mesh', 'display')

        if not np.all(np.isclose(xform, np.eye(4))):
            vertices = affine.transform(vertices, xform)

            if self.threedee:
                nmat    = affine.invert(xform).T
                normals = affine.transform(normals, nmat, vector=True)

        self.vertices = np.asarray(vertices,          dtype=np.float32)
        self.indices  = np.asarray(indices.flatten(), dtype=np.uint32)

        self.vertices = dutils.makeWriteable(self.vertices)
        self.indices  = dutils.makeWriteable(self.indices)

        if self.threedee:
            self.normals = np.array(normals, dtype=np.float32)
Esempio n. 2
0
    def updateVertices(self, *a):
        """Called by :meth:`__init__`, and when certain display properties
        change. (Re-)generates the mesh vertices, indices and normals (if
        being displayed in 3D). They are stored as attributes called
        ``vertices``, ``indices``, and ``normals`` respectively.
        """

        overlay = self.overlay
        opts = self.opts
        threedee = self.threedee
        vertices = overlay.vertices
        indices = overlay.indices
        normals = self.overlay.vnormals
        vdata = opts.getVertexData('vertex')
        xform = opts.getTransform('mesh', 'display')

        if not np.all(np.isclose(xform, np.eye(4))):
            vertices = affine.transform(vertices, xform)

            if self.threedee:
                nmat = affine.invert(xform).T
                normals = affine.transform(normals, nmat, vector=True)

        self.origIndices = indices
        indices = np.asarray(indices.flatten(), dtype=np.uint32)

        # If flatShading is active, we cannot share
        # vertices between triangles, so we generate
        # a set of unique vertices for each triangle,
        # and then re-generate the triangle indices.
        # The original indices are saved above, as
        # they will be used by the getVertexData
        # method to duplicate the vertex data.
        if threedee and (vdata is not None) and opts.flatShading:
            self.vertices = vertices[indices].astype(np.float32)
            self.indices = np.arange(0, len(self.vertices), dtype=np.uint32)
            normals = normals[indices, :]
        else:
            self.vertices = np.asarray(vertices, dtype=np.float32)
            self.indices = indices

        self.vertices = dutils.makeWriteable(self.vertices)
        self.indices = dutils.makeWriteable(self.indices)

        if self.threedee:
            self.normals = np.array(normals, dtype=np.float32)
Esempio n. 3
0
def test_makeWriteable():
    robuf = bytes(b'\01\02\03\04')
    wbuf = bytearray(b'\01\02\03\04')

    roarr = np.ndarray((4, ), dtype=np.uint8, buffer=robuf)
    warr = np.ndarray((4, ), dtype=np.uint8, buffer=wbuf)

    warr.flags['WRITEABLE'] = False

    rocopy = dutils.makeWriteable(roarr)
    wcopy = dutils.makeWriteable(warr)

    assert rocopy.base is not roarr.base
    assert wcopy.base is warr.base

    rocopy[1] = 100
    wcopy[1] = 100
Esempio n. 4
0
    def doRefresh(self):
        """Overrides :meth:`.Texture.doRefresh`.

        (Re-)configures the OpenGL texture.
        """

        data = self.preparedData

        if data is None:
            return

        log.debug('Configuring 3D texture (id %s) for %s (data shape: %s)',
                  self.name, self.handle, self.shape)

        # First dimension for multi-
        # valued textures
        if self.nvals > 1: shape = data.shape[1:]
        else: shape = data.shape

        # The image data is flattened, with
        # fortran dimension ordering, so the
        # data, as stored on the GPU, has its
        # first dimension as the fastest
        # changing.
        data = np.array(data.ravel(order='F'), copy=False)

        # PyOpenGL needs the data array
        # to be writeable, as it uses
        # PyArray_ISCARRAY to check
        # for contiguousness. but if the
        # data has come from a nibabel
        # ArrayProxy, the writeable flag
        # will be set to False for some
        # reason.
        data = dutils.makeWriteable(data)

        interp = self.interp
        intFmt = self.internalFormat
        baseFmt = self.baseFormat
        ttype = self.textureType

        if interp is None:
            interp = gl.GL_NEAREST

        with self.bound():

            # Enable storage of tightly packed data of any size (i.e.
            # our texture shape does not have to be divisible by 4).
            gl.glPixelStorei(gl.GL_PACK_ALIGNMENT, 1)
            gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1)

            gl.glTexParameteri(gl.GL_TEXTURE_3D, gl.GL_TEXTURE_MAG_FILTER,
                               interp)
            gl.glTexParameteri(gl.GL_TEXTURE_3D, gl.GL_TEXTURE_MIN_FILTER,
                               interp)

            # Clamp texture borders to
            # the specified border value(s)
            if self.border is not None:
                gl.glTexParameteri(gl.GL_TEXTURE_3D, gl.GL_TEXTURE_WRAP_S,
                                   gl.GL_CLAMP_TO_BORDER)
                gl.glTexParameteri(gl.GL_TEXTURE_3D, gl.GL_TEXTURE_WRAP_T,
                                   gl.GL_CLAMP_TO_BORDER)
                gl.glTexParameteri(gl.GL_TEXTURE_3D, gl.GL_TEXTURE_WRAP_R,
                                   gl.GL_CLAMP_TO_BORDER)
                gl.glTexParameterfv(gl.GL_TEXTURE_3D,
                                    gl.GL_TEXTURE_BORDER_COLOR,
                                    np.asarray(self.border, dtype=np.float32))

            # Clamp texture borders to the edge
            # values - it is the responsibility
            # of the rendering logic to not draw
            # anything outside of the image space
            else:
                gl.glTexParameteri(gl.GL_TEXTURE_3D, gl.GL_TEXTURE_WRAP_S,
                                   gl.GL_CLAMP_TO_EDGE)
                gl.glTexParameteri(gl.GL_TEXTURE_3D, gl.GL_TEXTURE_WRAP_T,
                                   gl.GL_CLAMP_TO_EDGE)
                gl.glTexParameteri(gl.GL_TEXTURE_3D, gl.GL_TEXTURE_WRAP_R,
                                   gl.GL_CLAMP_TO_EDGE)

            # The macOS GL driver sometimes corrupts
            # the texture data if we don't generate
            # mipmaps
            gl.glTexParameteri(gl.GL_TEXTURE_3D, gl.GL_GENERATE_MIPMAP,
                               gl.GL_TRUE)

            # create the texture according to
            # the format determined by the
            # determineTextureType method.
            #
            # note: The ancient Chromium driver (still
            #       in use by VirtualBox) will improperly
            #       create 3D textures without two calls
            #       (to glTexImage3D and glTexSubImage3D).
            #       If I specify the texture size and set
            #       the data in a single call, it seems to
            #       expect that the data or texture
            #       dimensions always have even size - odd
            #       sized images will be displayed
            #       incorrectly.
            gl.glTexImage3D(gl.GL_TEXTURE_3D, 0, intFmt, shape[0], shape[1],
                            shape[2], 0, baseFmt, ttype, None)
            gl.glTexSubImage3D(gl.GL_TEXTURE_3D, 0, 0, 0, 0, shape[0],
                               shape[1], shape[2], baseFmt, ttype, data)
Esempio n. 5
0
    def doRefresh(self):
        """Overrides :meth:`.Texture.doRefresh`. Configures this ``Texture2D``.
        This includes setting up interpolation, and setting the texture size
        and data.
        """

        data = self.preparedData

        if   data is None:    width, height = self.shape
        elif self.nvals == 1: width, height = data.shape
        else:                 width, height = data.shape[1:]

        if data is not None:
            data = np.array(data.ravel('F'), copy=False)
            data = dutils.makeWriteable(data)

        interp = self.interp

        if interp is None:
            interp = gl.GL_NEAREST

        with self.bound():

            gl.glPixelStorei(gl.GL_PACK_ALIGNMENT,   1)
            gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1)

            gl.glTexParameteri(gl.GL_TEXTURE_2D,
                               gl.GL_TEXTURE_MAG_FILTER,
                               interp)
            gl.glTexParameteri(gl.GL_TEXTURE_2D,
                               gl.GL_TEXTURE_MIN_FILTER,
                               interp)

            if self.border is not None:
                gl.glTexParameteri(gl.GL_TEXTURE_2D,
                                   gl.GL_TEXTURE_WRAP_S,
                                   gl.GL_CLAMP_TO_BORDER)
                gl.glTexParameteri(gl.GL_TEXTURE_2D,
                                   gl.GL_TEXTURE_WRAP_T,
                                   gl.GL_CLAMP_TO_BORDER)
                gl.glTexParameterfv(gl.GL_TEXTURE_2D,
                                    gl.GL_TEXTURE_BORDER_COLOR,
                                    self.border)
            else:
                gl.glTexParameteri(gl.GL_TEXTURE_2D,
                                   gl.GL_TEXTURE_WRAP_S,
                                   gl.GL_CLAMP_TO_EDGE)
                gl.glTexParameteri(gl.GL_TEXTURE_2D,
                                   gl.GL_TEXTURE_WRAP_T,
                                   gl.GL_CLAMP_TO_EDGE)

            # If the width and height have not
            # changed, then we don't need to
            # re-define the texture. But we can
            # use glTexSubImage2D if we have
            # data to upload
            if width  == self.__width  and \
               height == self.__height and \
               data is not None:
                gl.glTexSubImage2D(gl.GL_TEXTURE_2D,
                                   0,
                                   0,
                                   0,
                                   width,
                                   height,
                                   self.baseFormat,
                                   self.textureType,
                                   data)

            # If the width and/or height have
            # changed, we need to re-define
            # the texture properties
            else:
                self.__width  = width
                self.__height = height
                gl.glTexImage2D(gl.GL_TEXTURE_2D,
                                0,
                                self.internalFormat,
                                width,
                                height,
                                0,
                                self.baseFormat,
                                self.textureType,
                                data)
Esempio n. 6
0
    def __vdataChanged(self, value, valid, ctx, name):
        """Called when the :attr:`vertexData` or :attr:`modulateData`
        properties changes. Attempts to load the data if possible. The data may
        subsequently be retrieved via the :meth:`getVertexData` method.
        """

        vdata = None
        vdataRange = None
        overlay = self.overlay
        vdfile = value

        if name == 'vertexData': key = 'vertex'
        elif name == 'modulateData': key = 'modulate'
        else: raise RuntimeError()

        try:
            if vdfile is not None:

                if vdfile not in overlay.vertexDataSets():
                    log.debug('Loading vertex data: {}'.format(vdfile))
                    vdata = overlay.loadVertexData(vdfile)
                else:
                    vdata = overlay.getVertexData(vdfile)

                vdataRange = np.nanmin(vdata), np.nanmax(vdata)

                if len(vdata.shape) == 1:
                    vdata = vdata.reshape(-1, 1)

                vdata = dutils.makeWriteable(vdata)

        except Exception as e:

            # TODO show a warning
            log.warning('Unable to load vertex data from {}: {}'.format(
                vdfile, e, exc_info=True))

            vdata = None
            vdataRange = None

        self.__vdata[key] = vdata
        self.__vdataRange[key] = vdataRange

        if key == 'vertex':
            if vdata is not None: npoints = vdata.shape[1]
            else: npoints = 1
            self.vertexDataIndex = 0
            self.setAttribute('vertexDataIndex', 'maxval', npoints - 1)

        # if modulate data has changed,
        # don't update display/clipping
        # ranges (unless modulateData is
        # None, meaning that it is using
        # vertexData)
        if key == 'vertex':
            drange = True
            mrange = self.modulateData is None
        # and vice versa
        else:
            drange = False
            mrange = True

        self.updateDataRange(drange, drange, mrange)