Page 1 of 2

Non Power of Two texture work around?

Posted: Wed Dec 03, 2008 9:05 pm
by Cloudef
Hi,
I'm new to irrlicht and I'm doing 2d game. Ive got so far all basic loading and stuff working, but i hate that I'm not apple to load non power of two textures and 90% of my media is non power of 2.

I tough if there would be some workarounds? Lets say like re-size image canvas on fly or combine the image with invisible power of 2 image?

Posted: Wed Dec 03, 2008 9:24 pm
by Lambda
just dont use power of 2 images, you can resize these images, i am using npo2 textures for the gui of my game and everything is working fine :)

Posted: Wed Dec 03, 2008 9:33 pm
by Cloudef
The thing is, that i moved from another engine and i have lot of images that are not power of two. Also i don't want to re-size the image only the canvas. If there is tool that can handle multiple image canvas then i could re-size them.

Posted: Wed Dec 03, 2008 9:41 pm
by hybrid
Can you show your code to drw the image and screenshots to explain which errors you encounter?

Posted: Wed Dec 03, 2008 9:45 pm
by Cloudef
Sure

I load it normally using:

Code: Select all

Player[id]->state[state].body[parti].s[state2].i = Driver->getTexture(str2.c_str());
and draw using:

Code: Select all

void drawPlayer(int id) {
 int state=Player[id]->State;
 int state2=Player[id]->State2;
 int i;
 dimension2d<s32> imgSize;
 for(i=0;i < 3;i++) {
  if(Player[id]->state[state].body[i].s[state2].exist) {
   imgSize = Player[id]->state[state].body[i].s[state2].i->getOriginalSize();
   Driver->draw2DImage(Player[id]->state[state].body[i].s[state2].i, core::position2d<s32>(Player[id]->state[state].body[i].s[state2].x,Player[id]->state[state].body[i].s[state2].y),core::rect<s32>(0,0,imgSize.Width,imgSize.Height), 0,video::SColor(255,255,255,255), true);
  }
 }
}
It draws it okay. But because image is not power of two it gets really "messy".
[/code]

Posted: Wed Dec 03, 2008 10:05 pm
by Lambda
Cloudef wrote:Sure

I load it normally using:

Code: Select all

Player[id]->state[state].body[parti].s[state2].i = Driver->getTexture(str2.c_str());
and draw using:

Code: Select all

void drawPlayer(int id) {
 int state=Player[id]->State;
 int state2=Player[id]->State2;
 int i;
 dimension2d<s32> imgSize;
 for(i=0;i < 3;i++) {
  if(Player[id]->state[state].body[i].s[state2].exist) {
   imgSize = Player[id]->state[state].body[i].s[state2].i->getOriginalSize();
   Driver->draw2DImage(Player[id]->state[state].body[i].s[state2].i, core::position2d<s32>(Player[id]->state[state].body[i].s[state2].x,Player[id]->state[state].body[i].s[state2].y),core::rect<s32>(0,0,imgSize.Width,imgSize.Height), 0,video::SColor(255,255,255,255), true);
  }
 }
}
It draws it okay. But because image is not power of two it gets really "messy".
[/code]
if you want your image smoothed you need to change a line in the driver .cpp, its easy.

in CD3D9Driver.cpp search for

Code: Select all

pID3DDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
and replace with

Code: Select all

pID3DDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);

Posted: Wed Dec 03, 2008 10:08 pm
by CuteAlien
@Cloudef: A screenshot would be nice...

@Lambda: Beware of the "everything is working" - in this case it might depend very much on the card. I had my GUI working here perfectly, but then someone tested it with a card not supporting npot and it got all messed up. A surprising number of modern cards still don't do that.

Anyway, while I'm not exactly sure which problem Cloudef is facing, in my case (for the GUI) I found no other way but to change the engine. What I did was adding some padding to the textures. Now unfortunately parts of the stuff I had to change for that have been rewritten since then in the engine, so I have no working patch for that right now :-( The old patches I used for that are still available here (search for npot). But in the current state you can only use them as some startingpoint for an own implementation.

