opengl es texture!

Hi there,
In OpenGL ES, the width and height of a picture that used for texture must be two to the power of n. In my program i need draw a lot of pictures and some of them are not two to the power of n. Then how to use these pictures? Thanks a lot!

First you have to know that the power-of-two limitation does not forces width and height to be the same. Depending on the case, it can help reduce the overhead.ie, 32128 is valid POT.
Then you can just fill in the non-power-of-two part you have and only use texcoords within this rectangle, instead of the full 0-1 range.
Ex, for 30
100 NPOT picture on a 32*128 POT texture, use texcoords :
xmin=0, xmax=30/32.0
ymin=0, ymax=100/128.0

Hi ZbuffeR,
Thanks for your reply!

“First you have to know that the power-of-two limitation does not forces width and height to be the same. Depending on the case, it can help reduce the overhead.ie, 32*128 is valid POT.”
yes, i know that the width and height of a picture for texture can not be the same.

“Then you can just fill in the non-power-of-two part you have and only use texcoords within this rectangle, instead of the full 0-1 range.
Ex, for 30100 NPOT picture on a 32128 POT texture, use texcoords :
xmin=0, xmax=30/32.0
ymin=0, ymax=100/128.0”

How to do what you said? ie, if i have a 30100 picture and read its data into a buffer(a buffer of 30100BYTES_PER_PIXEL length, ie, BYTE pBuffer = new BYTE[30100BYTES_PER_PIXEL];), then pass 32,128 and pBuffer to the third, fouth and last parameter of the function glTexImage2D. Does this make a right texture? Thanks a lot!

BTW: if a 30140 picture, its texture should be 32256?

That is the idea, but you will have to play with GL_PACK_ROW_LENGTH and provide all the rows (even if the last ones are undefined) to avoid GL trying to read past your array. See the documentation about glPixelStorei
It is simpler if you can fill in yourself 30100 in a 32128 block, and send the 32*128 data to OpenGL.

EDIT: scratch that, even simpler is to glTexImage2D on a NULL pointer, with 32*128, then glTexSubImage2D the part of interest.
Just keep in mind the default GL alignment is 4 bytes, so you might have to do this for byte alignment :
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelStorei(GL_PACK_ALIGNMENT, 1);

And yes : for a 30140 picture, its texture should be 32256.

Hi ZbuffeR,

Thanks for your help! But i still have some questions.

I have a 400*240 picture and want to draw it at the position (0,0,400,240) of my screen. First i read the picture into a buffer(the pointer pData in the following codes points to this buffer), then i try the following:

  1. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 512, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, pData);
    when doing this, my program stops and seems to be dead.

so i try the second method as follow:

BYTE pBuf = new BYTE[512256*iChannel];
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 512, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, pBuf);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 480, 240, GL_RGB, GL_UNSIGNED_BYTE, pData);
delete [] pBuf;
pBuf = NULL;

This works ok! but there is a problem when i draw this texture to the screen.
because the picture is 400*240, so i draw it to the RECT(0,0,400,240) of my screen, but i found
the picture doesnt occupy all the rect, the right and lower place is black! How to solve this problem?
Thanks a lot!

Can anybody help me? Thanks!

  1. of course this can not work, as I explained above.
  2. perfect.

Did you use custom texcoords as I explained even earlier ?
xmin=0, xmax=400/512.0
ymin=0, ymax=240/256.0

What code do you use to draw on screen ? Quad, vertex, texturecoord, etc ? Please show your code.

Hi ZbuffeR,

Thanks very much!

“Did you use custom texcoords as I explained even earlier ?
xmin=0, xmax=400/512.0
ymin=0, ymax=240/256.0”

Sorry, i dont know when and where to use this. Can i pass them as parameters to some functions?

Sorry for i have no code on hand, but i remember a little, it is something like this:

glBindTexture(…);
glVertexPointer(…);
glTexCoord(…);
glDrawArrays(…);

Thans again!

BTW: I will show my code more complete, but it need some hours later for i am not at my office now.

Hi ZbuffeR,

My full codes are as follow:

void OpenGL::LoadTexture(BYTE* pData, int iWidth, int iHeight, int iChannel, unsigned int* texture)
{
glGenTextures(1, texture);
glBindTexture(GL_TEXTURE_2D, *texture);

glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);

int width = ldexp(1, ceil(log(iWidth)/log(2)));
int height = ldexp(1, ceil(log(iHeight)/log(2)));	
if (iChannel == 2)
{
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);
	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, iWidth, iHeight, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pData);
}
else if (iChannel == 3)
{
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, iWidth, iHeight, GL_RGB, GL_UNSIGNED_BYTE, pData);
}
else if (iChannel == 4)
{
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
	glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, iWidth, iHeight, GL_RGBA, GL_UNSIGNED_BYTE, pData);
}

}

void OpenGL::GlDrawIcon(const RECT& rect, unsigned int texture, int z)
{
glTranslatex(0, 0, Int2Fixed(z));

GLshort vertices[12];
GetVerticesFromRect(vertices, rect);	
glTexCoordPointer(2, GL_FIXED, 0, m_texcoords);	
glVertexPointer(3, GL_SHORT, 0, vertices);
glBindTexture(GL_TEXTURE_2D, texture);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

glTranslatex(0, 0, Int2Fixed(-z));

}

m_texcoords[0] = m_texcoords[1] = m_texcoords[3] = m_texcoords[4] = 0;
m_texcoords[2] = m_texcoords[5] = m_texcoords[6] = m_texcoords[7] = ONE;

Thanks!

Hi,

Another thing i need clarify:

First, i make a 512256 texture with a 480240 picture.

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 512, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 480, 240, GL_RGB, GL_UNSIGNED_BYTE, pData);

Second, i draw it on screen.
if i draw the texture at the (0,0,512,256) region of the screen, then the picture is fully in the region (0,0,480,240).
and the (481,0,512,256) and (0,241,512,256) regions both are black(have no picture data), so i want these black areas dont show on my screen.

if i draw the texture at the (0,0,480,240) region of the screen,
then the picture is fully in a region (0,0,x,y), and the (x+1,0,480,240) and (0,y+1,480,240) regions both are black. This time the picture is not shown with its original size(480*240), it is been resized(size reduced).

I search this problem with google, many people have no idea with it and some people think it cannt be figured. They think that using pictures with width and height be the power of 2 is the only solution. I dont know whether thet are right.

Now i have no idea, any help and suggestions would be appreciated!

if there are no good ideas, i have to break down a 480*240 picture to 12 pictures, with width and height as follow:

256128 128128 16128
256
64 12864 1664
25632 12832 1632
256
16 12816 1616

You already have all the information you need.
If you post 3 messages while us europeans are asleep, please be patient enough to have an answer :slight_smile:

Here :

m_texcoords[0] = m_texcoords[1] = m_texcoords[3] = m_texcoords[4] = 0;
m_texcoords[2] = m_texcoords[5] = m_texcoords[6] = m_texcoords[7] = ONE;

Fix your texture coordinates, as I already explained 2 times here, instead of using the 0;1 range, use 0;(float)iWidth/width for width and 0;(float)iHeight/height.

That way you will only see the desired part of the texture, without black borders.

I search this problem with google, many people have no idea with it and some people think it cannt be figured. They think that using pictures with width and height be the power of 2 is the only solution. I dont know whether thet are right.

Indeed they are WRONG.

Hi ZbuffeR,

Thanks very much! It’s ok now! :slight_smile: