7. Textures

In addition to cube map textures and 2D textures that are pasted onto polygon models, the 3DS system can handle shadow textures used for shadows, gas textures used for rendering gases, and lookup tables used by the reserved fragment shader (these lookup tables cannot be used as textures).

This chapter explains the necessary procedures for using these textures and describes how the native PICA format differs from the OpenGL specifications.

7.1. Creating Texture Objects

Use the glGenTextures function to create texture objects to bind as textures.

Code 7-1. Definition of the glGenTextures Function
void glGenTextures(GLsizei n, GLuint* textures); 

7.2. Specifying Texture Objects

Use the glBindTexture function to specify a texture object to bind as a texture. After this function is called, the various texture processes are performed using the specified texture object. Texture images loaded for (and the results of processing performed on) a texture object are preserved until the texture object is deleted. Consequently, you can switch texture objects to change textures without reloading texture images.

Code 7-2. Definition of the glBindTexture Function
void glBindTexture(GLenum target, GLuint texture); 

Specify the texture type for target, and the texture object to bind for texture. A GL_INVALID_ENUM error is generated if you set target to a value that is not in the following table.

Table 7-1. Texture Types

target Value

Type of Texture

GL_TEXTURE_2D

2D textures, shadow textures, and gas textures.

GL_TEXTURE_CUBE_MAP_POSITIVE_X

Cube map textures.

GL_TEXTURE_CUBE_MAP_NEGATIVE_X

Cube map textures.

GL_TEXTURE_CUBE_MAP_POSITIVE_Y

Cube map textures.

GL_TEXTURE_CUBE_MAP_NEGATIVE_Y

Cube map textures.

GL_TEXTURE_CUBE_MAP_POSITIVE_Z

Cube map textures.

GL_TEXTURE_CUBE_MAP_NEGATIVE_Z

Cube map textures.

GL_LUT_TEXTUREi_DMP (where i is a value between 0 and 31)

Lookup tables (used by the reserved fragment shader).

GL_TEXTURE_COLLECTION_DMP

Texture collections (see 7.9. Texture Collections).

7.3. Loading Texture Images

In addition to normal texture images (2D textures), the glTexImage2D function loads the following special textures: cube map textures, shadow textures, and gas textures. Partial texture loading with the glTexSubImage2D function is not supported.

Code 7-3. Definition of the glTexImage2D Function
void glTexImage2D(GLenum target, GLint level, GLenum internalformat, 
                  GLsizei width, GLsizei height, GLint border, GLenum format, 
                  GLenum type, const void* pixels); 

Set target to one of the following values.

Table 7-2 target Values in glTexImage2D

target Value

Texture Usage

GL_TEXTURE_2D

2D textures, shadow textures, and gas textures.

GL_TEXTURE_CUBE_MAP_POSITIVE_X

Cube map +X plane textures.

GL_TEXTURE_CUBE_MAP_NEGATIVE_X

Cube map −X plane textures.

GL_TEXTURE_CUBE_MAP_POSITIVE_Y

Cube map +Y plane textures.

GL_TEXTURE_CUBE_MAP_NEGATIVE_Y

Cube map −Y plane textures.

GL_TEXTURE_CUBE_MAP_POSITIVE_Z

Cube map +Z plane textures.

GL_TEXTURE_CUBE_MAP_NEGATIVE_Z

Cube map −Z plane textures.

Combinations of format and type specify the format of texture images stored in the region given by pixels. The following table lists the formats that can be handled by the 3DS system. The Bytes column indicates the number of bytes per texel. An asterisk (*) that follows the byte count indicates a native PICA format, which has a different byte order than the standard OpenGL format. For more information about the native PICA format, see 7.10. Native PICA Format.

Table 7-3. Texture Image Formats Specified by format and type

format

type

Format

Bytes

GL_RGBA

GL_UNSIGNED_SHORT_4_4_4_4

RGBA4

2

GL_RGBA

GL_UNSIGNED_SHORT_5_5_5_1

RGBA5551

2

GL_RGBA

GL_UNSIGNED_BYTE

RGBA8

4

GL_RGB

GL_UNSIGNED_SHORT_5_6_5

RGB565

2

GL_RGB

GL_UNSIGNED_BYTE

