Well, it's been bit quiet here, on the Tips forum, so I thought I'd share a piece of code that many books, and tutorials doesn't seem to cover at all (many GL references misses the following function, glTexSubImage2D, as well).
I often see people either doing the following the loading textures:
a) Using width & height with a value of power of two in the original texture stored in the harddrive, even if the actual texture doesn't need to be this big. (This is done by either stretching the image to the width/height, which usually results into a loss of pixel precision, or by padding the needed range with unnecessary pixels).
b) Same as a, but instead of storing the texture in such format, the process is done programmatically before storing it in VRAM.
This code doesn't need you to do such measurements, it uses glTexImage2D in conjuction with sub image loading.
I'll first show the code and then explain how it works.
Note. You may need to change the parameters of glTexImage2D and glTexSubImage2D according to the format you use, this is just your very basic example.
| CODE |
// NearestPowerOfTwo() requires <cmath> inline GLsizei NearestPowerOfTwo(GLsizei a) { return 1 << (int)ceil(log10(a) / log10(2.0)); }
void LoadTexture(GLsizei width, GLsizei height, const GLvoid * pixels) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, NearestPowerOfTwo(width), NearestPowerOfTwo(height), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); } |
For those who don't understand it fully after looking through the code, here's an explanation of how it works..
Let's start with the LoadTexture().
The first call to glTexImage2D() is pretty similiar to what you usually see, but here we are passing a NULL pointer (0 in this) as a last argument for the source pixels pointer. What this does is only allocate the needed memory in the VRAM for the texture, but does not load any data yet, this is perfect for what we need.
You may also note the usage of NearestPowerOfTwo() function here, I'll explain its purpose after the explanation of glTexSubImage2D().
glTexSubImage2D() function's existance is a mystery for many OpenGL programmres, even some more experienced ones. What it does is copy a defined portion of pixels into an existing texture (which is why we first created the texture with glTexImage2D).
For people who care, the definition of the function is the following:
| CODE |
void glTexSubImage2D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels ) |
After looking at the definition, the code above should be pretty self-explationary.
Anyways, as for the NearestPowerOfTwo(), what it does is nothing more than find the nearest, big enough power of two value of the initial width/height value.
If you aren't familiar with logarithms, the logic is the following:
| CODE |
f(x) = 2^a >= x (where a is INTEGER) lg 2^a >= lg x || take logarithms (base 10) from both sides a lg 2 >= lg x || use one of the logarithm's rules, and move the exponent a >= lg x / lg 2 || divide both sides of the equation by lg 2
REMEMBER FROM DEFINITION, a needs to be INTEGER, hence if a % 1 != 0, it has a decimal part, you can effectively round it up by using the ceil() standard function Note. You HAVE to round it up because otherwise the equation a >= lg x / lg 2 would not be true (it would be less than lg x / lg 2) a = ceil(lg x / lg 2)
Now that you got the exponent of the equation, it's easy enough to get the result result = 2 ^ a Or in C/C++: result = pow(2, a); Shifting 1 to left by a bits does exactly the same; It's a fast power-of-two operation 1 << a; |
Or if you prefer to see the thing scanned:
http://www.uncleramiscorner.info/powerOfTwo.jpg(Excuse my crappy handwriting ;d)
You could of course use something more simple, understandable code to find the value if speed isn't the most critical thing (eg. writing a while loop multiplying a temporary value by two as long as it's smaller than the value you want to get nearest, big enough power of two value for).
Good, better than NeHe's stupid glaux thing.