nonstandard texture sizes

Started by
5 comments, last by wyled 18 years, 1 month ago
It seems that both the width and height of an opengl texture must be a power of 2. But if I need to use a texture of nonstandard texture size, must I resize it or cut it into pieces?? I have once heard there are some ways around this limitation, is it true? If true ,what is it?? Thanks!!
Advertisement
ARB_texture_non_power_of_two, if your card supports it (most do, nowadays).

If not, you will have to resize or cut it up, as you mentioned.
You can also load it into a texture of the next higher power of 2 size. Wasted space, but keeps your texels the same size if that's important to you. Keep in mind this won't work well if you need to tile the texture coords.
Thank you a lot, bpoint & wendigo23!

It seems that wedingo23's idea fit me quite well, for I must keeps texels the same size . And I'm seldom need to tile the texture coords in my program.
Also, If I understand correctly, using tex coords in the range 0.0-1.0 won't give your correct results. Depending on your texture's aspect ratio and where within the texture you place your texels, you will have to adjust the tex coords on your polygons appropriately.

E.g. If you intend to store a 512x300 texture, the logical choice would be a 512x512 texture. Now, if you place your texture data in the upper part of your texture (which would generally be the case) the bottom 212 rows would still remain empty (white or garbage, the way you want them). So to correctly map the tex coords you need to map the t texcoord in the range (212.0/500.0, 1.0).
Quote:Original post by bpoint
ARB_texture_non_power_of_two, if your card supports it (most do, nowadays).
Actually, GL_ARB_texture_non_power_of_two is not very widely supported yet. Out of NVIDIA and ATI only the GeForce 6x00 (and similar Quadro cards) and above support it. I'm not sure on the Radeon X1x00 cards but according to the OpenGL Extensions Viewer and Delphi3d's hardware list they don't. 3Dlabs' Wildcat Realizm and XGI's Volari Family cards apparently support it as well, but they are not very common in consumer PCs.

There is also GL_ARB_texture_rectangle which is more widely supported, but it has some other restrictions and differences over regular 2d textures. The main differences are...
 - Non-normalized texture coordinates ([0,w] x [0,h] instead of [0,1] x [0,1]) - No mipmapping - Only clamping wrap modes
Read the spec for more information.
I would advise against using any ARB extentions as they aren't supported by many cards.

Instead this issue can easily be resolved in your code instead of a quick (and sloppy) function fix.

Here is a function i wrote that can handle oddly sized textures, however you need to encase your textures in a data structure to remind your code of the initial size and the new size (it also handles PNG transparency):

(I appologize for the sloppyness of the code. It uses SDL_image to load images for compatibility and ease of use.
// in the .h filetypedef struct {	GLuint texture;	int ow;			// Old width	int oh;			// Old height	int w;	int h;	char filename[32];	char type;	char *bitmask;} GLtexture;// in the .c fileGLtexture* OGL_S2T(char *filename){	Uint8 *rowhi, *rowlo;	Uint8 *tmpbuf, tmpch;	SDL_Surface *s;	SDL_Surface *tmp;	int i, j;	int x2, y2;	SDL_Color clr;	Uint32 col = 0;	Uint32 col2 = 0;	char *gpos = NULL;	char *hpos = NULL;	int iw=0, ih=0;	int exp = 1;	GLtexture *tex = (GLtexture *)malloc(sizeof(GLtexture));	s = IMG_Load(filename);	if ( s == NULL ) {		fprintf(stderr, "Unable to load %s: %s\n", filename, SDL_GetError());		return(NULL);	}	SDL_DisplayFormatAlpha(s);	tex->ow = s->w;	tex->oh = s->h;	while(pow(2, exp) < s->w)		exp++;	iw = pow(2, exp);	exp = 1;	while(pow(2, exp) < s->h)		exp++;	ih = pow(2, exp);	tmp = SDL_CreateRGBSurface(SDL_HWSURFACE|SDL_SRCALPHA, iw, ih, 32, 0, 0, 0, 255);	SDL_LockSurface(tmp);	SDL_LockSurface(s);	y2 = 0;	while(y2 < s->h)	{		x2 = 0;		while(x2 < s->w)		{			gpos = (char *)s->pixels;			gpos += (s->pitch * y2);			gpos += (s->format->BytesPerPixel * x2);			hpos = (char*)tmp->pixels;			hpos += (tmp->pitch *y2);			hpos += (tmp->format->BytesPerPixel * x2);			memcpy(&col, gpos, s->format->BytesPerPixel);			SDL_GetRGBA(col, s->format, &clr.r, &clr.g, &clr.b, &clr.unused);			col2 = SDL_MapRGBA(s->format, clr.r, clr.g, clr.b, clr.unused);			memcpy(hpos, &col2, tmp->format->BytesPerPixel);			x2++;		}		y2++;	}	SDL_UnlockSurface(tmp);	SDL_UnlockSurface(s);	tex->bitmask = GenBitMask(s);		SDL_FreeSurface(s);	/* GL surfaces are upsidedown and RGB, not BGR :-) */	tmpbuf = (Uint8 *)malloc(tmp->pitch);	if ( tmpbuf == NULL ) {		fprintf(stderr, "Out of memory\n");		return(NULL);	}	rowhi = (Uint8 *)tmp->pixels;	rowlo = rowhi + (tmp->h * tmp->pitch) - tmp->pitch;	for ( i=0; i<tmp->h/2; ++i ) {		for ( j=0; j<tmp->w; ++j ) {			tmpch = rowhi[j*4];			rowhi[j*4] = rowhi[j*4+2];			rowhi[j*4+2] = tmpch;			tmpch = rowlo[j*4];			rowlo[j*4] = rowlo[j*4+2];			rowlo[j*4+2] = tmpch;		}		memcpy(tmpbuf, rowhi, tmp->pitch);		memcpy(rowhi, rowlo, tmp->pitch);		memcpy(rowlo, tmpbuf, tmp->pitch);		rowhi += tmp->pitch;		rowlo -= tmp->pitch;	}	free(tmpbuf);	glGenTextures(1, &tex->texture);	glBindTexture(GL_TEXTURE_2D, tex->texture);	tex->w = iw;	tex->h = ih;	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);	glTexImage2D(GL_TEXTURE_2D, 0, 4, iw, ih, 0, GL_BGRA, GL_UNSIGNED_BYTE, tmp->pixels);	SDL_FreeSurface(tmp);	strcpy(tex->filename, filename);	tex->type = GFX_TYPE_BMP;	return tex;	}
---John Josef, Technical DirectorGlass Hat Software Inc

This topic is closed to new replies.

Advertisement