summaryrefslogtreecommitdiff
path: root/silx/gui/_glutils/Texture.py
diff options
context:
space:
mode:
authorPicca Frédéric-Emmanuel <picca@debian.org>2022-02-02 14:19:58 +0100
committerPicca Frédéric-Emmanuel <picca@debian.org>2022-02-02 14:19:58 +0100
commit4e774db12d5ebe7a20eded6dd434a289e27999e5 (patch)
treea9822974ba45196f1e3740995ab157d6eb214a04 /silx/gui/_glutils/Texture.py
parentd3194b1a9c4404ba93afac43d97172ab24c57098 (diff)
New upstream version 1.0.0+dfsg
Diffstat (limited to 'silx/gui/_glutils/Texture.py')
-rw-r--r--silx/gui/_glutils/Texture.py352
1 files changed, 0 insertions, 352 deletions
diff --git a/silx/gui/_glutils/Texture.py b/silx/gui/_glutils/Texture.py
deleted file mode 100644
index c72135a..0000000
--- a/silx/gui/_glutils/Texture.py
+++ /dev/null
@@ -1,352 +0,0 @@
-# coding: utf-8
-# /*##########################################################################
-#
-# Copyright (c) 2014-2020 European Synchrotron Radiation Facility
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-# ###########################################################################*/
-"""This module provides a class wrapping OpenGL 2D and 3D texture."""
-
-__authors__ = ["T. Vincent"]
-__license__ = "MIT"
-__date__ = "04/10/2016"
-
-
-try:
- from collections import abc
-except ImportError: # Python2 support
- import collections as abc
-
-from ctypes import c_void_p
-import logging
-
-import numpy
-
-from . import gl, utils
-
-
-_logger = logging.getLogger(__name__)
-
-
-class Texture(object):
- """Base class to wrap OpenGL 2D and 3D texture
-
- :param internalFormat: OpenGL texture internal format
- :param data: The data to copy to the texture or None for an empty texture
- :type data: numpy.ndarray or None
- :param format_: Input data format if different from internalFormat
- :param shape: If data is None, shape of the texture
- (height, width) or (depth, height, width)
- :type shape: List[int]
- :param int texUnit: The texture unit to use
- :param minFilter: OpenGL texture minimization filter (default: GL_NEAREST)
- :param magFilter: OpenGL texture magnification filter (default: GL_LINEAR)
- :param wrap: Texture wrap mode for dimensions: (t, s) or (r, t, s)
- If a single value is provided, it used for all dimensions.
- :type wrap: OpenGL wrap mode or 2 or 3-tuple of wrap mode
- """
-
- def __init__(self, internalFormat, data=None, format_=None,
- shape=None, texUnit=0,
- minFilter=None, magFilter=None, wrap=None):
-
- self._internalFormat = internalFormat
- if format_ is None:
- format_ = self.internalFormat
-
- if data is None:
- assert shape is not None
- else:
- assert shape is None
- data = numpy.array(data, copy=False, order='C')
- if format_ != gl.GL_RED:
- shape = data.shape[:-1] # Last dimension is channels
- else:
- shape = data.shape
-
- self._deferredUpdates = [(format_, data, None)]
-
- assert len(shape) in (2, 3)
- self._shape = tuple(shape)
- self._ndim = len(shape)
-
- self.texUnit = texUnit
-
- self._texParameterUpdates = {} # Store texture params to update
-
- self._minFilter = minFilter if minFilter is not None else gl.GL_NEAREST
- self._texParameterUpdates[gl.GL_TEXTURE_MIN_FILTER] = self._minFilter
-
- self._magFilter = magFilter if magFilter is not None else gl.GL_LINEAR
- self._texParameterUpdates[gl.GL_TEXTURE_MAG_FILTER] = self._magFilter
-
- self._name = None # Store texture ID
-
- if wrap is not None:
- if not isinstance(wrap, abc.Iterable):
- wrap = [wrap] * self.ndim
-
- assert len(wrap) == self.ndim
-
- self._texParameterUpdates[gl.GL_TEXTURE_WRAP_S] = wrap[-1]
- self._texParameterUpdates[gl.GL_TEXTURE_WRAP_T] = wrap[-2]
- if self.ndim == 3:
- self._texParameterUpdates[gl.GL_TEXTURE_WRAP_R] = wrap[0]
-
- @property
- def target(self):
- """OpenGL target type of this texture"""
- return gl.GL_TEXTURE_2D if self.ndim == 2 else gl.GL_TEXTURE_3D
-
- @property
- def ndim(self):
- """The number of dimensions: 2 or 3"""
- return self._ndim
-
- @property
- def internalFormat(self):
- """Texture internal format"""
- return self._internalFormat
-
- @property
- def shape(self):
- """Shape of the texture: (height, width) or (depth, height, width)"""
- return self._shape
-
- @property
- def name(self):
- """OpenGL texture name.
-
- It is None if not initialized or already discarded.
- """
- return self._name
-
- @property
- def minFilter(self):
- """Minifying function parameter (GL_TEXTURE_MIN_FILTER)"""
- return self._minFilter
-
- @minFilter.setter
- def minFilter(self, minFilter):
- if minFilter != self.minFilter:
- self._minFilter = minFilter
- self._texParameterUpdates[gl.GL_TEXTURE_MIN_FILTER] = minFilter
-
- @property
- def magFilter(self):
- """Magnification function parameter (GL_TEXTURE_MAG_FILTER)"""
- return self._magFilter
-
- @magFilter.setter
- def magFilter(self, magFilter):
- if magFilter != self.magFilter:
- self._magFilter = magFilter
- self._texParameterUpdates[gl.GL_TEXTURE_MAG_FILTER] = magFilter
-
- def _isPrepareRequired(self) -> bool:
- """Returns True if OpenGL texture needs to be updated.
-
- :rtype: bool
- """
- return (self._name is None or
- self._texParameterUpdates or
- self._deferredUpdates)
-
- def _prepareAndBind(self, texUnit=None):
- """Synchronizes the OpenGL texture"""
- if self._name is None:
- self._name = gl.glGenTextures(1)
-
- self._bind(texUnit)
-
- # Synchronizes texture parameters
- for pname, param in self._texParameterUpdates.items():
- gl.glTexParameter(self.target, pname, param)
- self._texParameterUpdates = {}
-
- # Copy data to texture
- for format_, data, offset in self._deferredUpdates:
- gl.glPixelStorei(gl.GL_UNPACK_ALIGNMENT, 1)
-
- # This are the defaults, useless to set if not modified
- # gl.glPixelStorei(gl.GL_UNPACK_ROW_LENGTH, 0)
- # gl.glPixelStorei(gl.GL_UNPACK_SKIP_PIXELS, 0)
- # gl.glPixelStorei(gl.GL_UNPACK_SKIP_ROWS, 0)
- # gl.glPixelStorei(gl.GL_UNPACK_IMAGE_HEIGHT, 0)
- # gl.glPixelStorei(gl.GL_UNPACK_SKIP_IMAGES, 0)
-
- if data is None:
- data = c_void_p(0)
- type_ = gl.GL_UNSIGNED_BYTE
- else:
- type_ = utils.numpyToGLType(data.dtype)
-
- if offset is None: # Initialize texture
- if self.ndim == 2:
- _logger.debug(
- 'Creating 2D texture shape: (%d, %d),'
- ' internal format: %s, format: %s, type: %s',
- self.shape[0], self.shape[1],
- str(self.internalFormat), str(format_), str(type_))
-
- gl.glTexImage2D(
- gl.GL_TEXTURE_2D,
- 0,
- self.internalFormat,
- self.shape[1],
- self.shape[0],
- 0,
- format_,
- type_,
- data)
-
- else:
- _logger.debug(
- 'Creating 3D texture shape: (%d, %d, %d),'
- ' internal format: %s, format: %s, type: %s',
- self.shape[0], self.shape[1], self.shape[2],
- str(self.internalFormat), str(format_), str(type_))
-
- gl.glTexImage3D(
- gl.GL_TEXTURE_3D,
- 0,
- self.internalFormat,
- self.shape[2],
- self.shape[1],
- self.shape[0],
- 0,
- format_,
- type_,
- data)
-
- else: # Update already existing texture
- if self.ndim == 2:
- gl.glTexSubImage2D(gl.GL_TEXTURE_2D,
- 0,
- offset[1],
- offset[0],
- data.shape[1],
- data.shape[0],
- format_,
- type_,
- data)
-
- else:
- gl.glTexSubImage3D(gl.GL_TEXTURE_3D,
- 0,
- offset[2],
- offset[1],
- offset[0],
- data.shape[2],
- data.shape[1],
- data.shape[0],
- format_,
- type_,
- data)
-
- self._deferredUpdates = []
-
- def _bind(self, texUnit=None):
- """Bind the texture to a texture unit.
-
- :param int texUnit: The texture unit to use
- """
- if texUnit is None:
- texUnit = self.texUnit
- gl.glActiveTexture(gl.GL_TEXTURE0 + texUnit)
- gl.glBindTexture(self.target, self.name)
-
- def _unbind(self, texUnit=None):
- """Reset texture binding to a texture unit.
-
- :param int texUnit: The texture unit to use
- """
- if texUnit is None:
- texUnit = self.texUnit
- gl.glActiveTexture(gl.GL_TEXTURE0 + texUnit)
- gl.glBindTexture(self.target, 0)
-
- def prepare(self):
- """Synchronizes the OpenGL texture.
-
- This method must be called with a current OpenGL context.
- """
- if self._isPrepareRequired():
- self._prepareAndBind()
- self._unbind()
-
- def bind(self, texUnit=None):
- """Bind the texture to a texture unit.
-
- The OpenGL texture is updated if needed.
-
- This method must be called with a current OpenGL context.
-
- :param int texUnit: The texture unit to use
- """
- if self._isPrepareRequired():
- self._prepareAndBind(texUnit)
- else:
- self._bind(texUnit)
-
- def discard(self):
- """Delete associated OpenGL texture.
-
- This method must be called with a current OpenGL context.
- """
- if self._name is not None:
- gl.glDeleteTextures(self._name)
- self._name = None
- else:
- _logger.warning("Texture not initialized or already discarded")
-
- # with statement
-
- def __enter__(self):
- self.bind()
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- self._unbind()
-
- def update(self, format_, data, offset=(0, 0, 0), copy=True):
- """Update the content of the texture.
-
- Texture is not resized, so data must fit into texture with the
- given offset.
-
- This update is performed lazily during next call to
- :meth:`prepare` or :meth:`bind`.
- Data MUST not be changed until then.
-
- :param format_: The OpenGL format of the data
- :param data: The data to use to update the texture
- :param List[int] offset: Offset in the texture where to copy the data
- :param bool copy:
- True (default) to copy data, False to use as is (do not modify)
- """
- data = numpy.array(data, copy=copy, order='C')
- offset = tuple(offset)
-
- assert data.ndim == self.ndim
- assert len(offset) >= self.ndim
- for i in range(self.ndim):
- assert offset[i] + data.shape[i] <= self.shape[i]
-
- self._deferredUpdates.append((format_, data, offset))