convert pic to power-of-two during runtime?

Started by
8 comments, last by drarem 18 years, 4 months ago
So I've created a small demo and noticed - the textures don't work on my two laptops. They have have the same integrated graphics driver - 852/855 GM intel. Not unless I use powers of two textures. What would be the math to convert a 384x256 texture to a 512x256 sized texture during runtime (tile size is 64x64)? Or is that possible, I was thinking if I modify the texture coordinates alone, it should only display that - right? Right? Here is my work so far: 1) Load bitmap 2) Find the next highest power of two and create the RGBA image 3) Here's where my math fails.. (512 - 384) = extra pixels not used = 128 64/384 isn't right, the uv coords would be off 64/512 isn't right either, uv coords would exceed the actual 384x256 image Is it how many 64 will go into 384, will go into 512? Please help, thanks.
I'll give you a beating like Rodney King who deserved it!=====================================Any and all ideas, theories, and text c2004,c2009 BrainDead Software. All Rights Reserved.
Advertisement
Next power of 2 w.r.t. w(idth) and h(eight):
w' = ceil(log(w)/log(2))
h' = ceil(log(h)/log(2))
(Obviously not efficient to compute but its the math way to do it.)
Feel free to do an equivalent integer math trick, e.g. (in C):
int nextPowerOfTwo(int arg) {   int result = 16; // assuming that image size will not below 16 pixels   while(result<arg) {      result <<= 1;   }   return result;}


You have two ways to solve your problem (if no power of 2 textures are supported):

(1) Copy the original image unscaled into the bigger buffer (aligned to the u,v=0 corner) and use adapted texture co-ordinates by multiplying u by w/w' and v by h/h'. This method is simple but may produce artifacts as soon as texture repetition and such should be used. And it obviously wastes texels.

(2) Scale the image to the bigger texture size. Here it depends on the wanted quality of the scaled image. For good quality you have to up-sample the image with a suitable multi-point filter. For poorest quality you could use the nearest neighbour filter, for a little bit better quality the bi-linear interpolation filter.


BTW: I remember that older extensions exist for non power of 2 textures that use a pixelwise addressing. So perhaps your problem is just an addressing problem?

[Edited by - haegarr on December 15, 2005 6:10:43 AM]
Appendix: I've forgotten to hint at a trick if scaling all particular u,v co-ordinates isn't appropriate: It should be possible to alter the texture transformation matrix, so that the scaling of u,v is done on-the-fly by the GPU.
Quote:Original post by drarem
3) Here's where my math fails..
(512 - 384) = extra pixels not used = 128
64/384 isn't right, the uv coords would be off
64/512 isn't right either, uv coords would exceed the actual 384x256 image

Is it how many 64 will go into 384, will go into 512?

Maybe I'm being stupid, but why would 64/512 be wrong? (assuming this is to calculate the UV texture coordinate from the pixel coordinates, and not to adjust an existing UV coordinate, in which case you want what haegarr said: u *= w/w', v *= h/h')

John B
The best thing about the internet is the way people with no experience or qualifications can pretend to be completely superior to other people who have no experience or qualifications.
Quote:Original post by JohnBSmall
Maybe I'm being stupid, but why would 64/512 be wrong? (assuming this is to calculate the UV texture coordinate from the pixel coordinates, and not to adjust an existing UV coordinate, in which case you want what haegarr said: u *= w/w', v *= h/h')

You're absolutely right: E.g. a pixel co-ordinate x=64 corresponds to an u=64/384 in the "old" texture. Then in the new texture it would be
u' = u * w / w' = 64 / 384 * 384 / 512 = 64 / 512
q.e.d.
Quote:Original post by JohnBSmall
Quote:Original post by drarem
3) Here's where my math fails..
(512 - 384) = extra pixels not used = 128
64/384 isn't right, the uv coords would be off
64/512 isn't right either, uv coords would exceed the actual 384x256 image

Is it how many 64 will go into 384, will go into 512?

Maybe I'm being stupid, but why would 64/512 be wrong? (assuming this is to calculate the UV texture coordinate from the pixel coordinates, and not to adjust an existing UV coordinate, in which case you want what haegarr said: u *= w/w', v *= h/h')

John B


I don't know - I am confused.
The tiles are 64x64 and stretch out to 384x256 (that is 6 rows x 4 columns).
UVs for that is easy to calculate. 512/64 = 8 rows across but the tiles are 6x4.
I thought it would be cutting them off.

I'm researching the gl_texture_ext_arb stuff at the moment, trying to figure out how to calculate the 0...w out. Would that be 64/w or w/64 for each tile?