RGB8

3

GL_ALPHA

GL_UNSIGNED_BYTE

A8

1

GL_ALPHA

GL_UNSIGNED_4BITS_DMP

A4

0.5

GL_LUMINANCE

GL_UNSIGNED_BYTE

L8

1

GL_LUMINANCE

GL_UNSIGNED_4BITS_DMP

L4

0.5

GL_LUMINANCE_ALPHA

GL_UNSIGNED_BYTE

LA8

2

GL_LUMINANCE_ALPHA

GL_UNSIGNED_BYTE_4_4_DMP

LA4

1

GL_SHADOW_DMP

GL_UNSIGNED_INT

-

4

GL_GAS_DMP

GL_UNSIGNED_SHORT

-

4

GL_HILO8_DMP

GL_UNSIGNED_BYTE

-

2

GL_RGBA_NATIVE_DMP

GL_UNSIGNED_SHORT_4_4_4_4

RGBA4

2

GL_RGBA_NATIVE_DMP

GL_UNSIGNED_SHORT_5_5_5_1

RGBA5551

2

GL_RGBA_NATIVE_DMP

GL_UNSIGNED_BYTE

RGBA8

4*

GL_RGB_NATIVE_DMP

GL_UNSIGNED_SHORT_5_6_5

RGB565

2

GL_RGB_NATIVE_DMP

GL_UNSIGNED_BYTE

RGB8

3*

GL_ALPHA_NATIVE_DMP

GL_UNSIGNED_BYTE

A8

1

GL_ALPHA_NATIVE_DMP

GL_UNSIGNED_4BITS_DMP

A4

0.5

GL_LUMINANCE_NATIVE_DMP

GL_UNSIGNED_BYTE

L8

1

GL_LUMINANCE_NATIVE_DMP

GL_UNSIGNED_4BITS_DMP

L4

0.5

GL_LUMINANCE_ALPHA_NATIVE_DMP

GL_UNSIGNED_BYTE

LA8

2*

GL_LUMINANCE_ALPHA_NATIVE_DMP

GL_UNSIGNED_BYTE_4_4_DMP

LA4

1

GL_SHADOW_NATIVE_DMP

GL_UNSIGNED_INT

-

4*

GL_GAS_NATIVE_DMP

GL_UNSIGNED_SHORT

-

4*

GL_HILO8_DMP_NATIVE_DMP

GL_UNSIGNED_BYTE

-

2*

R, G, and B represent colors (red, green, and blue, respectively).
A represents the alpha value.
L represents the luminance value.

As set forth in the OpenGL ES 1.1 specifications, a value of 1 is output for the alpha component if the texture combiner references a texture without an alpha component. This is also true for compressed textures.

You can only set format to GL_RGB or GL_RGB_NATIVE_DMP and type to GL_UNSIGNED_BYTE when target is GL_TEXTURE_2D. When format is GL_*_NATIVE_DMP, pixels must specify data in the native PICA format. When GL_GAS_DMP is specified, pixels must be 0 (NULL).

For width and height, specify the width and height of the texture image. Both numbers must be powers of 2, from 8 through 1024.

If target is GL_TEXTURE_CUBE_MAP_*, width and height must have the same value. Every surface must have the same settings, except for pixels (and target).

If pixels is set to 0 (NULL), a region is allocated but image data is not loaded.

For internalformat specify the basic internal format. A GL_INVALID_OPERATION error is generated when internalformat and format are not the same value. The following table shows how an image's RGBA components correspond to the components in the basic internal format.

Table 7-4. Correspondence Between RGBA Formats and Basic Internal Formats

Basic Internal Format

RGBA

Internal Format

GL_ALPHA

A

A

GL_LUMINANCE

R

L

GL_LUMINANCE_ALPHA

R, A

L, A

GL_RGB

R, G, B

R, G, B

GL_RGBA

R, G, B, A

R, G, B, A

GL_HILO8_DMP

R, G

Nx, Ny

The GL_HILO8_DMP format outputs 0.0 for the B component and 1.0 for the A component.