Posted: Wed Dec 03, 2008 11:49 pm
by cecil0812
I just finished up writing a little 2D sprite based RPG in Irrlicht. I had to deal with this very issue.

First, converting your images to power of two isn't as bad as you might think. Download The Gimp or Paint.NET or something and just add padding to your images.

Then, add a blit color to your images. I used a bright green color. You can tell Irrlicht to make this color transparent when it loads it and voila. Power of two textures that are actually the size you want.

Alternatively, when you get the texture for drawing it, you can specify the rectangle in the image to draw, thus making your image power of two, but only displaying the rectangle (which may or may not be power of two).

Here's a little code I used:

Code: Select all

video::ITexture* myImage = driver->getTexture("someImage.png");
driver->makeColorKeyTexture(myImage, core::position2d<s32>(0, 0));
I always had the Color Key be at the first pixel of the image which made it easy to find at all times.

Let me know if you need more info :)

Posted: Thu Dec 04, 2008 12:20 am
by jontan6
isnt it that irrlicht convert npot textures to pot on load? just a guess

Posted: Thu Dec 04, 2008 12:53 am
by cecil0812
jontan6 wrote:isnt it that irrlicht convert npot textures to pot on load? just a guess
No, it doesn't. It just warns you about a slow unlock with non power of 2 (if using software mode). With my video card and OpenGL with non power of 2, it crashed hard. With DirectX, it didn't crash but it didn't clip correctly.

Power of 2 is the way to go :)

Posted: Thu Dec 04, 2008 6:09 am
by Cloudef
I guess i have to then find batch converter and convert a lot of images.

Screen of problem:

Image
Original

Image
Irrlicht


Oh and the media is not mine btw, I'm currently reverse engineering Maple Story and creating similar engine that it is. The old rendering engine that i used had some limitations to my needs so i moved to irrlicht.

Posted: Thu Dec 04, 2008 7:15 am
by CuteAlien
jontan6 wrote:isnt it that irrlicht convert npot textures to pot on load? just a guess
I think it scales per default to pot if the card does not support npot textures. At least I think it does so in OpenGL and DX. That's just not always what you might want sometimes you want scale, sometimes you prefer padding.

Posted: Thu Dec 04, 2008 8:43 am
by hybrid
Yes, Irrlicht scales to POT for the HW accelerated drivers, because those can fail otherwise. The SW driver does handle NPOT, not sure about burningsvideo. We already had some suggestions on how to integrate padding into this scenario, but we'd like to have a clean way without too many caveats for this problem. Right now it's not possible to specify the proper source rectangle as part of the image, i.e. one is forced to use alpha channel for the padded images. While this is often no problem, it needs to be properly adapted to all parts of the engine. Patches are welcome, please put them on the patch tracker :D

Posted: Thu Dec 04, 2008 4:29 pm
by cecil0812
Hmmm, if it scales to POT on OpenGL and DirectX...

Like I said before, for DirectX, it made my sprites look funky. The auto scaling was probably a little off.

For OpenGL, whatever it was doing just crashed the program.

This was all using Irrlicht 1.4.

Once I converted everything to POT, everything looked and ran great.

Posted: Thu Dec 04, 2008 8:57 pm
by SwitchCase
For hardware which can't do npot sizes OR you don't have the required opengl extensions available (btw i dont know about d3d) then you can scale your image with something like...

Code: Select all

int width = imageWidth;
int height = imageHeight;

int i;
bool sizeToFit = false;

// Scale image width to next pot size		
if( (width != 1) && (width & (width - 1)) )
{
	i = 1;
	while( (sizeToFit ? 2 * i : i) < width )
		i *= 2;
	width = i;
}
		
// Scale image height to next pot size		
if( (height != 1) && (height & (height - 1)) )
{
	i = 1;
	while( (sizeToFit ? 2 * i : i) < height )
		i *= 2;
	height = i;
}
		
// Scale image down if now larger than the maximum texture size
while( (width > kMaxWidth) || (height > kMaxHeight) )
{
	width /= 2;
	height /= 2;
	imageWidth *= 0.5;
	imageHeight *= 0.5;
}
... then proceed to creating the texture with these dimensions but drawing them using the original image dimensions.

:P