115 lines
3.6 KiB
Cython
115 lines
3.6 KiB
Cython
from kivy.graphics.opengl_utils cimport (gl_has_texture_native_format,
|
|
gl_has_texture_conversion)
|
|
cimport cython
|
|
from cython cimport view as cyview
|
|
from cpython.array cimport array, clone
|
|
|
|
|
|
@cython.boundscheck(False)
|
|
@cython.wraparound(False)
|
|
cdef inline convert_to_gl_format(data, fmt, width, height):
|
|
''' Takes data as a bytes object or an instance that implements the python
|
|
buffer interface. If the data format is supported by opengl, the data
|
|
is returned unchanged. Otherwise, the data is converted to a supported
|
|
format, when possible, and returned as a python array object.
|
|
|
|
Note that conversion is currently only supported for bytes data.
|
|
'''
|
|
cdef array ret_array
|
|
cdef char *src_buffer
|
|
cdef char *dst_buffer
|
|
cdef char [::1] view
|
|
cdef int datasize
|
|
cdef str ret_format
|
|
cdef int i, k
|
|
cdef char c, c2
|
|
cdef int pitch, rowlen
|
|
cdef int pitchalign = 0
|
|
|
|
# if native support of this format is available, use it
|
|
if gl_has_texture_native_format(fmt):
|
|
return data, fmt
|
|
|
|
# no native support, can we at least convert it ?
|
|
if not gl_has_texture_conversion(fmt):
|
|
raise Exception('Unimplemented texture conversion for {}'.format(fmt))
|
|
|
|
# do appropriate conversion, since we accepted it
|
|
if isinstance(data, bytes):
|
|
datasize = <int>len(data)
|
|
ret_array = clone(array('b'), datasize, False)
|
|
src_buffer = <char *>data
|
|
else:
|
|
view = data
|
|
datasize = view.nbytes
|
|
ret_array = clone(array('b'), datasize, False)
|
|
src_buffer = &view[0]
|
|
dst_buffer = ret_array.data.as_chars
|
|
|
|
# BGR -> RGB
|
|
if fmt == 'bgr':
|
|
ret_format = 'rgb'
|
|
memcpy(dst_buffer, src_buffer, datasize)
|
|
|
|
i = 0
|
|
rowlen = width * 3
|
|
pitch = (rowlen + 3) & ~3
|
|
if rowlen * height < datasize:
|
|
# FIXME: warn/fail if pitch * height != datasize:
|
|
pitchalign = pitch - rowlen
|
|
rowlen -= 1 # to match 0-based k below
|
|
|
|
# note, this is the fastest copying method. copying element by element
|
|
# from a memoryview is slower then copying the whole buffer and then
|
|
# properly modifying the elements
|
|
with nogil:
|
|
while i < datasize:
|
|
c = dst_buffer[i]
|
|
k = i + 2
|
|
dst_buffer[i] = dst_buffer[k]
|
|
dst_buffer[k] = c
|
|
if pitchalign and k % rowlen == 0:
|
|
i += pitchalign
|
|
i += 3
|
|
|
|
# BGRA -> RGBA
|
|
elif fmt == 'bgra':
|
|
ret_format = 'rgba'
|
|
memcpy(dst_buffer, src_buffer, datasize)
|
|
with nogil:
|
|
for i in range(0, datasize, 4):
|
|
c = dst_buffer[i]
|
|
dst_buffer[i] = dst_buffer[i + 2]
|
|
dst_buffer[i + 2] = c
|
|
|
|
# ARGB -> RGBA
|
|
elif fmt == 'argb':
|
|
ret_format = 'rgba'
|
|
memcpy(dst_buffer, &src_buffer[1], datasize-1)
|
|
c2 = src_buffer[0]
|
|
with nogil:
|
|
for i in range(0, datasize, 4):
|
|
c = dst_buffer[i+3]
|
|
dst_buffer[i+3] = c2
|
|
c2 = c
|
|
|
|
# ABGR -> RGBA
|
|
elif fmt == 'abgr':
|
|
ret_format = 'rgba'
|
|
memcpy(dst_buffer, &src_buffer[1], datasize-1)
|
|
c2 = src_buffer[0]
|
|
with nogil:
|
|
for i in range(0, datasize, 4):
|
|
c = dst_buffer[i+3]
|
|
dst_buffer[i+3] = c2
|
|
c2 = c
|
|
|
|
c = dst_buffer[i]
|
|
dst_buffer[i] = dst_buffer[i + 2]
|
|
dst_buffer[i + 2] = c
|
|
|
|
else:
|
|
assert False, 'Non implemented texture conversion {}'.format(fmt)
|
|
|
|
return ret_array, ret_format
|