Athena: Textures

Spiderweb

Another side project I’ve been working on to go with Athena is a image convertor for storing my textures in a binary format. Originally I was just using FreeImage to load up an image like bitmap, jpeg or png.

Since all my images were to be in the RGBA format in the end, this obviously had it’s drawbacks for being slightly slow and using up extra ram when converting an image that were not layed out like this. So I rewrote my texture class to support different image formats, but apparently I didn’t understand glTexImage2D() as much as I thought I did.

Coming from a DirectX background, I thought the data you pass to glTexImage2D() would be the data going to the VRAM, but instead the data being passed gets converted to whatever you specify as the internalformat.

Type

So first of all the type parameter, this tells the glTexImage2D() what the type of variable each component in your data is using. So if you specify GL_FLOAT, it will treat each component like it is a floating point colour (0.0 to 1.0), and if you specify GL_UNSIGNED_BYTE, each component will be treated like an unsigned byte colour (0 to 255).

Format

The the format parameter, this tells the glTexImage2D() how many components are in the data as well as how to treat that data. It’ll probably be easy to explain for each. I’ll ignore GL_COLOR_INDEX since I haven’t used it yet.

GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA

These are all made up of one component, so if you have a 10×10 image, it will only have 10×10 components. When specifying an internalformat of RGBA, it will only copy the data to the colour component being specified.

GL_RED( x ) = RGBA( x, 0, 0, 1 )

GL_GREEN( x ) = RGBA( 0, x, 0, 1 )

GL_BLUE( x ) = RGBA( 0, 0, x, 1 )

GL_ALPHA( x ) = RGBA( 0, 0, 0, x )

There is an internalformat for GL_ALPHA that will do the formatting automatically whenever the texture is used, so there is no need to specify an GL_RGB/GL_RGBA for the internalformat.

Fairly simple, now for the other colours.

GL_RGB, GL_RGBA

These are fairly straight forward, they are three and four components respectively, and when converting to an internalformat of GL_RGBA they copy component for component. If an alpha component isn’t a part of the original data and is required by the internalformat, it is automatically set to fully opaque.

GL_RGB( x, y, z ) = RGBA( x, y, z, 1 )

GL_RGBA( x, y, z, w ) = RGBA( x, y, z, w )

Luminance works slightly differently.

GL_LUMINANCE

Luminance is a single component, and can be used for all internal formats as far as I know. It is treated like its single component represents the red, green and blue channels, so when used with an internalformat of GL_RGBA, you get luminance of the three colour components and an opaque alpha. There is no need for this however, since there is an internalformat of GL_LUMINANCE which will do exactly the same when the texture is being used.

GL_LUMINANCE( x ) = RGBA( x, x, x, 1 )

If the internalformat is GL_INTENSITY is used however, the data is a one for one copy, only when the texture is used, it is treated like the data is copied to all four components.

GL_INTENSITY( x ) = RGBA( x, x, x, x )

And finally Luminance Alpha.

GL_LUMINANCE_ALPHA

Luminance Alpha is similar to GL_LUMINANCE, only when the internalformat is GL_RGBA, it copies the luminance to the three colour components, and the alpha to the alpha component.

GL_LUMINANCE_ALPHA( x, y ) = RGBA( x, x, x, y )

Again, there is already an internalformat of GL_LUMINANCE_ALPHA, so there is no need to use GL_RGBA.

InternalFormat

The internalformat parameter just defines how you would like the data you are passing to be stored in VRAM. It does not have to match the format being passed in, just be compatible from I can tell.

So if you pass in a luminance of GL_UNSIGNED_BYTE, and request an internalformat of GL_LUMINANCE4, it will scale your luminance down by half and pack them into 4 bits per component.

Reducing the data size in VRAM increases speed and space usage, but has the drawback of causing banding since there is less possible colour combinations.

Another thing about the internalformat is, like I said, it is a request, they driver does not have to match it, but the data will be treated the same as the request.