Ejemplo n.º 1
0
	def __setitem__(self, idxs, data):
		"""Set the contents of the buffer. Currently, only :py:obj:`Ellipsis` is valid as an index.

		:param idxs: The indices to set. A new buffer will be created if :py:obj:`Ellipsis` is
			passed.
		:param data: The new contents of the buffer. If a :py:class:`numpy.ndarray` is passed, it
			will be used to initialize the buffer. If a :py:class:`numpy.dtype`
			is passed, the buffer will not be initialized.
		:type data: :py:class:`numpy.dtype` or :py:class:`numpy.ndarray`

		.. warning::

		   |buffer-bind|
		"""
		if idxs is Ellipsis:
			if isinstance(data, dtype):
				dt = data
				data = None
			else:
				dt = ( data.dtype if product(data.shape) == 1
				       else dtype((data.dtype, data.shape)) )
			try:
				binding = next(iter(self.active_bindings))
			except StopIteration:
				raise RuntimeError("Buffer data can only be set if it is bound.")
			GL.glBufferData(binding, dt.itemsize, data, self.usage)
			self.dtype = dt
		else:
			raise NotImplementedError("TODO: Allow changing replacing buffer dtypes.")
Ejemplo n.º 2
0
	def stride(self):
		"""Return the stride of buffer rows (in machine units)."""
		try:
			count, *shape = self.dtype.shape
		except ValueError:
			return None
		return self.dtype.base.itemsize * product(shape)
Ejemplo n.º 3
0
	def flush(self):
		"""Ensures changes are visible to GL for rendering. This has two actions depending on how
		the buffer was mapped.

		If it was mapped with :py:obj:`GL.GL_MAP_FLUSH_EXPLICIT_BIT` the buffer is flushed using
		:py:func:`GL.glFlushMappedBufferRange`

		Otherwise, a memory barrier is issued. This requires ``ARB_shader_image_load_store``.

		.. warning::

		   |buffer-bind|
		"""

		# FIXME: FLUSH_EXPLICIT_BIT is for flushing sub-ranges (no auto-flush at unmap?), so flush minimal region instead of whole mapped region
		try:
			binding = next(iter(self.gl_buffer.active_bindings))
		except StopIteration:
			raise RuntimeError("Buffer mappings can only be flushed if the buffer is bound.")

		if self.access & GL.GL_MAP_FLUSH_EXPLICIT_BIT:
			length = self.dtype.itemsize * product(self.shape)
			GL.glFlushMappedBufferRange(binding, self.offset, length)
		else:
			GL.glMemoryBarrier(GL.GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT)
Ejemplo n.º 4
0
	def indices(self):
		'''The total number of vertex attribute indices taken up by the attribute.'''

		datatype = getattr(self.datatype, 'base', self.datatype)
		element_indices = getattr(datatype, 'columns', 1)
		array_shape = getattr(self.datatype, 'full_shape', (1,))
		return element_indices * product(array_shape)
Ejemplo n.º 5
0
	def __getitem__(self, idx):
		datatype = self.datatype[idx]

		array_elements = product(getattr(datatype, 'full_shape', (1,)))
		base_type = getattr(datatype, 'base', datatype)
		element_indices = getattr(base_type, 'columns', 1)

		location = self.location + idx * element_indices * array_elements
		return VAOAttribute(self.vao, location, datatype, self.normalized, self.divisor)
Ejemplo n.º 6
0
	def __getitem__(self, idx):
		var = super().__getitem__(idx)

		array_elements = product(getattr(var.datatype, 'full_shape', (1,)))
		base_type = getattr(var.datatype, 'base', var.datatype)
		element_indices = getattr(base_type, 'columns', 1)

		if self.shader_location is None:
			location = None
		else:
			location = self.shader_location + idx * element_indices * array_elements
		return VertexAttribute(var.name, var.datatype, location, self.normalized)
Ejemplo n.º 7
0
	def components(self):
		return product(self.dtype.shape)
Ejemplo n.º 8
0
	def __init__(self, parent, *idxs):
		self.parent = parent
		if parent.dtype.subdtype is None:
			# Parent is a record array
			# Only allow one field for consistency with numpy.
			if len(idxs) != 1:
				raise IndexError("Invalid index into record array.")
			idx = idxs[0]
			if idx in range(-len(parent.dtype), len(parent.dtype)):
				idx = idx % len(parent.dtype)
			else:
				try:
					idx = parent.dtype.names.index(idx)
				except ValueError:
					raise IndexError("No such field: {}".format(idx))
			offset = sum(parent.dtype[i].itemsize for i in range(idx))
			self.dtype = parent.dtype.base[idx]
		else:
			parent_base, parent_shape = parent.dtype.subdtype
			if all(isinstance(idx, slice) or isinstance(idx, int) for idx in idxs):
				# Indexing shape
				if len(idxs) > len(parent_shape):
					raise IndexError("Too many indices.")
				if not isContiguous(idxs, parent_shape):
					raise IndexError("Non-contiguous indexing is not permitted.")
				offset = flatOffset(idxs, parent_shape, base=parent_base.itemsize)
				if any(idx >= s for idx, s in zip(idxs, parent_shape)
				       if not isinstance(idx, slice)):
					raise IndexError("Index out of bounds.")
				idxs = chain(idxs, repeat(slice(None)))
				shape = (len(range(*idx.indices(s))) for idx, s in zip(idxs, parent_shape)
				         if isinstance(idx, slice))
				self.dtype = dtype((parent_base, tuple(shape)))
			else:
				# Indexing record fields
				# Multiple indices must be in a list for consistency with numpy
				if len(idxs) > 1:
					raise IndexError("Invalid indexes.")
				if isinstance(idxs[0], str):
					field_name = first_field = idxs[0]
					if field_name not in parent_base.names:
						raise IndexError("No such field: {}".format(field_name))
					if len(parent_base) > 1 and product(parent_shape) > 1:
						raise IndexError("Non-contiguous indexing is not permitted.")
					field = parent_base[field_name]
					self.dtype = dtype((field.base, parent_shape + field.shape))
				else:
					field_names = tuple(filter(lambda x: x in parent_base.names, idxs[0]))
					try:
						first_field = field_names[0]
					except IndexError:
						raise IndexError("No such fields: {}".format(', '.join(field_names)))
					if product(parent_shape) > 1:
						if field_names != parent_base.names:
							raise IndexError("Non-contiguous indexing is not permitted.")
					else:
						if not contains(field_names, parent_base.names):
							raise IndexError("Non-contiguous indexing is not permitted.")
					base_dtype = dtype([(name, parent_base[name]) for name in field_names])
					self.dtype = dtype((base_dtype, parent_shape))
				offset = parent_base.fields[first_field][1]
		self.offset = offset + getattr(parent, 'offset', 0)
		self.buffer = getattr(parent, 'buffer', parent)