EDIT: By the way, in the new texture I am padding the excess with white values - I have seen none crop up but the texture looks weird still.
I'll give you a beating like Rodney King who deserved it!=====================================Any and all ideas, theories, and text c2004,c2009 BrainDead Software. All Rights Reserved.
Ok. If you don't copy but strech the texture (say, the texture still shows 6 by 4 tiles), then you have to use
u' := u
v' := v
or, if you have still pixel co-ordinates
u' := x / w
v' := y / h
u and v are relative co-ordinates, so you only have to normalize x,y by the widht,height of the image in which x and y is measured!

E.g. if x=64, w=384:
u' := 64 / 384


EDIT: Perhaps you have another problem if you have a weird texture look. COuld you describe what "weird" means in this case, or even better post a screen shot?

[Edited by - haegarr on December 15, 2005 7:10:46 AM]
Find the next power of two as haegarr said, then use gluScaleImage I think is the easiest way.
I'm trying to gluscaleimage, it looks like it will be satisfactory.

Here is the code, thanks for all the help.


    unsigned char *pImage_RGBA = NULL;    unsigned char *pImage_RGBA_temp = NULL;    if( pImage_RGB != NULL ) {	 	SPRITES[id].x = 0.0;	 	SPRITES[id].y = 0.0;	 	SPRITES[id].txwid = ((float)(xsiz/framesx)/(float)xsiz);	 	SPRITES[id].tywid = ((float)(ysiz/framesy)/(float)ysiz);	 	SPRITES[id].xscale = (xsiz/framesx)/xscale;		SPRITES[id].yscale = (ysiz/framesy)/yscale;	 	for (dy=0; dy < framesy; dy++) {			for (dx=0; dx< framesx; dx++) {				SPRITES[id].prex[nptr] = SPRITES[id].txwid*dx;				SPRITES[id].prey[nptr] = SPRITES[id].tywid*dy;				SPRITES[id].prexa[nptr] = SPRITES[id].prex[nptr] + SPRITES[id].txwid;				SPRITES[id].preya[nptr] = SPRITES[id].prey[nptr] + SPRITES[id].tywid;				nptr = nptr + 1;  	     }	    }        int imageSize_RGB  = xsiz * ysiz * 3;		int imageSize_RGBA = powx * powy * 4;  //store as power of 2 plus alpha	    int imageSize_RGBA_temp = powx * powy * 3;        // allocate buffer for a RGBA image        pImage_RGBA = new unsigned char[imageSize_RGBA];		pImage_RGBA_temp = new unsigned char[imageSize_RGBA];			        int i, j;        gluScaleImage(GL_RGB, xsiz,ysiz, GL_UNSIGNED_BYTE, pImage_RGB, powx,powy, GL_UNSIGNED_BYTE, pImage_RGBA_temp);        for( i = 0, j = 0; i < imageSize_RGBA_temp; i += 3, j += 4 )        {            // Does the current pixel match the selected color key?            if( pImage_RGBA_temp   == g_keyColor[0] &&                pImage_RGBA_temp[i+1] == g_keyColor[1] &&                pImage_RGBA_temp[i+2] == g_keyColor[2] )            {                pImage_RGBA[j+3] = 0;   // If so, set alpha to fully transparent.            }            else            {                pImage_RGBA[j+3] = 255; // If not, set alpha to fully opaque.            }            pImage_RGBA[j]   = pImage_RGBA_temp;            pImage_RGBA[j+1] = pImage_RGBA_temp[i+1];            pImage_RGBA[j+2] = pImage_RGBA_temp[i+2];        }        glGenTextures( id, &g_Textureid );        glBindTexture( gl_texture_exts, id );        glTexParameteri(gl_texture_exts,GL_TEXTURE_MIN_FILTER, GL_NEAREST);        glTexParameteri(gl_texture_exts,GL_TEXTURE_MAG_FILTER, GL_NEAREST);        glTexImage2D( gl_texture_exts, 0, GL_RGBA, powx,powy, 0,                     GL_RGBA, GL_UNSIGNED_BYTE, pImage_RGBA );
I'll give you a beating like Rodney King who deserved it!=====================================Any and all ideas, theories, and text c2004,c2009 BrainDead Software. All Rights Reserved.
it runs slower on the laptop compared to my pc, i almost wonder if it is worth it.

note: gl_texture_exts = GL_TEXTURE_2D
I'll give you a beating like Rodney King who deserved it!=====================================Any and all ideas, theories, and text c2004,c2009 BrainDead Software. All Rights Reserved.

This topic is closed to new replies.

Advertisement