Unlike in the OpenGL specifications, level specifies the number of mipmap levels as a negative value. For example, -2 indicates two mipmap levels, and both -1 and 0 indicate one mipmap level. You cannot separately specify which textures to use for each mipmap level. Instead, set pixels to a series of textures, starting with the texture to use as the largest mipmap and ending with the texture to use as the smallest mipmap.

You must set border to 0.

7.3.1. Formats With 4-Bit Components

Texture formats with a type of GL_UNSIGNED_BYTE_4_4_DMP or GL_UNSIGNED_4BITS_DMP use 4 bits for a single component, and require a special data ordering.

In a format with a type of GL_UNSIGNED_BYTE_4_4_DMP, two components are stored in a single byte. You can combine this with a format of GL_LUMINANCE_ALPHA or GL_LUMINANCE_ALPHA_NATIVE_DMP. The luminance is stored in the most-significant 4 bits and the alpha component is stored in the least-significant 4 bits.

In a format with a type of GL_UNSIGNED_4BITS_DMP, two texels are stored in a single byte. You can combine this with a format of GL_LUMINANCE, GL_LUMINANCE_NATIVE_DMP, GL_ALPHA, or GL_ALPHA_NATIVE_DMP. Viewed as a row of texels, the first component is stored in the least-significant 4 bits, the second component is stored in the most-significant 4 bits, and so on.

Warning:

If you enable a texture format with a type of GL_UNSIGNED_4BITS_DMP (a 4-bit format) at the same time as another texture format (a non-4-bit format that includes ETC1 compressed textures) and then use them as a multitexture, there are restrictions on the placements of the texture.

If you are placing 4-bit textures in VRAM, you must place 4-bit textures and non-4-bit textures in separate memory. In such cases, VRAM-A and VRAM-B are treated as separate memory. Behavior is undefined when textures having different bit formats are placed in the same memory.

There is no restriction on texture arrays when 4-bit textures are placed in main memory.

Figure 7-1. Bit Layout of Texture Formats That Comprise 4-Bit Components

Luminance[n] Alpha[n] +0 Byte Luminance[n+1] Alpha[n+1] +1 Byte Luminance[n+3] Alpha[n+2] Luminance[n+2] Alpha[n+3] GL_LUMINANCE_ALPHA(GL_LUMINANCE_ALPHA_NATIVE_DMP) GL_UNSIGNED_BYTE_4_4_DMP GL_LUMINANCE(GL_LUMINANCE_NATIVE_DMP) GL_ALPHA(GL_ALPHA_NATIVE_DMP) GL_UNSIGNED_4BITS_DMP

7.4. Loading Compressed Textures

You can load compressed image data as texture images. Partial texture loading, with the glCompressedTexSubImage2D function, is not supported.

Code 7-4. Definition of the glCompressedTexImage2D Function
void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, 
                            GLsizei width, GLsizei height, GLint border, 
                            GLsizei imageSize, const void* data); 

For target specify the value specified in the glTexImage2D function. However, shadow textures and gas textures cannot use the regions allocated by this function.

For width and height, specify the width and height of the texture image. Both numbers must be powers of 2, from 16 through 1024.

The values specified for level and border, and the restrictions on cube map textures and mipmap textures, are the same as in the glTexImage2D function.

The hardware supports only one compressed texture format: ETC1 (Ericsson Texture Compression). You can set internalformat to either GL_ETC1_RGB8_NATIVE_DMP or GL_ETC1_ALPHA_RGB8_A4_NATIVE_DMP.

The ETC1 format takes blocks of 4×4 texels in the 24-bit RGB format and compresses them each into 64 bits. An alpha channel is not supported by GL_ETC1_RGB8_NATIVE_DMP, but it is supported by GL_ETC1_ALPHA_RGB8_A4_NATIVE_DMP, which adds 4 bits of alpha component data for each of the 16 texels.

A value of 1 is output for the alpha component when the texture combiner references a compressed texture with a format that does not include an alpha channel.

For imageSize specify the number of bytes in the image data. If the original texture image has a width of w and a height of h, imageSize can be found using the following equation. The value of blockSize is either 8 when there is no alpha channel or 16 when there is.

imageSize = (w / 4) * (h / 4) * blockSize

The ETC1 format handled by the 3DS system is different from the standard OpenGL specifications. 7.10. Native PICA Format explains the differences between this format and the standard specifications. For more information about formats, see the 3DS Programming Manual: Advanced Graphics.

