Thursday, June 26, 2008

Textures

Today I've added in the caustics warp for underwater surfaces. I've tried to keep it fairly subtle, so hopefully the effect won't distract you from doing what you're supposed to be doing - staying alive and getting out of wherever you are!

I've also had to go back and rework water warp updating owing to some bugs that surfaced in the course of this. It was fairly irritating to have to do this, but I've finally got a rock solid implementation. It's based on the FitzQuake framebuffer update, but with a few small modifications:

  • Doesn't need to scale the update texture to 2x the original size.
  • Capable of handling any texture size (up to the supported maximum (for more on this see further down)) - the FitzQuake version only did 64 x 64 textures.
  • Uses vertex arrays for rendering.
  • Capable of handling variable warp speeds - including negative/reverse warps (both the FitzQuake and the original GLQuake warps only did a speed of 8).
  • No longer uses the old gl_warpsin.h table (uses a custom sintable instead, capable of handling greater levels of detail).
  • Ensures that liquid textures are square.
  • Various small optimisations.
I don't know if I mentioned anything about the maximum texture size MHQuake supports, but this is quite interesting so I'm going to write a bit about it. When I calculate the max texture size at startup, I use the following procedure:
  1. Do a glGetIntegerv for the max size supported by the implementation.
  2. Reduce this to the lowest of the MHQuake window width and height.
  3. Reduce further to the highest power of 2 below this.
Some folks may kick and scream about this, but when you think about it it does make sense. There's no point in having a texture that will always be minified on-screen, you're only wasting video RAM because miplevel 0 never gets used. Some cards even cause texture corruption under these circumstances.

I'm going to need to revisit my resolution changing code, as right now this is one thing that a resolution change doesn't accomodate (the max texture size won't change, and current textures don't get updated to reflect what the new max size should be). I always needed to do this for more robust 3D card support (hello ATI!), so having the second reason is the kick in the pants I need for it.

When uploading textures I now follow this procedure:
  1. Calculate the scaled_width and scaled_height to the power of 2 equal or above the base size.
  2. Resample it up to this.
  3. Use mipmapping of width and height individually to bring it down to the max supported size.
  4. glTexImage2D it.
This might seem strange, but again it makes sense. Main memory is plentiful in supply, so I don't mind using a bit extra when I need to. Furthermore, my mipmapping functions have been modified to preserve colour balance better, so it makes sense to use them where they're of benefit.

Finally, my resampling function is a custom one of my own that lets me expand an 8 bit texture to 32 bit at the same time as I'm resampling it. This gives me a memory saving, so I gain as well as lose on this strategy.

Till next time!

0 comments: