mirror of https://github.com/kivy/kivy.git
Make blit_buffer accept memoryviews and objects that implement the buffer interface in additon to bytes. Use new conversion function.
This commit is contained in:
parent
1565c28cc2
commit
801e1ee6ce
|
@ -42,15 +42,17 @@ Blitting custom data
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
You can create your own data and blit it to the texture using
|
You can create your own data and blit it to the texture using
|
||||||
:meth:`Texture.blit_data`::
|
:meth:`Texture.blit_buffer`.
|
||||||
|
|
||||||
|
For example, to blit immutable bytes data::
|
||||||
|
|
||||||
# create a 64x64 texture, defaults to rgb / ubyte
|
# create a 64x64 texture, defaults to rgb / ubyte
|
||||||
texture = Texture.create(size=(64, 64))
|
texture = Texture.create(size=(64, 64))
|
||||||
|
|
||||||
# create 64x64 rgb tab, and fill with value from 0 to 255
|
# create 64x64 rgb tab, and fill with values from 0 to 255
|
||||||
# we'll have a gradient from black to white
|
# we'll have a gradient from black to white
|
||||||
size = 64 * 64 * 3
|
size = 64 * 64 * 3
|
||||||
buf = [int(x * 255 / size) for x in xrange(size)]
|
buf = [int(x * 255 / size) for x in range(size)]
|
||||||
|
|
||||||
# then, convert the array to a ubyte string
|
# then, convert the array to a ubyte string
|
||||||
buf = b''.join(map(chr, buf))
|
buf = b''.join(map(chr, buf))
|
||||||
|
@ -63,6 +65,34 @@ You can create your own data and blit it to the texture using
|
||||||
with self.canvas:
|
with self.canvas:
|
||||||
Rectangle(texture=texture, pos=self.pos, size=(64, 64))
|
Rectangle(texture=texture, pos=self.pos, size=(64, 64))
|
||||||
|
|
||||||
|
Since 1.8.1, you can blit data stored in a instance that implements the python
|
||||||
|
buffer interface, or a memoryview thereof, such as numpy arrays, python
|
||||||
|
`array.array`, a `bytearray`, or a cython array. This is beneficial if you
|
||||||
|
expect to blit similar data, with perhaps a few changes in the data.
|
||||||
|
|
||||||
|
When using a bytes representation of the data, for every change you have to
|
||||||
|
regenerate the bytes instance, from perhaps a list, which is very inefficient.
|
||||||
|
When using a buffer object, you can simply edit parts of the original data.
|
||||||
|
Similarly, unless starting with a bytes object, converting to bytes requires a
|
||||||
|
full copy, however, when using a buffer instance, no memory is copied, except
|
||||||
|
to upload it to the GPU.
|
||||||
|
|
||||||
|
Continuing with the example above::
|
||||||
|
|
||||||
|
from array import array
|
||||||
|
|
||||||
|
size = 64 * 64 * 3
|
||||||
|
buf = [int(x * 255 / size) for x in range(size)]
|
||||||
|
# initialize the array with the buffer values
|
||||||
|
arr = array('B', buf)
|
||||||
|
# now blit the array
|
||||||
|
texture.blit_buffer(arr, colorfmt='rgb', bufferfmt='ubyte')
|
||||||
|
|
||||||
|
# now change some elements in the original array
|
||||||
|
arr[24] = arr[50] = 99
|
||||||
|
# blit again the buffer
|
||||||
|
texture.blit_buffer(arr, colorfmt='rgb', bufferfmt='ubyte')
|
||||||
|
|
||||||
|
|
||||||
BGR/BGRA support
|
BGR/BGRA support
|
||||||
----------------
|
----------------
|
||||||
|
@ -194,7 +224,6 @@ include "common.pxi"
|
||||||
include "opengl_utils_def.pxi"
|
include "opengl_utils_def.pxi"
|
||||||
include "img_tools.pxi"
|
include "img_tools.pxi"
|
||||||
|
|
||||||
from array import array
|
|
||||||
from kivy.weakmethod import WeakMethod
|
from kivy.weakmethod import WeakMethod
|
||||||
from kivy.graphics.context cimport get_context
|
from kivy.graphics.context cimport get_context
|
||||||
|
|
||||||
|
@ -802,8 +831,15 @@ cdef class Texture:
|
||||||
called in order to update the texture.
|
called in order to update the texture.
|
||||||
|
|
||||||
:Parameters:
|
:Parameters:
|
||||||
`pbuffer` : bytes
|
`pbuffer` : bytes, or a class that implements the buffer interface\
|
||||||
Image data.
|
(including memoryview).
|
||||||
|
A buffer containing the image data. It can be either a bytes
|
||||||
|
object or a instance of a class that implements the python
|
||||||
|
buffer interface, e.g. `array.array`, `bytearray`, numpy arrays
|
||||||
|
etc. If it's not a bytes object, the underlying buffer must
|
||||||
|
be contiguous, have only one dimension and must not be
|
||||||
|
readonly, even though the data is not modified, due to a cython
|
||||||
|
limitation. See module description for usage details.
|
||||||
`size` : tuple, defaults to texture size
|
`size` : tuple, defaults to texture size
|
||||||
Size of the image (width, height)
|
Size of the image (width, height)
|
||||||
`colorfmt` : str, defaults to 'rgb'
|
`colorfmt` : str, defaults to 'rgb'
|
||||||
|
@ -820,9 +856,12 @@ cdef class Texture:
|
||||||
Indicate if we need to regenerate the mipmap from level 0.
|
Indicate if we need to regenerate the mipmap from level 0.
|
||||||
|
|
||||||
.. versionadded:: 1.0.7
|
.. versionadded:: 1.0.7
|
||||||
|
|
||||||
added `mipmap_level` and `mipmap_generation`
|
added `mipmap_level` and `mipmap_generation`
|
||||||
|
|
||||||
|
.. versionchanged:: 1.8.1
|
||||||
|
`pbuffer` can now be any class instance that implements the python
|
||||||
|
buffer interface and / or memoryviews thereof.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
cdef GLuint target = self._target
|
cdef GLuint target = self._target
|
||||||
if colorfmt is None:
|
if colorfmt is None:
|
||||||
|
@ -839,20 +878,27 @@ cdef class Texture:
|
||||||
# time.
|
# time.
|
||||||
self.bind()
|
self.bind()
|
||||||
|
|
||||||
# need conversion ?
|
# need conversion, do check here because it seems to be faster ?
|
||||||
cdef bytes data
|
if not gl_has_texture_native_format(colorfmt):
|
||||||
data = pbuffer
|
pbuffer, colorfmt = convert_to_gl_format(pbuffer, colorfmt)
|
||||||
data, colorfmt = _convert_buffer(data, colorfmt)
|
cdef char [:] view
|
||||||
|
cdef char *cdata
|
||||||
|
cdef long datasize
|
||||||
|
if isinstance(pbuffer, bytes): # if it's bytes, just use memory
|
||||||
|
cdata = <bytes>pbuffer # explicit bytes
|
||||||
|
datasize = len(pbuffer)
|
||||||
|
else: # if it's a memoryview or buffer type, use start of memory
|
||||||
|
view = pbuffer
|
||||||
|
cdata = &view[0]
|
||||||
|
datasize = view.nbytes
|
||||||
|
|
||||||
# prepare nogil
|
# prepare nogil
|
||||||
cdef int iglfmt = _color_fmt_to_gl(self._icolorfmt)
|
cdef int iglfmt = _color_fmt_to_gl(self._icolorfmt)
|
||||||
cdef int glfmt = _color_fmt_to_gl(colorfmt)
|
cdef int glfmt = _color_fmt_to_gl(colorfmt)
|
||||||
cdef long datasize = len(pbuffer)
|
|
||||||
cdef int x = pos[0]
|
cdef int x = pos[0]
|
||||||
cdef int y = pos[1]
|
cdef int y = pos[1]
|
||||||
cdef int w = size[0]
|
cdef int w = size[0]
|
||||||
cdef int h = size[1]
|
cdef int h = size[1]
|
||||||
cdef char *cdata = <char *>data
|
|
||||||
cdef int glbufferfmt = bufferfmt
|
cdef int glbufferfmt = bufferfmt
|
||||||
cdef int is_allocated = self._is_allocated
|
cdef int is_allocated = self._is_allocated
|
||||||
cdef int is_compressed = _is_compressed_fmt(colorfmt)
|
cdef int is_compressed = _is_compressed_fmt(colorfmt)
|
||||||
|
|
3
setup.py
3
setup.py
|
@ -428,7 +428,8 @@ graphics_dependencies = {
|
||||||
'texture.pxd': ['c_opengl.pxd'],
|
'texture.pxd': ['c_opengl.pxd'],
|
||||||
'texture.pyx': [
|
'texture.pyx': [
|
||||||
'config.pxi', 'common.pxi', 'opengl_utils_def.pxi', 'context.pxd',
|
'config.pxi', 'common.pxi', 'opengl_utils_def.pxi', 'context.pxd',
|
||||||
'c_opengl.pxd', 'c_opengl_debug.pxd', 'opengl_utils.pxd'],
|
'c_opengl.pxd', 'c_opengl_debug.pxd', 'opengl_utils.pxd',
|
||||||
|
'img_tools.pxi'],
|
||||||
'vbo.pxd': ['buffer.pxd', 'c_opengl.pxd', 'vertex.pxd'],
|
'vbo.pxd': ['buffer.pxd', 'c_opengl.pxd', 'vertex.pxd'],
|
||||||
'vbo.pyx': [
|
'vbo.pyx': [
|
||||||
'config.pxi', 'common.pxi', 'c_opengl_debug.pxd', 'context.pxd',
|
'config.pxi', 'common.pxi', 'c_opengl_debug.pxd', 'context.pxd',
|
||||||
|
|
Loading…
Reference in New Issue