7.5. Copying From the Color Buffer

You can get (copy) an image of the color buffer as a texture.

Code 7-5. Definition of the glCopyTexImage2D Function
void glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, 
                      GLint x, GLint y, GLsizei width, GLsizei height, 
                      GLint border); 

For target, specify the value specified in the glTexImage2D function. All other argument values are also the same, except for the following differences.

  • For internalformat specify either GL_RGB or GL_RGBA, but data cannot be converted from the color buffer format during the copy (only formats with the same pixel sizes are allowed).
  • The values of x and y specify the starting point from which to copy color buffer data (with the origin at the lower-left corner and the positive axes pointing up and right). For width and height, specify the width and height of the region to copy. The values of x and y must be multiples of 8.
  • You can only specify 0 for level.

7.5.1. Copying From the Color Buffer

You can also copy a partial texture image region from the color buffer.

Code 7-6. Definition of the glCopyTexSubImage2D Function
void glCopyTexSubImage2D(GLenum target, GLint level, 
                         GLint xoffset, GLint yoffset, GLint x, GLint y, 
                         GLsizei width, GLsizei height); 

Data must be copied to a texture image region that was allocated in advance by the glTexImage2D function.

This function is the same as glCopyTexImage2D except that xoffset and yoffset specify the coordinates of the region to be copied to (where the origin is the lower-left corner and the positive axes point up and toward the right), and width and height specify a multiple of 8 (not necessarily a power of two).

7.5.2. Copying From the Depth Buffer

If you call the glEnable function with GL_DEPTH_STENCIL_COPY_DMP passed as an argument, the glCopyTexImage2D and glCopyTexSubImage2D functions copy the content of the depth (and stencil) buffer, rather than the color buffer, to a texture as long as depth/stencil copy operations are enabled.

The format of the current depth buffer determines the format of the texture to specify as the copy target. Because the format is not converted during the copy operation, a GL_INVALID_OPERATION error occurs if you attempt to copy data to a texture with an unsupported format. The copied data is identical for both native and non-native texture formats.

Table 7-5. Depth Buffer Formats and the Corresponding Texture Format and Type

Depth Buffer Format

Texture Format

Texture Type

Components

GL_DEPTH24_STENCIL8_EXT

GL_RGBA

GL_RGBA_NATIVE_DMP

GL_UNSIGNED_BYTE

R: Stencil
G: D [23 : 16]
B: D [15 : 8]
A: D [7 : 0]

GL_DEPTH_COMPONENT24_OES

GL_RGB

GL_RGB_NATIVE_DMP

GL_UNSIGNED_BYTE

R: D [23 : 16]
G: D [15 : 8]
B: D [7 : 0]

GL_DEPTH_COMPONENT16

GL_HILO8_DMP

GL_HILO8_DMP_NATIVE_DMP

GL_UNSIGNED_BYTE

R: D [15 : 8]
G: D [7 : 0]

Note: The Components column shows which bits of the depth value are set in each component. (For example, Depth [15:8] indicates that bits 8 through 15 of the depth value are set for that component.)

You can call the glEnable, glDisable, and glIsEnabled functions and pass GL_DEPTH_STENCIL_COPY_DMP as an argument to respectively enable, disable, and determine the current status of depth and stencil copy operations.

Note:

You cannot use the glCopyTexImage2D and glCopyTexSubImage2D functions in block 32 mode. No errors are generated, but images are not transferred properly. For information about block mode settings, see the 3DS Programming Manual: Advanced Graphics.

7.6. Specifying a Texture as the Render Target

To write rendering results directly to a texture ("render to texture"), take a texture image allocated by glTexImage2D and bind it to a framebuffer object using the glFramebufferTexture2D function. Because rendering results are written directly to each of the special textures used by shadows and gases, you do not need to use this function to specify the special textures as rendering targets.

Code 7-7. Definition of the glFramebufferTexture2D Function
void glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, 
                            GLuint texture, GLint level); 

For target, you can only specify GL_FRAMEBUFFER.

For attachment, specify the data to write to the texture. You can specify GL_COLOR_ATTACHMENT0 (color data) or GL_DEPTH_ATTACHMENT (depth data). For textarget, specify the value specified for target in the glTexImage2D function. For texture, specify the texture object to bind to the framebuffer object. For level, can only specify 0.

When a texture is specified as the render target for the depth (and stencil) buffer, Table 7-5 in 7.5.2. Copying From the Depth Buffer shows which texture format to specify for each depth buffer format.

Specifying GL_DEPTH_ATTACHMENT as the attachment parameter has the same effect as specifying GL_DEPTH_STENCIL_ATTACHMENT, when you call this function on a depth buffer in the GL_DEPTH24_STENCIL8_EXT format.

7.7. Loading Lookup Tables

The glTexImage1D function loads one-dimensional textures in OpenGL, but it is used to load lookup tables on the 3DS system. A lookup table is a one-dimensional table accessed by procedural textures, fragment lighting, fog, and gases. It cannot be used as a texture.

Code 7-8. Definition of the glTexImage1D Function
void glTexImage1D(GLenum target, GLint level, GLint internalformat, 
                  GLsizei width, GLint border, GLenum format, GLenum type, 
                  const GLvoid *pixels); 

For target, specify GL_LUT_TEXTUREi_DMP to specify the lookup table to load. The lookup table number is given by i, a number between 0 and one less than the value obtained by passing GL_MAX_LUT_TEXTURES_DMP to pname in the glGetIntegerv function. In other words, you can specify a lookup table number in the range from 0 through 31. GL_LUT_TEXTUREi_DMP is defined as GL_LUT_TEXTURE0_DMP+i.

You can only specify 0 for level, GL_FLOAT for type, and GL_LUMINANCEF_DMP for format and internalformat. A GL_INVALID_VALUE error is generated if level is nonzero. A GL_INVALID_ENUM error is generated if type, format, or internalformat is not one of these values.

For width, specify the number of table elements, and for pixels, specify the table elements. The maximum value that can be specified for width is 512, which is the same value obtained from the glGetIntegerv function when GL_MAX_LUT_ENTRIES_DMP is passed into pname. However, the various reserved fragment processes have unique restrictions on the number of table elements and on the table elements.

To get the ID of the texture object bound to GL_LUT_TEXTUREi_DMP, call glGetIntegerv and specify GL_TEXTURE_BINDING_LUTi_DMP for the pname parameter (where i is a value from 0 through 31).

Use the glTexSubImage1D function to rewrite a subset of the lookup table data that has been loaded.

Code 7-9. Definition of the glTexSubImage1D Function
void glTexSubImage1D(GLenum target, GLint level, GLint xoffset, 
                     GLsizei width, GLenum format, GLenum type, 
                     const GLvoid *pixels); 

Data must be copied to a lookup table region that was allocated in advance by the glTexImage1D function.

This function is identical to glTexImage1D except for xoffset and width, which specify the starting element number and the number of elements, respectively. A GL_INVALID_VALUE error is generated if the sum of width and xoffset exceeds the number of table elements.

The glCopyTexImage1D and glCopyTexSubImage1D functions have not been implemented. Texture parameter settings are also unsupported.

7.8. Destroying Texture Objects

You can use the glDeleteTextures function to destroy texture objects that are no longer necessary.

Code 7-10. Definition of the glDeleteTextures Function
void glDeleteTextures(GLsizei n, const GLuint* textures); 

7.9. Texture Collections

Using texture collections, you can bind a group of texture objects to a texture type in one operation. Texture collections share their namespace with texture objects and can be created, specified, and destroyed using glGenTextures, glBindTexture, and glDeleteTextures, respectively.

7.9.1. Creating Texture Collections

A texture collection operates as a special texture object. Consequently, use the glGenTextures function to generate objects that can be used as texture collections, just as you would for texture objects.

7.9.2. Specifying Texture Collections

Use the glBindTexture function to specify a texture object to use as a texture collection. Call this function, and for the target parameter, specify GL_TEXTURE_COLLECTION_DMP. By default, the object with a name of 0 (with a value of 0 passed into texture) is a texture collection.

After this function is called, the texture collection records the texture objects bound by glBindTexture to each texture type (2D texture, cube map texture, and lookup table). The function overwrites any other existing binding to the same texture. Settings recorded in the texture collection remain until the collection is switched.

