0
votes

I'm creating a class to manage the images using OpenGL. To load the image i'm using SOIL to load PNG. Because i need to check collision i want to get the transparent pixel. So i'm trying to get the data using: glGetTexImage

The constructor loads the image:

Image::Image(string imagePath, unsigned int flags){
    this->imagePath=imagePath;
    this->pxData=NULL;
    texture=SOIL_load_OGL_texture
    (
     imagePath.c_str(),
     SOIL_LOAD_AUTO,
     SOIL_CREATE_NEW_ID,
     flags
    );

    //Use that to subdivide in sprites the texture
    glGetTexLevelParameteriv(GL_TEXTURE_2D, texture, GL_TEXTURE_WIDTH, &textureWidth);
    glGetTexLevelParameteriv(GL_TEXTURE_2D, texture, GL_TEXTURE_HEIGHT, &textureHeight);
    glBindTexture(GL_TEXTURE_2D, this->texture);
    //cout << "Real Dimensions - " << textureWidth << "-" << textureHeight;

    loadPixels(); //multiple instances of image generates error here
}

the LoadPixels load inside my structure the pixel data.

typedef struct PixelData{
    unsigned char r;
    unsigned char g;
    unsigned char b;
    unsigned char a;
} PixelData;
PixelData* pxData;

Then in the loadPixels i store that data:

void Image::loadPixels(){
    pxData = new PixelData[textureHeight*textureWidth];
    glGetTexImage(GL_TEXTURE_2D, 1, GL_RGBA, GL_UNSIGNED_BYTE , pxData);
}

The problem is, if i create an image:

Image img("/Developer/img.png", SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT);

It works fine.

If i create a lot of images:

    Image img("/Developer/img.png", SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT);
    Image img2("/Developer/img2.png", SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT);
    Image img3("/Developer/img3.png", SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT);
    Image img4("/Developer/img4.png", SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT);
    Image img5("/Developer/img5.png", SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT);
    Image img6("/Developer/img6.png", SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT);
    Image img7("/Developer/img7.png", SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT);
    Image img8("/Developer/img8.png", SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT);
    Image img9("/Developer/img9.png", SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT);
    Image img10("/Developer/img10.png", SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB | SOIL_FLAG_COMPRESS_TO_DXT);

Then my program crashes:

The error is:

OpenGL Game Engine(35463,0x7fff7b121310) malloc: *** error for object 0x104017808: incorrect checksum for freed object - object was probably modified after being freed.
*** set a breakpoint in malloc_error_break to debug

If i comment the glGetTexImage(GL_TEXTURE_2D, 1, GL_RGBA, GL_UNSIGNED_BYTE , pxData); it works fine, so i imagine the problem is not the allocation.

I just need to get the pixel data to store it, i want to create some data using those pixels so i need to get the pixel of my texture.

NOTE:

The program stops at imagePath.c_str() with sigabort if i uncomment the loadPixels, if i comment it it loads fine all the textures

Thanks to Audrey i got more information.

glGetTexLevelParameteriv(GL_TEXTURE_2D, this->texture, GL_TEXTURE_WIDTH, &textureWidth);
glGetTexLevelParameteriv(GL_TEXTURE_2D, this->texture, GL_TEXTURE_HEIGHT, &textureHeight);

Real Dimensions - 128-128
Real Dimensions - 64-64
Real Dimensions - 32-32
Real Dimensions - 16-16

It is the same image, but the sizes keep getting smaller.

I checked the id and it really creates a new id each time, so why the sizes are getting messed?

Is there another way to get that data, what am i missing here? Another question, this method gets the bind texture, is there a way to get the texture data using the texture id?

2
Are textureWidth and textureHeight returning what you think they are? - Andrey Mishchenko
They return the texture size, its ok,. The problem is when i want to get the data from the glGetTexImage, if i cal only once the data is returned perfectly but if i call a lot of time the program crashes - Lefsler
I am wondering if getGlTexImage is trying to write too many bytes to pxData. That's the first place I would check. You may not get an error when dealing with just one image, because you own some memory beyond the end of pxData, and it is being corrupted but you don't notice and the computer doesn't complain/segfault. - Andrey Mishchenko
@Audrey thanks, i checked and the size returned is getting smaller even if the image is the same, i don't know why this strange behaviour - Lefsler

2 Answers

1
votes
glGetTexLevelParameteriv(GL_TEXTURE_2D, texture, GL_TEXTURE_HEIGHT, &textureHeight);

The second parameter does not take the texture ID. It's a mipmap level. You need to bind the texture first, and then call this function with 0 where you've put texture.

Specifically, your texture ID's are almost certainly being instantiated as '0', '1', '2', etc... Each time you called glGetTexLevelParameteriv with a successive value you were asking for a smaller mipmap level on the currently bound texture. The fact that your first call didn't fail leads me to suspect that SOIL_load_OGL_texture actually doesn't unbind it before it returns.

Remember that almost no OpenGL function takes a texture, buffer or shader ID as a parameter, but rather acts on the currently bound object. The only functions that you typically use with the actual ID are the ones that create, destroy or bind the object, eg glGenTextures, glDeleteTextures and glBindTexture

2
votes

As per the discussion in the comments, it looks like getGlTexImage is overflowing the pxData buffer. If you post what the output of the functions giving you textureWidth and textureHeight are, we may be able to figure out what is wrong. (For example, are you sure of compatibility between the return type of the getter function and the variables textureWidth, etc?)

Edit: I would check your <Gl.h> to see the signature of the function glGetTexLevelParametersiv. I looked around online a bit and the Microsoft WINAPI version of this has a different signature than the one on OpenGL.org, and neither agrees with the signature you are using.

Try reordering and rewriting to this:

glBindTexture(GL_TEXTURE_2D, this->texture);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &textureWidth);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &textureHeight);