| | """Image/texture implementation code |
| | |
| | This module provides the Pan-OpenGL operations required to support OpenGL |
| | image handling. Most of this code is simply boilerplate code that sets |
| | OpenGL parameters such that normal Pythonic assumptions about data-ordering |
| | are met to allow easier interaction with other projects (such as PIL or |
| | Numpy). |
| | |
| | Generally speaking, there are 3 pieces of information which control how |
| | an image is processed in the system: |
| | |
| | format -- this is the pixel format, such as GL_RGB/GL_RED/GL_ABGR_EXT |
| | dims -- tuple of dimensions for the image, (width,height,depth) order |
| | type -- the storage data-type for the image, normally GL_UNSIGNED_BYTE |
| | when working in Python, but all of the standard OpenGL types for |
| | images can be used if you happen to have your data in some exotic |
| | format. |
| | |
| | OpenGL.UNSIGNED_BYTE_IMAGES_AS_STRING -- if this global value is set, |
| | then read of unsigned byte images using glReadPixels and |
| | glGetTexImage produces a string instead of the default array format. |
| | |
| | Attributes of Note: |
| | |
| | COMPONENT_COUNTS -- used to lookup how many units of a |
| | given storage type are required to store a unit in a given format |
| | |
| | TYPE_TO_ARRAYTYPE -- maps Image storage types to their array data-type |
| | constants, i.e. maps GL_UNSIGNED_SHORT_4_4_4_4 to GL_UNSIGNED_SHORT |
| | so that we can use the standard array types for manipulating |
| | image arrays. |
| | |
| | RANK_PACKINGS -- commands required to set up default array-transfer |
| | operations for an array of the specified rank. |
| | |
| | New image formats and types will need to be registered here to be supported, |
| | this means that extension modules which add image types/formats need to alter |
| | the tables described above! |
| | |
| | XXX Should be an API to handle that instead of direct modification. |
| | |
| | """ |
| | from OpenGL.raw.GL.VERSION import GL_1_1 as _simple |
| | from OpenGL import arrays |
| | from OpenGL import _configflags |
| | import ctypes |
| |
|
| | def SetupPixelRead( format, dims, type): |
| | """Setup transfer mode for a read into a numpy array return the array |
| | |
| | Calls setupDefaultTransferMode, sets rankPacking and then |
| | returns a createTargetArray for the parameters. |
| | """ |
| | setupDefaultTransferMode() |
| | |
| | |
| | |
| | rankPacking( len(dims)+1 ) |
| | return createTargetArray( format, dims, type ) |
| |
|
| | def setupDefaultTransferMode( ): |
| | """Set pixel transfer mode to assumed internal structure of arrays |
| | |
| | Basically OpenGL-ctypes (and PyOpenGL) assume that your image data is in |
| | non-byte-swapped order, with big-endian ordering of bytes (though that |
| | seldom matters in image data). These assumptions are normally correct |
| | when dealing with Python libraries which expose byte-arrays. |
| | """ |
| | _simple.glPixelStorei(_simple.GL_PACK_SWAP_BYTES, 0) |
| | _simple.glPixelStorei(_simple.GL_PACK_LSB_FIRST, 0) |
| | def rankPacking( rank ): |
| | """Set the pixel-transfer modes for a given image "rank" (# of dims) |
| | |
| | Uses RANK_PACKINGS table to issue calls to glPixelStorei |
| | """ |
| | for func,which,arg in RANK_PACKINGS[rank]: |
| | try: |
| | func(which,arg) |
| | except Exception as err: |
| | |
| | pass |
| |
|
| | def createTargetArray( format, dims, type ): |
| | """Create storage array for given parameters |
| | |
| | If storage type requires > 1 unit per format pixel, then dims will be |
| | extended by 1, so in the common case of RGB and GL_UNSIGNED_BYTE you |
| | will wind up with an array of dims + (3,) dimensions. See |
| | COMPONENT_COUNTS for table which controls which formats produce |
| | larger dimensions. The secondary table TIGHT_PACK_FORMATS overrides |
| | this case, so that image formats registered as TIGHT_PACK_FORMATS |
| | only ever return a dims-shaped value. TIGHT_PACK_FORMATS will raise |
| | ValueErrors if they are used with a format that does not have the same |
| | number of components as they define. |
| | |
| | Note that the base storage type must provide a zeros method. The zeros |
| | method relies on their being a registered default array-implementation for |
| | the storage type. The default installation of OpenGL-ctypes will use |
| | Numpy arrays for returning the result. |
| | """ |
| | |
| | |
| | componentCount = formatToComponentCount( format ) |
| | if componentCount > 1: |
| | if type not in TIGHT_PACK_FORMATS: |
| | |
| | |
| | dims += (componentCount, ) |
| | elif TIGHT_PACK_FORMATS[ type ] < componentCount: |
| | raise ValueError( |
| | """Image type: %s supports %s components, but format %s requires %s components"""%( |
| | type, |
| | TIGHT_PACK_FORMATS[ type ], |
| | format, |
| | componentCount, |
| | ) |
| | ) |
| | arrayType = arrays.GL_CONSTANT_TO_ARRAY_TYPE[ TYPE_TO_ARRAYTYPE.get(type,type) ] |
| | return arrayType.zeros( dims ) |
| |
|
| | def formatToComponentCount( format ): |
| | """Given an OpenGL image format specification, get components/pixel""" |
| | size = COMPONENT_COUNTS.get( format ) |
| | if size is None: |
| | raise ValueError( """Unrecognised image format: %r"""%(format,)) |
| | return size |
| |
|
| | def returnFormat( data, type ): |
| | """Perform compatibility conversion for PyOpenGL 2.x image-as string results |
| | |
| | Uses OpenGL.UNSIGNED_BYTE_IMAGES_AS_STRING to control whether to perform the |
| | conversions. |
| | """ |
| | if _configflags.UNSIGNED_BYTE_IMAGES_AS_STRING: |
| | if type == _simple.GL_UNSIGNED_BYTE: |
| | if hasattr( data, 'tostring' ): |
| | return data.tostring() |
| | elif hasattr( data, 'raw' ): |
| | return data.raw |
| | elif hasattr( data, '_type_' ): |
| | s = ctypes.string_at( ctypes.cast( data, ctypes.c_voidp ), ctypes.sizeof( data )) |
| | result = s[:] |
| | return s |
| | return data |
| |
|
| |
|
| | COMPONENT_COUNTS = { |
| | |
| | } |
| | TYPE_TO_BITS = { |
| | |
| | } |
| | TYPE_TO_ARRAYTYPE = { |
| | |
| | } |
| | TIGHT_PACK_FORMATS = { |
| | } |
| | RANK_PACKINGS = { |
| | |
| | } |
| |
|