Jump to content
  • Advertisement
Sign in to follow this  
LonelyStar

OpenGL Non-power-of-two textures

This topic is 4838 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi everybody, To render the screen into a texture, I want a (non-power-of-two) texture in screen size. Looking trough OpenGL extensions, I found: GL_NV_texture_rectangle GL_ARB_texture_rectangle GL_ARB_texture_non_power_of_two What is the difference between those and which should I use (or should I use a compleletly different one?)? Thanks! Nathan

Share this post


Link to post
Share on other sites
Advertisement
Quote:
Original post by LonelyStar
Hi everybody,
To render the screen into a texture, I want a (non-power-of-two) texture in screen size.
Looking trough OpenGL extensions, I found:

GL_NV_texture_rectangle
GL_ARB_texture_rectangle
GL_ARB_texture_non_power_of_two

What is the difference between those and which should I use (or should I use a compleletly different one?)?
Thanks!
Nathan
The differences are described in great detail in the specs. Generally you want to use GL_ARB_texture_non_power_of_two if it's supported because it functions exactly the same as regular textures. If you want to use non-normalized texture coordinates use GL_ARB_texture_rectangle. GL_NV_texture_rectangle is identical to the ARB and EXT versions, if I'm remembering correctly.

Share this post


Link to post
Share on other sites
you can also
1 ) resize the image to be a power of two (pw2)

2) create a texture that is pw2 and use only a part of it (ie: 800x600 inside a 1024x1024)

Share this post


Link to post
Share on other sites
I could resize to a power of two texture but I think using only a part of it does not work.
I want to use the texture to be used as a frambuffer object and I can not find a way to use only part of a texture as a framebuffer object.
Is there a way?

Share this post


Link to post
Share on other sites
In my engine, I use SDL_Image for loading .png pictures and OpenGL for displaying them on screen. Since OGL requires power-of-two texture size, function which is responsible for loading and converting .pngs to texture, detects whether texture has required size or not.

If not, it creates texture with first good pw2 size, and copies original texture to this new, expanded one:



// ...

SDL_Surface * tmp = IMG_Load(filename.c_str());

if (tmp == 0) return false;

// first check whether it is needed to expand texture size to powers of 2
usint w = tmp->w;
usint h = tmp->h;

usint physicalW = tmp->w;
usint physicalH = tmp->h;

SDL_Surface * image = tmp; // create alias

bool IsWidth = IsPowerOfTwo(w);
bool IsHeight = IsPowerOfTwo(h);

// -------------------------------------------------

if ((!IsWidth) || (!IsHeight) || (tmp->format->BitsPerPixel != 32))
{

if (!IsWidth) w = PowerOfTwo(w);
if (!IsHeight) h = PowerOfTwo(h);

// -------------------------------------------------

Uint32 rmask, gmask, bmask, amask;

/* SDL interprets each pixel as a 32-bit number, so our masks must depend on the endianness (byte order) of the machine*/

#if SDL_BYTEORDER == SDL_BIG_ENDIAN
rmask = 0xff000000;
gmask = 0x00ff0000;
bmask = 0x0000ff00;
amask = 0x000000ff;
#else
rmask = 0x000000ff;
gmask = 0x0000ff00;
bmask = 0x00ff0000;
amask = 0xff000000;
#endif

// -------------------------------------------------

image = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, rmask, gmask, bmask, amask);

// now image is no longer alias to tmp, rather than new surface
if ( image == 0 )
{
logError2("TextureMgr", "Couldn't allocate memory for expanding texture to power of 2")
SDL_FreeSurface(tmp);
SC_ASSERT(!"Couldn't allocate memory for expanding texture to power of 2")
return false;
}

SDL_Rect area;
area.x = 0;
area.y = 0;
area.w = tmp->w;
area.h = tmp->h;

// it was fucking stupid bug with 32 bpp textures that needed to be resized
if ( tmp->format->BitsPerPixel == 32)
SDL_SetAlpha(tmp, 0, 0);

// copy the tmp into the new GL texture image
SDL_BlitSurface(tmp, &area, image, &area);
SDL_FreeSurface(tmp);
tmp = 0;
}

// -------------------------------------------------

TextureHandle textureHwnd;

glGenTextures(1, &textureHwnd.id);
glBindTexture(GL_TEXTURE_2D, textureHwnd.id);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);

textureHwnd.width = w;
textureHwnd.height = h;
textureHwnd.physicalWidth = physicalW;
textureHwnd.physicalHeight = physicalH;
textureHwnd.refCount = 1;

if (tmp) SDL_FreeSurface(tmp);
else SDL_FreeSurface(image);

// now add it to map
(_itor->second)->insert(TextureGroupPair(_textureName, textureHwnd));

return true;
}




And rendering texture on screen is performed by this function:



/*

_scrPnt is position of left down corner of texture on screen
_scrWidth and _scrHeight are width and height that blitted texture should occupy on screen

_texPnt is position of left down corner of place from where texture will be blitted
_texWidth and _texHeight are width and height of that blitted portion

All units are in pixels

*/


void SC :: Renderer :: RenderTexture(const TScrPoint & _scrPnt, usint _scrWidth, usint _scrHeight, ulint _depth,
const TScrPoint & _texPnt, ssint _texWidth, ssint _texHeight,
bool _flipH, bool _flipW)
{
if (_flipH) _texWidth = -_texWidth;
if (_flipW) _texHeight = -_texHeight;

float leftMargin = (float)_texPnt.x / (float)boundTexture.width;
float rightMargin = leftMargin + ((float)_texWidth / (float)boundTexture.width);

float downMargin = (float)_texPnt.y / (float)boundTexture.height;
float upMargin = downMargin + ((float)_texHeight / (float)boundTexture.height);

glPushMatrix();

glTranslatef(_scrPnt.x, _scrPnt.y, 0);

glBegin(GL_QUADS);

glTexCoord2f(leftMargin, downMargin);
glVertex3i(0, _scrHeight, _depth); // left down

glTexCoord2f(leftMargin, upMargin);
glVertex3i(0, 0, _depth); // left up

glTexCoord2f(rightMargin, upMargin);
glVertex3i(_scrWidth, 0, _depth); // right up

glTexCoord2f(rightMargin, downMargin);
glVertex3i( _scrWidth, _scrHeight, _depth); // right down

glEnd();

glPopMatrix();

}





Though you mentioned framebuffer objects, maybe those functions will help you somewhow. HTH :-)

Share this post


Link to post
Share on other sites
Quote:
Original post by LonelyStar
I could resize to a power of two texture but I think using only a part of it does not work.
I want to use the texture to be used as a frambuffer object and I can not find a way to use only part of a texture as a framebuffer object.
Is there a way?


You can use the part you want by setting properly the viewport.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!