# OpenGL imaging

This section assumes you are familiar with texture mapping in OpenGL (for example, chapter 9 of the OpenGL Programming Guide).

To create a texture from any AbstractImage, call get_texture:

    kitten = image.load('kitten.jpg')
    texture = kitten.get_texture()

Textures are automatically created and used by ImageData when blitted. It is useful to use textures directly when aiming for high performance or 3D applications.

The Texture class represents any texture object. The target attribute gives the texture target (for example, `GL_TEXTURE_2D`) and id the texture name. For example, to bind a texture:

    glBindTexture(texture.target, texture.id)

# Texture dimensions

Implementations of OpenGL prior to 2.0 require textures to have dimensions that are powers of two (i.e., 1, 2, 4, 8, 16, ...). Because of this restriction, pyglet will always create textures of these dimensions (there are several non-conformant post-2.0 implementations). This could have unexpected results for a user blitting a texture loaded from a file of non-standard dimensions. To remedy this, pyglet returns a TextureRegion of the larger texture corresponding to just the part of the texture covered by the original image.

A TextureRegion has an owner attribute that references the larger texture. The following session demonstrates this:

    >>> rgba = image.load('tests/image/rgba.png')
    >>> rgba
    <ImageData 235x257>         # The image is 235x257
    >>> rgba.get_texture()
    <TextureRegion 235x257>     # The returned texture is a region
    >>> rgba.get_texture().owner
    <Texture 256x512>           # The owning texture has power-2 dimensions
    >>>

A TextureRegion defines a tex_coords attribute that gives the texture coordinates to use for a quad mapping the whole image. tex_coords is a 4-tuple of 3-tuple of floats; i.e., each texture coordinate is given in 3 dimensions. The following code can be used to render a quad for a texture region:

    texture = kitten.get_texture()
    t = texture.tex_coords
    w, h = texture.width, texture.height
    array = (GLfloat * 32)(
         t[0][0], t[0][1], t[0][2], 1.,
         x,       y,       z,       1.,
         t[1][0], t[1][1], t[1][2], 1.,
         x + w,   y,       z,       1.,
         t[2][0], t[2][1], t[2][2], 1.,
         x + w,   y + h,   z,       1.,
         t[3][0], t[3][1], t[3][2], 1.,
         x,       y + h,   z,       1.)

    glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT)
    glInterleavedArrays(GL_T4F_V4F, 0, array)
    glDrawArrays(GL_QUADS, 0, 4)
    glPopClientAttrib()

The Texture.blit method does this.

Use the `Texture.create` method to create either a texture region from a larger power-2 sized texture, or a texture with the exact dimensions using the `GL_texture_rectangle_ARB` extension.

# Texture internal format

pyglet automatically selects an internal format for the texture based on the source image's format attribute. The following table describes how it is selected.

> Format | Internal format
> --- | ---
> Any format with 3 components | `GL_RGB`
> Any format with 2 components | `GL_LUMINANCE_ALPHA`
> `"A"` | `GL_ALPHA`
> `"L"` | `GL_LUMINANCE`
> `"I"` | `GL_INTENSITY`
> Any other format | `GL_RGBA`

Note that this table does not imply any mapping between format components and their OpenGL counterparts. For example, an image with format `"RG"` will use `GL_LUMINANCE_ALPHA` as its internal format; the luminance channel will be averaged from the red and green components, and the alpha channel will be empty (maximal).

Use the `Texture.create` class method to create a texture with a specific internal format.