When the texture collection is switched, all texture objects recorded in the new texture collection are bound as the new textures.

7.9.3. Destroying Texture Collections

Texture collections can be destroyed with the glDeleteTextures function, just like texture objects. Even if a texture collection is destroyed, it does not affect texture bindings to the texture objects recorded in that vertex state collection.

The glDeleteTextures function does not immediately destroy a texture collection that is in use. A texture collection remains in use until it is switched with another one. You cannot destroy the default texture collection. Calls to glDeleteTextures on the default texture collection are ignored.

7.10. Native PICA Format

The GPU's texture unit supports a different texture format than the OpenGL specifications. The format that is actually supported by the texture unit is called the native PICA format. Because libraries do not convert textures loaded in native PICA format, it is more efficient than the standard format.

There are three major differences between this format and the OpenGL specifications.

  • Byte order
    Bytes are written in a different order because of the way internal addresses are processed.
  • V-Flip
    The two formats use v-axes that run in opposite directions, when placing texels using UV coordinates.
  • Addressing
    Texels and compressed data blocks are written in different orders, because of differences between linear addressing (OpenGL) and block addressing (native PICA format).

In the CTR system, v-flip, addressing, and byte-order conversions are run, in that order, on an uncompressed texture (loaded by glTexImage2D), to convert it from the OpenGL format into the native PICA format. The system converts a compressed texture (loaded by glCompressedTexImage2D) by running V-flip, ETC compression, addressing, and finally, byte-order conversions. Note that v-flip conversion must precede ETC compression.

7.10.1. Byte Order Swapping

When the format uses more than one byte to represent a single texel and the texture was defined by calling glTexImage2D and passing GL_UNSIGNED_BYTE as the type, the number of bytes swapped (replaced) is the same as the number of bytes that represent a texel.

Data in a compressed format is swapped one block (8 bytes for 4×4 texels) at a time. However, if the format has an alpha channel (the first 8 bytes), the alpha portion is not byte-swapped.

Figure 7-2. Four-Byte Swap

OpenGL Native R G B A

Figure 7-3. Three-Byte Swap

OpenGL Native R G B

Figure 7-4. Two-Byte Swap

OpenGL Native L A

Figure 7-5. Byte Swap in a Compressed Format (No Alpha Channel)

B0 B1 B2 B3 B4 B5 B6 B7 ETC1 Native B8 B9 B15 B14 Swap 8 bytes at a time

Figure 7-6. Byte Swap in a Compressed Format (With Alpha Channel)

B0 B1 B2 B3 B4 B5 B6 B7 ETC1 Native Color portion swapped 8 bytes at a time B8 B9 B10 B11 B12 B13 B14 B15 Alpha portion not byte-swapped

7.10.2. V-Flip Differences

In the OpenGL specifications, images are converted into data starting with the texel at UV coordinates (0.0, 0.0). In the native PICA format, images are converted into data, starting with the texel at UV coordinates (0.0, 1.0). This is the same for both uncompressed and compressed textures.

7.10.3. Differences in Addressing

In the OpenGL specifications, texels are stored consecutively in the U direction (linear addressing). In the native PICA format, blocks of texels are stored, consecutively, in the U direction, but texels within those blocks are stored in a zigzag pattern (block addressing).

7.10.3.1. Uncompressed Textures

Texels are stored in a zigzag pattern within each block of 8×8 texels (as shown by the red lines in the figure), but the blocks are stored consecutively in the U direction.

Figure 7-7. Texel Order in an Uncompressed Texture

8x8 texels = 1 block (sequence of blocks in the u direction) 0.0 1.0

7.10.3.2. Compressed Textures

A compressed texture compresses each block of 4×4 texels. In the OpenGL specifications, blocks are stored consecutively in the U direction (shown by the blue line in the figure). In the native PICA format, blocks are stored in a zigzag pattern in meta-blocks of 2×2 blocks. The meta-blocks themselves are stored consecutively in the U direction (shown by the red line in the figure).

Figure 7-8. Texel Order in a Compressed Texture

0.0 1.0

For more information about compressed textures, see the 3DS Programming Manual: Advanced Graphics.


CONFIDENTIAL