Gui non-pow2 texture artifacts

You discovered a bug in the engine, and you are sure that it is not a problem of your code? Just post it in here. Please read the bug posting guidelines first.
Post Reply
Razed
Posts: 9
Joined: Mon May 10, 2004 9:43 am

Gui non-pow2 texture artifacts

Post by Razed »

I've just run into the infamous non-power of 2 texture artifacts. I've only dealt with 2d textures, so I'm not sure how these 'fixes' may effect the 3d case. Anyway, here's the problems I found.

1.) Texture size:
Firstly, CDirectX8Texture::getTextureSizeFromImageSize() rounds down, thus returning a texture size not large enough to fit the requested image size. In fact this whole lot can be replaced by the following code (not sure why it works, but it does, obtained from http://graphics.stanford.edu/~seander/bithacks.html)

inline s32 CDirectX8Texture::getTextureSizeFromImageSize(s32 size)
{
s32 ts = size;
ts--;
ts |= ts >> 1;
ts |= ts >> 2;
ts |= ts >> 4;
ts |= ts >> 8;
ts |= ts >> 16;
ts++;
return ts;
}

In scaling up, we have extra padding, but for 2d gui images that are power of 2 size this is essential to maintain 1-1 pixel accuracy.

Now, the next set of problems comes from the texture's use of ImageSize and TextureSize. In the cases I've seen, ImageSize should refer to the used portion of the image, and TextureSize should refer to the enlarged size (with extra padding that is not rendered). However, it is implemented such that the image is scaled into the whole TextureSize, thus causing scale issues. In fact, there are 3 sizes implicitly floating around in all this code. There is the original source file's image size (which can actually be discarded after load), the portion of texture we want to render, and then the fully padded texture size.

2.) 2D Render:
The texel coords assume we want to render the full texture image. Instead, we can just render the ImageSize portion, by changing draw2DImage's texel coords to:
const core::dimension2d<s32> sourceTextureSize = texture->getSize();
core::rect<f32> tcoords;
tcoords.UpperLeftCorner.X = (((f32)sourcePos.X)+0.5f) / sourceTextureSize.Width ;
tcoords.UpperLeftCorner.Y = (((f32)sourcePos.Y)+0.5f) / sourceTextureSize.Height;
tcoords.LowerRightCorner.X = (((f32)sourcePos.X +0.5f + (f32)sourceSize.Width)) / sourceTextureSize.Width;
tcoords.LowerRightCorner.Y = (((f32)sourcePos.Y +0.5f + (f32)sourceSize.Height)) / sourceTextureSize.Height;

3.) Image loading:
There is one last place that stretching occurs, and that is in texture loading. Here is where you'd probably want to use the 3 scales (file image size, used texture portion size, full texture size), but for my case I just hacked out the scale lines (thus copying the source image is 1-1).
f32 sourceXStep = 1.0f; // (f32)ImageSize.Width / (f32)TextureSize.Width;
f32 sourceYStep = 1.0f; // (f32)ImageSize.Height / (f32)TextureSize.Height;

At the end of that messing around, my images were back to working again (like they do in software, as software has no pow2 requirements). Hope it helps.
Post Reply